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/nvm/rom.h"
13 #include "sjme/alloc.h"
14 #include "sjme/debug.h"
15 #include "sjme/nvm/payload.h"
16 #include "sjme/nvm/romInternal.h"
17 #include "sjme/util.h"
19 #include "sjme/cleanup.h"
21 static sjme_errorCode
sjme_rom_libraryClose(
22 sjme_attrInNotNull sjme_closeable closeable
)
25 sjme_rom_library inLibrary
;
27 if (closeable
== NULL
)
28 return SJME_ERROR_NULL_ARGUMENTS
;
30 /* Recover library. */
31 inLibrary
= (sjme_rom_library
)closeable
;
33 /* Delete the prefix if there is one. */
34 if (inLibrary
->prefix
!= NULL
)
37 if (sjme_error_is(error
= sjme_alloc_free(
38 (sjme_pointer
)inLibrary
->prefix
)))
39 return sjme_error_default(error
);
42 inLibrary
->prefix
= NULL
;
45 /* Delete name if there is one. */
46 if (inLibrary
->name
!= NULL
)
49 if (sjme_error_is(error
= sjme_alloc_free(
50 (sjme_pointer
)inLibrary
->name
)))
51 return sjme_error_default(error
);
54 inLibrary
->name
= NULL
;
57 /* Forward close handler. */
58 if (inLibrary
->functions
->close
!= NULL
)
59 return inLibrary
->functions
->close(inLibrary
);
62 return SJME_ERROR_NONE
;
65 sjme_errorCode
sjme_rom_libraryHash(
66 sjme_attrInNotNull sjme_rom_library library
,
67 sjme_attrOutNotNull sjme_jint
* outHash
)
69 if (library
== NULL
|| outHash
== NULL
)
70 return SJME_ERROR_NULL_ARGUMENTS
;
72 /* Does it need to be calculated? */
73 if (library
->nameHash
== 0)
75 /* This should always be set. */
76 if (library
->name
== NULL
)
77 return SJME_ERROR_ILLEGAL_STATE
;
79 /* Calculate the hash. */
80 library
->nameHash
= sjme_string_hash(library
->name
);
84 *outHash
= library
->nameHash
;
85 return SJME_ERROR_NONE
;
88 sjme_errorCode
sjme_rom_libraryNew(
89 sjme_attrInNotNull sjme_alloc_pool
* pool
,
90 sjme_attrOutNotNull sjme_rom_library
* outLibrary
,
91 sjme_attrInNotNull sjme_lpcstr libName
,
92 sjme_attrInNullable sjme_pointer data
,
93 sjme_attrInNotNull
const sjme_rom_libraryFunctions
* inFunctions
,
94 sjme_attrInNullable
const sjme_frontEnd
* copyFrontEnd
)
97 sjme_rom_library result
;
99 if (pool
== NULL
|| outLibrary
== NULL
|| inFunctions
== NULL
||
101 return SJME_ERROR_NULL_ARGUMENTS
;
104 if (inFunctions
->init
== NULL
||
105 inFunctions
->close
== NULL
)
106 return SJME_ERROR_NOT_IMPLEMENTED
;
108 /* Allocate result. */
110 if (sjme_error_is(error
= sjme_alloc_weakNew(pool
,
111 sizeof(*result
), sjme_nvm_enqueueHandler
, NULL
,
112 (void**)&result
, NULL
)) || result
== NULL
)
116 result
->common
.closeable
.closeHandler
= sjme_rom_libraryClose
;
117 result
->common
.type
= SJME_NVM_STRUCTTYPE_ROM_LIBRARY
;
118 result
->cache
.common
.allocPool
= pool
;
119 result
->functions
= inFunctions
;
121 /* Copy front end? */
122 if (copyFrontEnd
!= NULL
)
123 memmove(&result
->common
.frontEnd
, copyFrontEnd
,
124 sizeof(*copyFrontEnd
));
126 /* Call initializer. */
127 if (sjme_error_is(error
= inFunctions
->init(result
, data
)))
130 /* Set library name. */
132 if (sjme_error_is(error
= sjme_alloc_strdup(pool
,
133 (sjme_lpstr
*)&result
->name
, libName
)))
137 *outLibrary
= result
;
138 return SJME_ERROR_NONE
;
145 sjme_alloc_free(result
);
147 return sjme_error_default(error
);
150 sjme_errorCode
sjme_rom_libraryRawRead(
151 sjme_attrInNotNull sjme_rom_library library
,
152 sjme_attrOutNotNullBuf(length
) sjme_pointer destPtr
,
153 sjme_attrInPositive sjme_jint srcPos
,
154 sjme_attrInPositive sjme_jint length
)
156 /* This is just an alias for the other. */
157 return sjme_rom_libraryRawReadIter(
158 library
, destPtr
, 0, srcPos
, 0, length
);
161 sjme_errorCode
sjme_rom_libraryRawReadIter(
162 sjme_attrInNotNull sjme_rom_library library
,
163 sjme_attrOutNotNullBuf(length
) sjme_pointer destPtr
,
164 sjme_attrInPositive sjme_jint destOffset
,
165 sjme_attrInPositive sjme_jint srcPos
,
166 sjme_attrInPositive sjme_jint srcOffset
,
167 sjme_attrInPositive sjme_jint length
)
169 uintptr_t rawDestPtr
;
170 sjme_errorCode error
;
173 if (library
== NULL
|| destPtr
== NULL
)
174 return SJME_ERROR_NULL_ARGUMENTS
;
176 /* Do we already know this will not work? */
177 if (library
->cache
.checkedRawAccess
&&
178 !library
->cache
.validRawAccess
)
179 return SJME_ERROR_UNSUPPORTED_OPERATION
;
181 /* Check all the bounds variants possible, for overflow as well. */
182 rawDestPtr
= (uintptr_t)destPtr
;
183 if (destOffset
< 0 || srcPos
< 0 || srcOffset
< 0 || length
< 0 ||
184 (destOffset
+ length
) < 0 || (srcPos
+ length
) < 0 ||
185 (srcOffset
+ length
) < 0 || (srcPos
+ srcOffset
+ length
) < 0 ||
186 (rawDestPtr
+ destOffset
) < rawDestPtr
||
187 (rawDestPtr
+ length
) < rawDestPtr
||
188 (rawDestPtr
+ destOffset
+ length
) < rawDestPtr
)
189 return SJME_ERROR_INDEX_OUT_OF_BOUNDS
;
191 /* Get the raw size of the target library. */
193 if (sjme_error_is(error
= sjme_rom_libraryRawSize(library
,
194 &libSize
)) || libSize
< 0)
197 return sjme_error_defaultOr(error
,
198 SJME_ERROR_UNSUPPORTED_OPERATION
);
199 return sjme_error_default(error
);
202 /* Check bounds of the size to ensure it is correct. */
203 if (length
> libSize
|| (srcPos
+ length
) > libSize
||
204 (srcPos
+ srcOffset
) > libSize
||
205 (srcPos
+ srcOffset
+ length
) > libSize
)
206 return SJME_ERROR_INDEX_OUT_OF_BOUNDS
;
208 /* Check native library handler. */
209 if (library
->functions
->rawData
== NULL
)
210 return SJME_ERROR_UNSUPPORTED_OPERATION
;
212 /* Call native library handler, which takes simpler arguments. */
213 return library
->functions
->rawData(library
,
214 (sjme_pointer
)(((uintptr_t)destPtr
) + destOffset
),
215 srcPos
+ srcOffset
, length
);
218 sjme_errorCode
sjme_rom_libraryRawSize(
219 sjme_attrInNotNull sjme_rom_library library
,
220 sjme_attrOutNotNull sjme_jint
* outSize
)
223 sjme_errorCode error
;
225 if (library
== NULL
|| outSize
== NULL
)
226 return SJME_ERROR_NULL_ARGUMENTS
;
228 /* Do we already know this will not work? */
229 if (library
->cache
.checkedRawAccess
&&
230 !library
->cache
.validRawAccess
)
231 return SJME_ERROR_UNSUPPORTED_OPERATION
;
233 /* Size was already determined? */
234 if (library
->cache
.size
> 0)
235 return library
->cache
.size
;
237 /* Native handler must be valid! */
238 if (library
->functions
->rawSize
== NULL
)
239 goto fail_unsupported
;
241 /* Call native handler. */
243 if (sjme_error_is(error
= library
->functions
->rawSize(
244 library
, &result
)) || result
< 0)
247 goto fail_unsupported
;
248 return sjme_error_default(error
);
253 return SJME_ERROR_NONE
;
256 /* Cache whether this is supported, so we need not bother? */
257 if (!library
->cache
.checkedRawAccess
)
259 library
->cache
.checkedRawAccess
= SJME_JNI_TRUE
;
260 library
->cache
.validRawAccess
= SJME_JNI_FALSE
;
264 return SJME_ERROR_UNSUPPORTED_OPERATION
;
267 sjme_errorCode
sjme_rom_libraryResourceAsStream(
268 sjme_attrInNotNull sjme_rom_library library
,
269 sjme_attrOutNotNull sjme_stream_input
* outStream
,
270 sjme_attrInNotNull sjme_lpcstr rcName
)
272 sjme_rom_libraryResourceStreamFunc resourceFunc
;
273 sjme_stream_input result
;
274 sjme_errorCode error
;
276 if (library
== NULL
|| outStream
== NULL
|| rcName
== NULL
)
277 return SJME_ERROR_NULL_ARGUMENTS
;
279 /* These must be set. */
280 if (library
->functions
== NULL
||
281 library
->functions
->resourceStream
== NULL
)
282 return SJME_ERROR_NOT_IMPLEMENTED
;
285 if (sjme_error_is(error
= sjme_thread_spinLockGrab(
286 &library
->common
.lock
)))
287 return sjme_error_default(error
);
289 /* Get the resource function. */
290 resourceFunc
= library
->functions
->resourceStream
;
292 /* Ask for the resource. */
293 /* Remember to remove any starting slash, because internally everything */
294 /* is treated as absolute. */
296 if (sjme_error_is(error
= resourceFunc(library
,
298 (rcName
[0] == '/' ? rcName
+ 1 : rcName
))) ||
300 goto fail_locateResource
;
302 /* Unlock library. */
303 if (sjme_error_is(error
= sjme_thread_spinLockRelease(
304 &library
->common
.lock
, NULL
)))
305 return sjme_error_default(error
);
309 return SJME_ERROR_NONE
;
311 /* Unlock library. */
313 sjme_thread_spinLockRelease(&library
->common
.lock
, NULL
);
315 return sjme_error_default(error
);