Compile fixes.
[SquirrelJME.git] / nanocoat / lib / base / stream.c
blobd4348b7481058d3afb3cc770b6f112184312e1a4
1 /* -*- Mode: C; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
3 // SquirrelJME
4 // Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
5 // ---------------------------------------------------------------------------
6 // SquirrelJME is under the Mozilla Public License Version 2.0.
7 // See license.mkd for licensing and copyright information.
8 // -------------------------------------------------------------------------*/
10 #include <string.h>
12 #include "sjme/stream.h"
13 #include "sjme/alloc.h"
14 #include "sjme/debug.h"
15 #include "sjme/util.h"
17 static sjme_errorCode sjme_stream_inputClose(
18 sjme_attrInNotNull sjme_closeable closeable)
20 sjme_errorCode error;
21 sjme_stream_input stream;
23 /* Recover stream. */
24 stream = (sjme_stream_input)closeable;
25 if (stream == NULL)
26 return SJME_ERROR_NULL_ARGUMENTS;
28 /* Function needs to exist. */
29 if (stream->functions == NULL || stream->functions->close == NULL)
30 return SJME_ERROR_ILLEGAL_STATE;
32 /* Close the stream. */
33 if (sjme_error_is(error = stream->functions->close(stream,
34 &stream->implState)))
35 return sjme_error_default(error);
37 /* Success! */
38 return SJME_ERROR_NONE;
41 sjme_errorCode sjme_stream_outputClose(
42 sjme_attrInNotNull sjme_closeable closeable)
44 sjme_errorCode error;
45 sjme_stream_output stream;
47 /* Recover stream. */
48 stream = (sjme_stream_output)closeable;
49 if (stream == NULL)
50 return SJME_ERROR_NULL_ARGUMENTS;
52 /* Function needs to exist. */
53 if (stream->functions == NULL || stream->functions->close == NULL)
54 return SJME_ERROR_ILLEGAL_STATE;
56 /* Close the stream. */
57 if (sjme_error_is(error = stream->functions->close(stream,
58 &stream->implState)))
59 return sjme_error_default(error);
61 /* Success! */
62 return SJME_ERROR_NONE;
65 sjme_errorCode sjme_stream_inputAvailable(
66 sjme_attrInNotNull sjme_stream_input stream,
67 sjme_attrOutNotNull sjme_attrOutNegativeOnePositive sjme_jint* outAvail)
69 sjme_jint result;
70 sjme_errorCode error;
72 if (stream == NULL || outAvail == NULL)
73 return SJME_ERROR_NULL_ARGUMENTS;
75 /* If this is not implemented, then we cannot do anything. */
76 if (stream->functions->available == NULL)
78 *outAvail = 0;
79 return SJME_ERROR_NONE;
82 /* Request the number of available bytes. */
83 result = -1;
84 if (sjme_error_is(error = stream->functions->available(stream,
85 &stream->implState, &result)) || result < 0)
86 return sjme_error_default(error);
88 /* Return result. */
89 *outAvail = result;
90 return SJME_ERROR_NONE;
93 sjme_errorCode sjme_stream_inputOpen(
94 sjme_attrInNotNull sjme_alloc_pool* inPool,
95 sjme_attrOutNotNull sjme_stream_input* outStream,
96 sjme_attrInNotNull const sjme_stream_inputFunctions* inFunctions,
97 sjme_attrInNullable sjme_pointer data,
98 sjme_attrInNullable const sjme_frontEnd* copyFrontEnd)
100 sjme_errorCode error;
101 sjme_stream_input result;
103 if (inPool == NULL || outStream == NULL || inFunctions == NULL)
104 return SJME_ERROR_NULL_ARGUMENTS;
106 /* These are required. */
107 if (inFunctions->read == NULL || inFunctions->init == NULL)
108 return SJME_ERROR_NOT_IMPLEMENTED;
110 /* Allocate result. */
111 result = NULL;
112 if (sjme_error_is(error = sjme_alloc_weakNew(inPool,
113 sizeof(*result), sjme_closeable_autoEnqueue, NULL,
114 (void**)&result, NULL)))
115 return sjme_error_default(error);
117 /* Setup details. */
118 result->implState.inPool = inPool;
119 result->functions = inFunctions;
120 result->closable.closeHandler = sjme_stream_inputClose;
122 /* Copy front end? */
123 if (copyFrontEnd != NULL)
124 memmove(&result->frontEnd, copyFrontEnd,
125 sizeof(*copyFrontEnd));
127 /* Call sub-init. */
128 if (sjme_error_is(error = result->functions->init(result,
129 &result->implState, data)))
131 /* Free before failure. */
132 sjme_alloc_free(result);
134 return sjme_error_default(error);
137 /* Success! */
138 *outStream = result;
139 return SJME_ERROR_NONE;
142 sjme_errorCode sjme_stream_inputRead(
143 sjme_attrInNotNull sjme_stream_input stream,
144 sjme_attrOutNotNull sjme_attrOutPositive sjme_jint* readCount,
145 sjme_attrOutNotNullBuf(length) sjme_pointer dest,
146 sjme_attrInPositive sjme_jint length)
148 /* This is just a simplified wrapper. */
149 return sjme_stream_inputReadIter(stream, readCount,
150 dest, 0, length);
153 sjme_errorCode sjme_stream_inputReadFully(
154 sjme_attrInNotNull sjme_stream_input stream,
155 sjme_attrOutNotNull sjme_attrOutNegativeOnePositive sjme_jint* readCount,
156 sjme_attrOutNotNullBuf(length) sjme_pointer dest,
157 sjme_attrInPositive sjme_jint length)
159 sjme_errorCode error;
160 sjme_intPointer rawDest;
161 sjme_jint at, left, subRead;
163 if (stream == NULL || readCount == NULL || dest == NULL)
164 return SJME_ERROR_NULL_ARGUMENTS;
166 rawDest = (uintptr_t)dest;
167 if (length < 0 || (rawDest + length) < rawDest)
168 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
170 /* Read until nothing is left. */
171 at = 0;
172 left = length;
173 while (left > 0)
175 /* Read as big as a chunk as possible. */
176 subRead = -2;
177 if (sjme_error_is(error = sjme_stream_inputRead(stream,
178 &subRead, SJME_POINTER_OFFSET(dest, at),
179 left)) || subRead < -1)
180 return sjme_error_default(error);
182 /* EOF, stop. */
183 if (subRead < 0)
185 /* Normal exit with the read count. */
186 if (at > 0)
187 break;
189 /* Otherwise indicate EOF. */
190 *readCount = -1;
191 return SJME_ERROR_NONE;
194 /* Move counters. */
195 at += subRead;
196 left -= subRead;
199 /* Success! */
200 *readCount = at;
201 return SJME_ERROR_NONE;
204 sjme_errorCode sjme_stream_inputReadIter(
205 sjme_attrInNotNull sjme_stream_input stream,
206 sjme_attrOutNotNull sjme_attrOutPositive sjme_jint* readCount,
207 sjme_attrOutNotNullBuf(length) sjme_pointer dest,
208 sjme_attrInPositive sjme_jint offset,
209 sjme_attrInPositive sjme_jint length)
211 sjme_intPointer rawDest;
212 sjme_jint count, newTotal, totalRead;
213 sjme_errorCode error;
214 sjme_pointer trueDest;
216 if (stream == NULL || readCount == NULL || dest == NULL)
217 return SJME_ERROR_NULL_ARGUMENTS;
219 rawDest = (uintptr_t)dest;
220 if (offset < 0 || length < 0 || (offset + length) < 0 ||
221 (rawDest + length) < rawDest)
222 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
224 /* Function needs to exist. */
225 if (stream->functions == NULL || stream->functions->read == NULL)
226 return SJME_ERROR_ILLEGAL_STATE;
228 /* Calculate the true target address. */
229 trueDest = (sjme_pointer)(rawDest + offset);
231 /* Overflowing write? */
232 totalRead = stream->totalRead;
233 if (totalRead < 0 || (totalRead + length) < 0)
234 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
236 /* Read in the data. */
237 count = -2;
238 if ((sjme_error_is(error = stream->functions->read(stream,
239 &stream->implState,
240 &count, trueDest, length))) || count < -1)
241 return sjme_error_default(error);
243 /* If not EOS, move counters up. */
244 if (count >= 0)
246 /* Never underflow, just keep it at max int. */
247 newTotal = stream->totalRead + count;
248 if (newTotal > stream->totalRead)
249 stream->totalRead = newTotal;
252 /* Return result. */
253 *readCount = count;
254 return SJME_ERROR_NONE;
257 sjme_errorCode sjme_stream_inputReadSingle(
258 sjme_attrInNotNull sjme_stream_input stream,
259 sjme_attrOutNotNull sjme_attrOutNegativeOnePositive sjme_jint* result)
261 sjme_jubyte single;
262 sjme_jint readCount;
263 sjme_errorCode error;
265 if (stream == NULL || result == NULL)
266 return SJME_ERROR_NULL_ARGUMENTS;
268 /* Constantly try to read a single byte. */
269 for (;;)
271 /* Attempt single byte read. */
272 single = 0xFE;
273 readCount = -2;
274 if (sjme_error_is(error = sjme_stream_inputReadIter(stream,
275 &readCount, &single, 0, 1)) || readCount < -1)
276 return sjme_error_default(error);
278 /* Did not read anything? */
279 if (readCount == 0)
280 continue;
282 /* EOF? */
283 if (readCount < 0)
285 *result = -1;
286 return SJME_ERROR_NONE;
289 /* Return resultant character. */
290 *result = (single & 0xFF);
291 return SJME_ERROR_NONE;
295 sjme_errorCode sjme_stream_inputReadValueJ(
296 sjme_attrInNotNull sjme_stream_input stream,
297 sjme_attrInRange(0, SJME_NUM_BASIC_TYPE_IDS)
298 sjme_basicTypeId typeId,
299 sjme_attrOutNotNull sjme_jvalue* outValue)
301 sjme_jint reqCount, readCount;
302 sjme_jvalue temp;
303 sjme_errorCode error;
305 if (stream == NULL || outValue == NULL)
306 return SJME_ERROR_NULL_ARGUMENTS;
308 if (typeId < 0 || typeId >= SJME_NUM_BASIC_TYPE_IDS ||
309 typeId == SJME_JAVA_TYPE_ID_BOOLEAN_OR_BYTE ||
310 typeId == SJME_JAVA_TYPE_ID_OBJECT)
311 return SJME_ERROR_INVALID_ARGUMENT;
313 /* How many bytes do we need to read? */
314 switch (typeId)
316 case SJME_BASIC_TYPE_ID_BOOLEAN:
317 case SJME_BASIC_TYPE_ID_BYTE:
318 reqCount = 1;
319 break;
321 case SJME_BASIC_TYPE_ID_SHORT:
322 case SJME_BASIC_TYPE_ID_CHARACTER:
323 reqCount = 2;
324 break;
326 case SJME_BASIC_TYPE_ID_INTEGER:
327 case SJME_BASIC_TYPE_ID_FLOAT:
328 reqCount = 4;
329 break;
331 case SJME_BASIC_TYPE_ID_LONG:
332 case SJME_BASIC_TYPE_ID_DOUBLE:
333 reqCount = 8;
334 break;
336 default:
337 return SJME_ERROR_INVALID_ARGUMENT;
340 /* Read into temporary, so we do not alter memory just yet. */
341 memset(&temp, 0, sizeof(temp));
342 readCount = -2;
343 if (sjme_error_is(error = sjme_stream_inputRead(stream,
344 &readCount, &temp, reqCount)) || readCount != reqCount)
345 return sjme_error_defaultOr(error,
346 SJME_ERROR_UNEXPECTED_EOF);
348 /* Normalize boolean? */
349 if (typeId == SJME_BASIC_TYPE_ID_BOOLEAN)
350 temp.z = (temp.b == 0 ? SJME_JNI_FALSE : SJME_JNI_TRUE);
352 #if defined(SJME_CONFIG_HAS_LITTLE_ENDIAN)
353 /* Perform byte swap on the data. */
354 if (reqCount > 1)
356 if (reqCount == 2)
357 temp.s = sjme_swap_short(temp.s);
358 else if (reqCount == 4)
359 temp.i = sjme_swap_int(temp.i);
360 else
361 temp.j = sjme_swap_long(temp.j);
363 #endif
365 /* Success! */
366 memmove(outValue, &temp, sizeof(temp));
367 return SJME_ERROR_NONE;
370 sjme_errorCode sjme_stream_inputReadValueJI(
371 sjme_attrInNotNull sjme_stream_input stream,
372 sjme_attrOutNotNull sjme_jint* outValue)
374 sjme_errorCode error;
375 sjme_jvalue value;
377 if (stream == NULL || outValue == NULL)
378 return SJME_ERROR_NULL_ARGUMENTS;
380 /* Read in value. */
381 memset(&value, 0, sizeof(value));
382 if (sjme_error_is(error = sjme_stream_inputReadValueJ(
383 stream, SJME_BASIC_TYPE_ID_INTEGER, &value)))
384 return sjme_error_default(error);
386 /* Give the value! */
387 *outValue = value.i;
388 return SJME_ERROR_NONE;
391 sjme_errorCode sjme_stream_inputReadValueJS(
392 sjme_attrInNotNull sjme_stream_input stream,
393 sjme_attrOutNotNull sjme_jshort* outValue)
395 sjme_errorCode error;
396 sjme_jvalue value;
398 if (stream == NULL || outValue == NULL)
399 return SJME_ERROR_NULL_ARGUMENTS;
401 /* Read in value. */
402 memset(&value, 0, sizeof(value));
403 if (sjme_error_is(error = sjme_stream_inputReadValueJ(
404 stream, SJME_BASIC_TYPE_ID_SHORT, &value)))
405 return sjme_error_default(error);
407 /* Give the value! */
408 *outValue = value.s;
409 return SJME_ERROR_NONE;
412 sjme_errorCode sjme_stream_outputOpen(
413 sjme_attrInNotNull sjme_alloc_pool* inPool,
414 sjme_attrOutNotNull sjme_stream_output* outStream,
415 sjme_attrInNotNull const sjme_stream_outputFunctions* inFunctions,
416 sjme_attrInNullable sjme_pointer data,
417 sjme_attrInNullable const sjme_frontEnd* copyFrontEnd)
419 sjme_errorCode error;
420 sjme_stream_output result;
422 if (inPool == NULL || outStream == NULL || inFunctions == NULL)
423 return SJME_ERROR_NULL_ARGUMENTS;
425 /* These are required. */
426 if (inFunctions->write == NULL || inFunctions->init == NULL)
427 return SJME_ERROR_NOT_IMPLEMENTED;
429 /* Allocate result. */
430 result = NULL;
431 if (sjme_error_is(error = sjme_alloc_weakNew(inPool,
432 sizeof(*result), sjme_closeable_autoEnqueue, NULL,
433 (void**)&result, NULL)))
434 return sjme_error_default(error);
436 /* Setup details. */
437 result->implState.inPool = inPool;
438 result->functions = inFunctions;
439 result->closable.closeHandler = sjme_stream_outputClose;
441 /* Copy front end? */
442 if (copyFrontEnd != NULL)
443 memmove(&result->frontEnd, copyFrontEnd,
444 sizeof(*copyFrontEnd));
446 /* Call sub-init. */
447 if (sjme_error_is(error = result->functions->init(result,
448 &result->implState, data)))
450 /* Free before failure. */
451 sjme_alloc_free(result);
453 return sjme_error_default(error);
456 /* Success! */
457 *outStream = result;
458 return SJME_ERROR_NONE;
461 sjme_errorCode sjme_stream_outputWrite(
462 sjme_attrInNotNull sjme_stream_output outStream,
463 sjme_attrOutNotNullBuf(length) sjme_pointer src,
464 sjme_attrInPositive sjme_jint length)
466 /* Forwards to iter variant. */
467 return sjme_stream_outputWriteIter(outStream, src,
468 0, length);
471 sjme_errorCode sjme_stream_outputWriteIter(
472 sjme_attrInNotNull sjme_stream_output stream,
473 sjme_attrOutNotNullBuf(length) sjme_pointer src,
474 sjme_attrInPositive sjme_jint offset,
475 sjme_attrInPositive sjme_jint length)
477 uintptr_t realSrc;
478 sjme_errorCode error;
479 sjme_jint written;
481 if (stream == NULL || src == NULL)
482 return SJME_ERROR_NULL_ARGUMENTS;
484 realSrc = (uintptr_t)src;
485 if (offset < 0 || length < 0 || (offset + length) < 0 ||
486 (realSrc + offset) < realSrc || (realSrc + length) < realSrc ||
487 (realSrc + offset + length) < realSrc)
488 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
490 /* Overflowing write? */
491 written = stream->totalWritten;
492 if (written < 0 || (written + length) < 0)
493 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
495 /* No write function exists? */
496 if (stream->functions->write == NULL)
497 return SJME_ERROR_ILLEGAL_STATE;
499 /* Forward call. */
500 if (sjme_error_is(error = stream->functions->write(stream,
501 &stream->implState,
502 (sjme_pointer)(realSrc + offset), length)))
503 return sjme_error_default(error);
505 /* Increase write count. */
506 stream->totalWritten += length;
508 /* Success! */
509 return SJME_ERROR_NONE;
512 sjme_errorCode sjme_stream_outputWriteSingle(
513 sjme_attrInNotNull sjme_stream_output outStream,
514 sjme_attrInRange(0, 256) sjme_jint value)
516 sjme_jubyte really;
518 /* Map down value. */
519 really = (sjme_jubyte)(value & 0xFF);
521 /* Forward call. */
522 return sjme_stream_outputWriteIter(outStream,
523 &really, 0, 1);
526 sjme_errorCode sjme_stream_outputWriteValueJP(
527 sjme_attrInNotNull sjme_stream_output outStream,
528 sjme_attrInRange(0, SJME_NUM_BASIC_TYPE_IDS) sjme_basicTypeId typeId,
529 sjme_attrInNotNull const sjme_jvalue* value)
531 sjme_jint reqCount;
532 union
534 sjme_jvalue value;
535 sjme_jubyte raw[8];
536 } temp;
538 if (outStream == NULL || value == NULL)
539 return SJME_ERROR_NULL_ARGUMENTS;
541 if (typeId < 0 || typeId >= SJME_NUM_BASIC_TYPE_IDS ||
542 typeId == SJME_JAVA_TYPE_ID_BOOLEAN_OR_BYTE ||
543 typeId == SJME_BASIC_TYPE_ID_OBJECT)
544 return SJME_ERROR_INVALID_ARGUMENT;
546 /* How many bytes do we need to write? */
547 switch (typeId)
549 case SJME_BASIC_TYPE_ID_BOOLEAN:
550 case SJME_BASIC_TYPE_ID_BYTE:
551 reqCount = 1;
552 break;
554 case SJME_BASIC_TYPE_ID_SHORT:
555 case SJME_BASIC_TYPE_ID_CHARACTER:
556 reqCount = 2;
557 break;
559 case SJME_BASIC_TYPE_ID_INTEGER:
560 case SJME_BASIC_TYPE_ID_FLOAT:
561 reqCount = 4;
562 break;
564 case SJME_BASIC_TYPE_ID_LONG:
565 case SJME_BASIC_TYPE_ID_DOUBLE:
566 reqCount = 8;
567 break;
569 default:
570 return SJME_ERROR_INVALID_ARGUMENT;
573 /* Copy value directly. */
574 memmove(&temp, value, sizeof(*value));
576 #if defined(SJME_CONFIG_HAS_LITTLE_ENDIAN)
577 /* Perform byte swap on the data. */
578 if (reqCount > 1)
580 if (reqCount == 2)
581 temp.value.s = sjme_swap_short(temp.value.s);
582 else if (reqCount == 4)
583 temp.value.i = sjme_swap_int(temp.value.i);
584 else
585 temp.value.j = sjme_swap_long(temp.value.j);
587 #endif
589 /* Forward write. */
590 return sjme_stream_outputWriteIter(outStream,
591 &temp, 0, reqCount);
594 sjme_errorCode sjme_stream_outputWriteValueJ(
595 sjme_attrInNotNull sjme_stream_output outStream,
596 sjme_attrInRange(0, SJME_NUM_BASIC_TYPE_IDS) sjme_basicTypeId typeId,
597 ...)
599 va_list va;
600 sjme_jvalue value;
602 if (typeId < 0 || typeId >= SJME_NUM_BASIC_TYPE_IDS ||
603 typeId == SJME_JAVA_TYPE_ID_BOOLEAN_OR_BYTE ||
604 typeId == SJME_BASIC_TYPE_ID_OBJECT)
605 return SJME_ERROR_INVALID_ARGUMENT;
607 /* Clear before reading in. */
608 memset(&value, 0, sizeof(value));
610 /* Read in the argument accordingly. */
611 va_start(va, typeId);
612 switch (typeId)
614 case SJME_BASIC_TYPE_ID_BOOLEAN:
615 value.z = va_arg(va, sjme_jboolean) != SJME_JNI_FALSE;
616 break;
618 case SJME_BASIC_TYPE_ID_BYTE:
619 value.b = va_arg(va, sjme_jbyte_promoted);
620 break;
622 case SJME_BASIC_TYPE_ID_SHORT:
623 value.s = va_arg(va, sjme_jshort_promoted);
624 break;
626 case SJME_BASIC_TYPE_ID_CHARACTER:
627 value.c = va_arg(va, sjme_jchar_promoted);
628 break;
630 case SJME_BASIC_TYPE_ID_INTEGER:
631 value.i = va_arg(va, sjme_jint);
632 break;
634 case SJME_BASIC_TYPE_ID_LONG:
635 value.j = va_arg(va, sjme_jlong);
636 break;
638 case SJME_BASIC_TYPE_ID_FLOAT:
639 value.f = va_arg(va, sjme_jfloat);
640 break;
642 case SJME_BASIC_TYPE_ID_DOUBLE:
643 value.d = va_arg(va, sjme_jdouble);
644 break;
646 default:
647 return SJME_ERROR_INVALID_ARGUMENT;
650 /* Stop. */
651 va_end(va);
653 /* Forward call. */
654 return sjme_stream_outputWriteValueJP(outStream, typeId,
655 &value);