1 /* -*- Mode: C; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
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 // -------------------------------------------------------------------------*/
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
)
21 sjme_stream_input stream
;
24 stream
= (sjme_stream_input
)closeable
;
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
,
35 return sjme_error_default(error
);
38 return SJME_ERROR_NONE
;
41 sjme_errorCode
sjme_stream_outputClose(
42 sjme_attrInNotNull sjme_closeable closeable
)
45 sjme_stream_output stream
;
48 stream
= (sjme_stream_output
)closeable
;
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
,
59 return sjme_error_default(error
);
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
)
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
)
79 return SJME_ERROR_NONE
;
82 /* Request the number of available bytes. */
84 if (sjme_error_is(error
= stream
->functions
->available(stream
,
85 &stream
->implState
, &result
)) || result
< 0)
86 return sjme_error_default(error
);
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. */
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
);
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
));
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
);
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
,
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. */
175 /* Read as big as a chunk as possible. */
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
);
185 /* Normal exit with the read count. */
189 /* Otherwise indicate EOF. */
191 return SJME_ERROR_NONE
;
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. */
238 if ((sjme_error_is(error
= stream
->functions
->read(stream
,
240 &count
, trueDest
, length
))) || count
< -1)
241 return sjme_error_default(error
);
243 /* If not EOS, move counters up. */
246 /* Never underflow, just keep it at max int. */
247 newTotal
= stream
->totalRead
+ count
;
248 if (newTotal
> stream
->totalRead
)
249 stream
->totalRead
= newTotal
;
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
)
263 sjme_errorCode error
;
265 if (stream
== NULL
|| result
== NULL
)
266 return SJME_ERROR_NULL_ARGUMENTS
;
268 /* Constantly try to read a single byte. */
271 /* Attempt single byte read. */
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? */
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
;
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? */
316 case SJME_BASIC_TYPE_ID_BOOLEAN
:
317 case SJME_BASIC_TYPE_ID_BYTE
:
321 case SJME_BASIC_TYPE_ID_SHORT
:
322 case SJME_BASIC_TYPE_ID_CHARACTER
:
326 case SJME_BASIC_TYPE_ID_INTEGER
:
327 case SJME_BASIC_TYPE_ID_FLOAT
:
331 case SJME_BASIC_TYPE_ID_LONG
:
332 case SJME_BASIC_TYPE_ID_DOUBLE
:
337 return SJME_ERROR_INVALID_ARGUMENT
;
340 /* Read into temporary, so we do not alter memory just yet. */
341 memset(&temp
, 0, sizeof(temp
));
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. */
357 temp
.s
= sjme_swap_short(temp
.s
);
358 else if (reqCount
== 4)
359 temp
.i
= sjme_swap_int(temp
.i
);
361 temp
.j
= sjme_swap_long(temp
.j
);
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
;
377 if (stream
== NULL
|| outValue
== NULL
)
378 return SJME_ERROR_NULL_ARGUMENTS
;
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! */
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
;
398 if (stream
== NULL
|| outValue
== NULL
)
399 return SJME_ERROR_NULL_ARGUMENTS
;
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! */
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. */
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
);
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
));
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
);
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
,
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
)
478 sjme_errorCode error
;
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
;
500 if (sjme_error_is(error
= stream
->functions
->write(stream
,
502 (sjme_pointer
)(realSrc
+ offset
), length
)))
503 return sjme_error_default(error
);
505 /* Increase write count. */
506 stream
->totalWritten
+= length
;
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
)
518 /* Map down value. */
519 really
= (sjme_jubyte
)(value
& 0xFF);
522 return sjme_stream_outputWriteIter(outStream
,
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
)
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? */
549 case SJME_BASIC_TYPE_ID_BOOLEAN
:
550 case SJME_BASIC_TYPE_ID_BYTE
:
554 case SJME_BASIC_TYPE_ID_SHORT
:
555 case SJME_BASIC_TYPE_ID_CHARACTER
:
559 case SJME_BASIC_TYPE_ID_INTEGER
:
560 case SJME_BASIC_TYPE_ID_FLOAT
:
564 case SJME_BASIC_TYPE_ID_LONG
:
565 case SJME_BASIC_TYPE_ID_DOUBLE
:
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. */
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
);
585 temp
.value
.j
= sjme_swap_long(temp
.value
.j
);
590 return sjme_stream_outputWriteIter(outStream
,
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
,
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
);
614 case SJME_BASIC_TYPE_ID_BOOLEAN
:
615 value
.z
= va_arg(va
, sjme_jboolean
) != SJME_JNI_FALSE
;
618 case SJME_BASIC_TYPE_ID_BYTE
:
619 value
.b
= va_arg(va
, sjme_jbyte_promoted
);
622 case SJME_BASIC_TYPE_ID_SHORT
:
623 value
.s
= va_arg(va
, sjme_jshort_promoted
);
626 case SJME_BASIC_TYPE_ID_CHARACTER
:
627 value
.c
= va_arg(va
, sjme_jchar_promoted
);
630 case SJME_BASIC_TYPE_ID_INTEGER
:
631 value
.i
= va_arg(va
, sjme_jint
);
634 case SJME_BASIC_TYPE_ID_LONG
:
635 value
.j
= va_arg(va
, sjme_jlong
);
638 case SJME_BASIC_TYPE_ID_FLOAT
:
639 value
.f
= va_arg(va
, sjme_jfloat
);
642 case SJME_BASIC_TYPE_ID_DOUBLE
:
643 value
.d
= va_arg(va
, sjme_jdouble
);
647 return SJME_ERROR_INVALID_ARGUMENT
;
654 return sjme_stream_outputWriteValueJP(outStream
, typeId
,