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 sjme_errorCode
sjme_rom_libraryHash(
22 sjme_attrInNotNull sjme_rom_library library
,
23 sjme_attrOutNotNull sjme_jint
* outHash
)
25 if (library
== NULL
|| outHash
== NULL
)
26 return SJME_ERROR_NULL_ARGUMENTS
;
28 /* Does it need to be calculated? */
29 if (library
->nameHash
== 0)
31 /* This should always be set. */
32 if (library
->name
== NULL
)
33 return SJME_ERROR_ILLEGAL_STATE
;
35 /* Calculate the hash. */
36 library
->nameHash
= sjme_string_hash(library
->name
);
40 *outHash
= library
->nameHash
;
41 return SJME_ERROR_NONE
;
44 sjme_errorCode
sjme_rom_libraryNew(
45 sjme_attrInNotNull sjme_alloc_pool
* pool
,
46 sjme_attrOutNotNull sjme_rom_library
* outLibrary
,
47 sjme_attrInNotNull sjme_lpcstr libName
,
48 sjme_attrInNullable sjme_pointer data
,
49 sjme_attrInNotNull
const sjme_rom_libraryFunctions
* inFunctions
,
50 sjme_attrInNullable
const sjme_frontEnd
* copyFrontEnd
)
53 sjme_rom_library result
;
55 if (pool
== NULL
|| outLibrary
== NULL
|| inFunctions
== NULL
||
57 return SJME_ERROR_NULL_ARGUMENTS
;
60 if (inFunctions
->init
== NULL
||
61 inFunctions
->close
== NULL
)
62 return SJME_ERROR_NOT_IMPLEMENTED
;
64 /* Allocate result. */
66 if (sjme_error_is(error
= sjme_nvm_alloc(pool
,
67 sizeof(*result
), SJME_NVM_STRUCT_ROM_LIBRARY
,
68 SJME_AS_NVM_COMMONP(&result
))) || result
== NULL
)
72 result
->cache
.common
.allocPool
= pool
;
73 result
->functions
= inFunctions
;
76 if (copyFrontEnd
!= NULL
)
77 memmove(&result
->common
.frontEnd
, copyFrontEnd
,
78 sizeof(*copyFrontEnd
));
80 /* Call initializer. */
81 if (sjme_error_is(error
= inFunctions
->init(result
, data
)))
84 /* Set library name. */
86 if (sjme_error_is(error
= sjme_alloc_strdup(pool
,
87 (sjme_lpstr
*)&result
->name
, libName
)))
92 return SJME_ERROR_NONE
;
100 sjme_closeable_close(SJME_AS_CLOSEABLE(result
));
102 return sjme_error_default(error
);
105 sjme_errorCode
sjme_rom_libraryRawRead(
106 sjme_attrInNotNull sjme_rom_library library
,
107 sjme_attrOutNotNullBuf(length
) sjme_pointer destPtr
,
108 sjme_attrInPositive sjme_jint srcPos
,
109 sjme_attrInPositive sjme_jint length
)
111 /* This is just an alias for the other. */
112 return sjme_rom_libraryRawReadIter(
113 library
, destPtr
, 0, srcPos
, 0, length
);
116 sjme_errorCode
sjme_rom_libraryRawReadIter(
117 sjme_attrInNotNull sjme_rom_library library
,
118 sjme_attrOutNotNullBuf(length
) sjme_pointer destPtr
,
119 sjme_attrInPositive sjme_jint destOffset
,
120 sjme_attrInPositive sjme_jint srcPos
,
121 sjme_attrInPositive sjme_jint srcOffset
,
122 sjme_attrInPositive sjme_jint length
)
124 uintptr_t rawDestPtr
;
125 sjme_errorCode error
;
128 if (library
== NULL
|| destPtr
== NULL
)
129 return SJME_ERROR_NULL_ARGUMENTS
;
131 /* Do we already know this will not work? */
132 if (library
->cache
.checkedRawAccess
&&
133 !library
->cache
.validRawAccess
)
134 return SJME_ERROR_UNSUPPORTED_OPERATION
;
136 /* Check all the bounds variants possible, for overflow as well. */
137 rawDestPtr
= (uintptr_t)destPtr
;
138 if (destOffset
< 0 || srcPos
< 0 || srcOffset
< 0 || length
< 0 ||
139 (destOffset
+ length
) < 0 || (srcPos
+ length
) < 0 ||
140 (srcOffset
+ length
) < 0 || (srcPos
+ srcOffset
+ length
) < 0 ||
141 (rawDestPtr
+ destOffset
) < rawDestPtr
||
142 (rawDestPtr
+ length
) < rawDestPtr
||
143 (rawDestPtr
+ destOffset
+ length
) < rawDestPtr
)
144 return SJME_ERROR_INDEX_OUT_OF_BOUNDS
;
146 /* Get the raw size of the target library. */
148 if (sjme_error_is(error
= sjme_rom_libraryRawSize(library
,
149 &libSize
)) || libSize
< 0)
152 return sjme_error_defaultOr(error
,
153 SJME_ERROR_UNSUPPORTED_OPERATION
);
154 return sjme_error_default(error
);
157 /* Check bounds of the size to ensure it is correct. */
158 if (length
> libSize
|| (srcPos
+ length
) > libSize
||
159 (srcPos
+ srcOffset
) > libSize
||
160 (srcPos
+ srcOffset
+ length
) > libSize
)
161 return SJME_ERROR_INDEX_OUT_OF_BOUNDS
;
163 /* Check native library handler. */
164 if (library
->functions
->rawData
== NULL
)
165 return SJME_ERROR_UNSUPPORTED_OPERATION
;
167 /* Call native library handler, which takes simpler arguments. */
168 return library
->functions
->rawData(library
,
169 (sjme_pointer
)(((uintptr_t)destPtr
) + destOffset
),
170 srcPos
+ srcOffset
, length
);
173 sjme_errorCode
sjme_rom_libraryRawSize(
174 sjme_attrInNotNull sjme_rom_library library
,
175 sjme_attrOutNotNull sjme_jint
* outSize
)
178 sjme_errorCode error
;
180 if (library
== NULL
|| outSize
== NULL
)
181 return SJME_ERROR_NULL_ARGUMENTS
;
183 /* Do we already know this will not work? */
184 if (library
->cache
.checkedRawAccess
&&
185 !library
->cache
.validRawAccess
)
186 return SJME_ERROR_UNSUPPORTED_OPERATION
;
188 /* Size was already determined? */
189 if (library
->cache
.size
> 0)
190 return library
->cache
.size
;
192 /* Native handler must be valid! */
193 if (library
->functions
->rawSize
== NULL
)
194 goto fail_unsupported
;
196 /* Call native handler. */
198 if (sjme_error_is(error
= library
->functions
->rawSize(
199 library
, &result
)) || result
< 0)
202 goto fail_unsupported
;
203 return sjme_error_default(error
);
208 return SJME_ERROR_NONE
;
211 /* Cache whether this is supported, so we need not bother? */
212 if (!library
->cache
.checkedRawAccess
)
214 library
->cache
.checkedRawAccess
= SJME_JNI_TRUE
;
215 library
->cache
.validRawAccess
= SJME_JNI_FALSE
;
219 return SJME_ERROR_UNSUPPORTED_OPERATION
;
222 sjme_errorCode
sjme_rom_libraryResourceAsStream(
223 sjme_attrInNotNull sjme_rom_library library
,
224 sjme_attrOutNotNull sjme_stream_input
* outStream
,
225 sjme_attrInNotNull sjme_lpcstr rcName
)
227 sjme_rom_libraryResourceStreamFunc resourceFunc
;
228 sjme_stream_input result
;
229 sjme_errorCode error
;
231 if (library
== NULL
|| outStream
== NULL
|| rcName
== NULL
)
232 return SJME_ERROR_NULL_ARGUMENTS
;
234 /* These must be set. */
235 if (library
->functions
== NULL
||
236 library
->functions
->resourceStream
== NULL
)
237 return SJME_ERROR_NOT_IMPLEMENTED
;
240 if (sjme_error_is(error
= sjme_thread_spinLockGrab(
241 &library
->common
.lock
)))
242 return sjme_error_default(error
);
244 /* Get the resource function. */
245 resourceFunc
= library
->functions
->resourceStream
;
247 /* Ask for the resource. */
248 /* Remember to remove any starting slash, because internally everything */
249 /* is treated as absolute. */
251 if (sjme_error_is(error
= resourceFunc(library
,
253 (rcName
[0] == '/' ? rcName
+ 1 : rcName
))) ||
255 goto fail_locateResource
;
257 /* Unlock library. */
258 if (sjme_error_is(error
= sjme_thread_spinLockRelease(
259 &library
->common
.lock
, NULL
)))
260 return sjme_error_default(error
);
264 return SJME_ERROR_NONE
;
266 /* Unlock library. */
268 sjme_thread_spinLockRelease(&library
->common
.lock
, NULL
);
270 return sjme_error_default(error
);