debug.c needs dylib.h.
[SquirrelJME.git] / nanocoat / src / romLibrary.c
blobde0dc62cf901c7bd4f89ee766ef928ef6b0209e7
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/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"
18 #include "sjme/zip.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);
39 /* Copy it in. */
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)
52 sjme_errorCode error;
53 sjme_rom_library result;
55 if (pool == NULL || outLibrary == NULL || inFunctions == NULL ||
56 libName == NULL)
57 return SJME_ERROR_NULL_ARGUMENTS;
59 /* Required. */
60 if (inFunctions->init == NULL ||
61 inFunctions->close == NULL)
62 return SJME_ERROR_NOT_IMPLEMENTED;
64 /* Allocate result. */
65 result = NULL;
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)
69 goto fail_alloc;
71 /* Setup result. */
72 result->cache.common.allocPool = pool;
73 result->functions = inFunctions;
75 /* Copy front end? */
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)))
82 goto fail_init;
84 /* Set library name. */
85 result->name = NULL;
86 if (sjme_error_is(error = sjme_alloc_strdup(pool,
87 (sjme_lpstr*)&result->name, libName)))
88 goto fail_strdup;
90 /* Success! */
91 *outLibrary = result;
92 return SJME_ERROR_NONE;
94 fail_refUp:
95 fail_strdup:
96 fail_init:
97 fail_commonInit:
98 fail_alloc:
99 if (result != NULL)
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;
126 sjme_jint libSize;
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. */
147 libSize = -2;
148 if (sjme_error_is(error = sjme_rom_libraryRawSize(library,
149 &libSize)) || libSize < 0)
151 if (libSize == -1)
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)
177 sjme_jint result;
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. */
197 result = -2;
198 if (sjme_error_is(error = library->functions->rawSize(
199 library, &result)) || result < 0)
201 if (result == -1)
202 goto fail_unsupported;
203 return sjme_error_default(error);
206 /* Return result. */
207 *outSize = result;
208 return SJME_ERROR_NONE;
210 fail_unsupported:
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;
218 /* Not supported! */
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;
239 /* Lock library. */
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. */
250 result = NULL;
251 if (sjme_error_is(error = resourceFunc(library,
252 &result,
253 (rcName[0] == '/' ? rcName + 1 : rcName))) ||
254 result == NULL)
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);
262 /* Success! */
263 *outStream = result;
264 return SJME_ERROR_NONE;
266 /* Unlock library. */
267 fail_locateResource:
268 sjme_thread_spinLockRelease(&library->common.lock, NULL);
270 return sjme_error_default(error);