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 typedef struct sjme_stream_inputSeekableInitData
19 /** The seekable to access. */
20 sjme_seekable seekable
;
22 /** The base offset. */
25 /** The length of the chunk. */
29 sjme_jboolean forwardClose
;
30 } sjme_stream_inputSeekableInitData
;
32 static sjme_errorCode
sjme_stream_inputSeekableAvailable(
33 sjme_attrInNotNull sjme_stream_input stream
,
34 sjme_attrInNotNull sjme_stream_implState
* inImplState
,
35 sjme_attrOutNotNull sjme_attrOutNegativeOnePositive sjme_jint
* outAvail
)
38 return sjme_error_notImplemented(0);
41 static sjme_errorCode
sjme_stream_inputSeekableClose(
42 sjme_attrInNotNull sjme_stream_input stream
,
43 sjme_attrInNotNull sjme_stream_implState
* inImplState
)
47 if (stream
== NULL
|| inImplState
== NULL
)
48 return SJME_ERROR_NONE
;
50 /* Only forward close if it was requested. */
51 if (inImplState
->forwardClose
)
52 if (sjme_error_is(error
= sjme_closeable_close(
53 SJME_AS_CLOSEABLE(inImplState
->handle
))))
54 return sjme_error_default(error
);
57 return SJME_ERROR_NONE
;
60 static sjme_errorCode
sjme_stream_inputSeekableInit(
61 sjme_attrInNotNull sjme_stream_input stream
,
62 sjme_attrInNotNull sjme_stream_implState
* inImplState
,
63 sjme_attrInNullable sjme_pointer data
)
65 sjme_stream_inputSeekableInitData
* init
;
68 if (stream
== NULL
|| inImplState
== NULL
|| data
== NULL
)
69 return SJME_ERROR_NULL_ARGUMENTS
;
72 inImplState
->handle
= init
->seekable
;
73 inImplState
->offset
= init
->base
;
74 inImplState
->index
= 0;
75 inImplState
->length
= init
->length
;
76 inImplState
->forwardClose
= init
->forwardClose
;
79 return SJME_ERROR_NONE
;
82 static sjme_errorCode
sjme_stream_inputSeekableRead(
83 sjme_attrInNotNull sjme_stream_input stream
,
84 sjme_attrInNotNull sjme_stream_implState
* inImplState
,
85 sjme_attrOutNotNull sjme_attrOutNegativeOnePositive sjme_jint
* readCount
,
86 sjme_attrOutNotNullBuf(length
) sjme_pointer dest
,
87 sjme_attrInPositive sjme_jint length
)
89 sjme_seekable seekable
;
91 sjme_jint size
, limit
, left
, readAt
;
93 if (stream
== NULL
|| inImplState
== NULL
|| readCount
== NULL
||
95 return SJME_ERROR_NULL_ARGUMENTS
;
98 return SJME_ERROR_INDEX_OUT_OF_BOUNDS
;
100 /* Recover seekable. */
101 seekable
= inImplState
->handle
;
102 if (seekable
== NULL
)
103 return SJME_ERROR_ILLEGAL_STATE
;
105 /* How much length is left? */
106 size
= inImplState
->length
;
107 readAt
= inImplState
->index
;
108 left
= size
- readAt
;
110 /* Can we quickly determine EOF? */
114 return SJME_ERROR_NONE
;
117 /* We cannot read more than what is left. */
118 limit
= (length
< left
? length
: left
);
121 if (sjme_error_is(error
= sjme_seekable_read(seekable
,
122 dest
, inImplState
->offset
+ readAt
, limit
)))
123 return sjme_error_default(error
);
125 /* We read exactly that. */
126 inImplState
->index
= readAt
+ limit
;
130 return SJME_ERROR_NONE
;
133 static const sjme_stream_inputFunctions sjme_stream_inputSeekableFunctions
=
135 .available
= sjme_stream_inputSeekableAvailable
,
136 .init
= sjme_stream_inputSeekableInit
,
137 .close
= sjme_stream_inputSeekableClose
,
138 .read
= sjme_stream_inputSeekableRead
,
141 sjme_errorCode
sjme_stream_inputOpenSeekable(
142 sjme_attrInNotNull sjme_seekable seekable
,
143 sjme_attrOutNotNull sjme_stream_input
* outStream
,
144 sjme_attrInPositive sjme_jint base
,
145 sjme_attrInPositive sjme_jint length
,
146 sjme_attrInValue sjme_jboolean forwardClose
)
148 sjme_errorCode error
;
149 sjme_stream_inputSeekableInitData init
;
151 if (seekable
== NULL
|| outStream
== NULL
)
152 return SJME_ERROR_NULL_ARGUMENTS
;
154 if (base
< 0 || length
< 0 || (base
+ length
) < 0)
155 return SJME_ERROR_INDEX_OUT_OF_BOUNDS
;
157 /* Setup initialize. */
158 memset(&init
, 0, sizeof(init
));
159 init
.seekable
= seekable
;
161 init
.length
= length
;
162 init
.forwardClose
= forwardClose
;
164 /* Open base stream. */
165 return sjme_stream_inputOpen(seekable
->inPool
,
166 outStream
, &sjme_stream_inputSeekableFunctions
,