Remove except as it is very clunky to use, there are simpler ways; More corrections...
[SquirrelJME.git] / nanocoat / src / rom.c
blobdc47f904aa26fac47fed1f97c2236337469621d1
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/rom.h"
13 #include "sjme/alloc.h"
14 #include "sjme/debug.h"
15 #include "sjme/payload.h"
16 #include "sjme/romInternal.h"
17 #include "sjme/util.h"
18 #include "sjme/zip.h"
20 sjme_errorCode sjme_rom_libraryFromZipMemory(
21 sjme_attrInNotNull sjme_alloc_pool* pool,
22 sjme_attrOutNotNull sjme_rom_library* outLibrary,
23 sjme_attrInNotNull sjme_cpointer base,
24 sjme_attrInPositive sjme_jint length)
26 sjme_seekable seekable;
27 sjme_errorCode error;
29 if (pool == NULL || outLibrary == NULL || base == NULL)
30 return SJME_ERROR_NULL_ARGUMENTS;
32 if (length < 0)
33 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
35 /* Get source seekable. */
36 seekable = NULL;
37 if (sjme_error_is(error = sjme_seekable_fromMemory(pool,
38 &seekable, base, length)) || seekable == NULL)
40 /* This is just an alias for the other function. */
41 return sjme_rom_libraryFromZipSeekable(pool, outLibrary, seekable);
44 sjme_errorCode sjme_rom_libraryFromZipSeekable(
45 sjme_attrInNotNull sjme_alloc_pool* pool,
46 sjme_attrOutNotNull sjme_rom_library* outLibrary,
47 sjme_attrInNotNull sjme_seekable seekable)
49 if (pool == NULL || outLibrary == NULL || seekable == NULL)
50 return SJME_ERROR_NULL_ARGUMENTS;
52 sjme_todo("Implement this?");
53 return SJME_ERROR_NOT_IMPLEMENTED;
56 sjme_errorCode sjme_rom_libraryHash(
57 sjme_attrInNotNull sjme_rom_library library,
58 sjme_attrOutNotNull sjme_jint* outHash)
60 if (library == NULL || outHash == NULL)
61 return SJME_ERROR_NULL_ARGUMENTS;
63 /* Does it need to be calculated? */
64 if (library->nameHash == 0)
66 /* This should always be set. */
67 if (library->name == NULL)
68 return SJME_ERROR_ILLEGAL_STATE;
70 /* Calculate the hash. */
71 library->nameHash = sjme_string_hash(library->name);
74 /* Copy it in. */
75 *outHash = library->nameHash;
76 return SJME_ERROR_NONE;
79 sjme_errorCode sjme_rom_libraryNew(
80 sjme_attrInNotNull sjme_alloc_pool* pool,
81 sjme_attrOutNotNull sjme_rom_library* outLibrary,
82 sjme_attrInNotNull const sjme_rom_libraryFunctions* inFunctions,
83 sjme_attrInNullable const sjme_frontEnd* inFrontEnd)
85 sjme_rom_libraryInitCacheFunc initCacheFunc;
86 sjme_rom_library result;
87 sjme_errorCode error;
89 if (pool == NULL || outLibrary == NULL || inFunctions == NULL)
90 return SJME_ERROR_NULL_ARGUMENTS;
92 /* There needs to be a cache initializer. */
93 initCacheFunc = inFunctions->initCache;
94 if (initCacheFunc == NULL)
95 return SJME_ERROR_INVALID_ARGUMENT;
97 /* Allocate resultant library. */
98 result = NULL;
99 if (sjme_error_is(error = sjme_alloc(pool,
100 SJME_SIZEOF_LIBRARY_CORE_N(inFunctions->uncommonTypeSize),
101 (sjme_pointer*)&result)) || result == NULL)
102 return sjme_error_default(error);
104 /* Setup some basic cache details. */
105 result->functions = inFunctions;
106 result->cache.common.allocPool = pool;
107 result->cache.common.uncommonSize = inFunctions->uncommonTypeSize;
109 /* Seed front end information? */
110 if (inFrontEnd != NULL)
111 result->cache.common.frontEnd = *inFrontEnd;
113 /* Initialize cache. */
114 if (sjme_error_is(error = initCacheFunc(result)))
116 /* Cleanup bad pointer. */
117 sjme_alloc_free(result);
119 return sjme_error_default(error);
122 /* Initialize fields. */
123 result->functions = inFunctions;
124 result->cache.common.allocPool = pool;
126 /* Use result. */
127 *outLibrary = result;
128 return SJME_ERROR_NONE;
131 sjme_errorCode sjme_rom_libraryRawRead(
132 sjme_attrInNotNull sjme_rom_library library,
133 sjme_attrOutNotNullBuf(length) sjme_pointer destPtr,
134 sjme_attrInPositive sjme_jint srcPos,
135 sjme_attrInPositive sjme_jint length)
137 /* This is just an alias for the other. */
138 return sjme_rom_libraryRawReadIter(
139 library, destPtr, 0, srcPos, 0, length);
142 sjme_errorCode sjme_rom_libraryRawReadIter(
143 sjme_attrInNotNull sjme_rom_library library,
144 sjme_attrOutNotNullBuf(length) sjme_pointer destPtr,
145 sjme_attrInPositive sjme_jint destOffset,
146 sjme_attrInPositive sjme_jint srcPos,
147 sjme_attrInPositive sjme_jint srcOffset,
148 sjme_attrInPositive sjme_jint length)
150 uintptr_t rawDestPtr;
151 sjme_errorCode error;
152 sjme_jint libSize;
154 if (library == NULL || destPtr == NULL)
155 return SJME_ERROR_NULL_ARGUMENTS;
157 /* Do we already know this will not work? */
158 if (library->cache.checkedRawAccess &&
159 !library->cache.validRawAccess)
160 return SJME_ERROR_UNSUPPORTED_OPERATION;
162 /* Check all the bounds variants possible, for overflow as well. */
163 rawDestPtr = (uintptr_t)destPtr;
164 if (destOffset < 0 || srcPos < 0 || srcOffset < 0 || length < 0 ||
165 (destOffset + length) < 0 || (srcPos + length) < 0 ||
166 (srcOffset + length) < 0 || (srcPos + srcOffset + length) < 0 ||
167 (rawDestPtr + destOffset) < rawDestPtr ||
168 (rawDestPtr + length) < rawDestPtr ||
169 (rawDestPtr + destOffset + length) < rawDestPtr)
170 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
172 /* Get the raw size of the target library. */
173 libSize = -2;
174 if (sjme_error_is(error = sjme_rom_libraryRawSize(library,
175 &libSize)) || libSize < 0)
177 if (libSize == -1)
178 return sjme_error_defaultOr(error,
179 SJME_ERROR_UNSUPPORTED_OPERATION);
180 return sjme_error_default(error);
183 /* Check bounds of the size to ensure it is correct. */
184 if (length > libSize || (srcPos + length) > libSize ||
185 (srcPos + srcOffset) > libSize ||
186 (srcPos + srcOffset + length) > libSize)
187 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
189 /* Check native library handler. */
190 if (library->functions->rawData == NULL)
191 return SJME_ERROR_UNSUPPORTED_OPERATION;
193 /* Call native library handler, which takes simpler arguments. */
194 return library->functions->rawData(library,
195 (sjme_pointer)(((uintptr_t)destPtr) + destOffset),
196 srcPos + srcOffset, length);
199 sjme_errorCode sjme_rom_libraryRawSize(
200 sjme_attrInNotNull sjme_rom_library library,
201 sjme_attrOutNotNull sjme_jint* outSize)
203 sjme_jint result;
204 sjme_errorCode error;
206 if (library == NULL || outSize == NULL)
207 return SJME_ERROR_NULL_ARGUMENTS;
209 /* Do we already know this will not work? */
210 if (library->cache.checkedRawAccess &&
211 !library->cache.validRawAccess)
212 return SJME_ERROR_UNSUPPORTED_OPERATION;
214 /* Size was already determined? */
215 if (library->cache.size > 0)
216 return library->cache.size;
218 /* Native handler must be valid! */
219 if (library->functions->rawSize == NULL)
220 goto fail_unsupported;
222 /* Call native handler. */
223 result = -2;
224 if (sjme_error_is(error = library->functions->rawSize(
225 library, &result)) || result < 0)
227 if (result == -1)
228 goto fail_unsupported;
229 return sjme_error_default(error);
232 /* Return result. */
233 *outSize = result;
234 return SJME_ERROR_NONE;
236 fail_unsupported:
237 /* Cache whether this is supported so we need not bother? */
238 if (!library->cache.checkedRawAccess)
240 library->cache.checkedRawAccess = SJME_JNI_TRUE;
241 library->cache.validRawAccess = SJME_JNI_FALSE;
244 /* Not supported! */
245 return SJME_ERROR_UNSUPPORTED_OPERATION;
248 sjme_errorCode sjme_rom_libraryResourceAsStream(
249 sjme_attrInNotNull sjme_rom_library library,
250 sjme_attrOutNotNull sjme_stream_input* outStream,
251 sjme_attrInNotNull sjme_lpcstr rcName)
253 sjme_rom_libraryResourceStreamFunc resourceFunc;
254 sjme_stream_input result;
255 sjme_errorCode error;
257 if (library == NULL || outStream == NULL || rcName == NULL)
258 return SJME_ERROR_NULL_ARGUMENTS;
260 /* These must be set. */
261 if (library->functions == NULL ||
262 library->functions->resourceStream == NULL)
263 return SJME_ERROR_ILLEGAL_STATE;
265 /* Get the resource function. */
266 resourceFunc = library->functions->resourceStream;
268 /* Ask for the resource. */
269 result = NULL;
270 if (sjme_error_is(error = resourceFunc(library,
271 &result, rcName)) || result == NULL)
272 return sjme_error_default(error);
274 /* Success! */
275 *outStream = result;
276 return SJME_ERROR_NONE;
279 sjme_errorCode sjme_rom_resolveClassPathById(
280 sjme_attrInNotNull sjme_rom_suite inSuite,
281 sjme_attrInNotNull const sjme_list_sjme_jint* inIds,
282 sjme_attrOutNotNull sjme_list_sjme_rom_library** outLibs)
284 sjme_list_sjme_rom_library* suiteLibs;
285 sjme_errorCode error;
286 sjme_jint length, i, numLibs, at, libId;
287 sjme_rom_library* working;
288 sjme_rom_library checkLibrary;
290 if (inSuite == NULL || inIds == NULL || outLibs == NULL)
291 return SJME_ERROR_NULL_ARGUMENTS;
293 /* Debug. */
294 sjme_message("sjme_rom_resolveClassPathById(%p, %p, %p)",
295 inSuite, inIds, outLibs);
297 /* How many are we looking for? */
298 length = inIds->length;
299 if (length < 0)
300 return SJME_ERROR_INVALID_ARGUMENT;
302 /* Debug. */
303 sjme_message("Looking for %d libraries...", length);
305 /* Allocate temporary storage on the stack for the libraries we want. */
306 working = sjme_alloca(sizeof(*working) * length);
307 if (working == NULL)
308 return sjme_error_outOfMemory(NULL, length);
310 /* Make sure it is cleared. */
311 memset(working, 0, sizeof(*working) * length);
313 /* Debug. */
314 sjme_message("Getting library list...");
316 /* Obtain the list of libraries within the suite. */
317 suiteLibs = NULL;
318 if (sjme_error_is(error = sjme_rom_suiteLibraries(inSuite,
319 &suiteLibs)) || suiteLibs == NULL)
320 return sjme_error_default(error);
322 /* Debug. */
323 sjme_message("Done: %p!", suiteLibs);
324 sjme_message("Found %d libraries.", suiteLibs->length);
326 /* Go through and find the ones with matching IDs. */
327 /* Order by library because there is likely to be more of those. */
328 numLibs = suiteLibs->length;
329 for (i = 0; i < numLibs; i++)
331 /* Which library is this? */
332 checkLibrary = suiteLibs->elements[i];
334 #if defined(SJME_CONFIG_DEBUG)
335 /* Debug. */
336 sjme_message("Looking at library #%d: %p",
337 i, checkLibrary);
338 #endif
340 /* Need to initialize the ID? */
341 libId = checkLibrary->id;
342 if (libId == 0)
344 /* No function? */
345 if (inSuite->functions->libraryId == NULL)
346 return SJME_ERROR_ILLEGAL_STATE;
348 /* Get the library ID. */
349 if (sjme_error_is(error = inSuite->functions->libraryId(
350 inSuite, checkLibrary, &libId)))
351 return sjme_error_default(error);
353 /* Library ID function did not store it? */
354 if (checkLibrary->id == 0)
355 checkLibrary->id = libId;
358 /* Scan through the requested classpath for matches. */
359 for (at = 0; at < length; at++)
360 if (inIds->elements[at] == libId)
362 working[at] = checkLibrary;
363 break;
367 /* Scan through and fail if any are null, that is not found. */
368 for (at = 0; at < length; at++)
369 if (working[at] == NULL)
370 return SJME_ERROR_LIBRARY_NOT_FOUND;
372 /* Return the libraries which gets placed into a list as a copy. */
373 return sjme_list_newA(inSuite->cache.common.allocPool,
374 sjme_rom_library, 0, length, outLibs, working);
377 sjme_errorCode sjme_rom_resolveClassPathByName(
378 sjme_attrInNotNull sjme_rom_suite inSuite,
379 sjme_attrInNotNull const sjme_list_sjme_lpcstr* inNames,
380 sjme_attrOutNotNull sjme_list_sjme_rom_library** outLibs)
382 sjme_list_sjme_rom_library* suiteLibs;
383 sjme_errorCode error;
384 sjme_jint length, i, at, hash, numSuiteLibs;
385 sjme_rom_library* working;
386 sjme_rom_library lib;
387 sjme_jint* inHashes;
389 if (inSuite == NULL || inNames == NULL || outLibs == NULL)
390 return SJME_ERROR_NULL_ARGUMENTS;
392 /* How many are we looking for? */
393 length = inNames->length;
394 if (length < 0)
395 return SJME_ERROR_INVALID_ARGUMENT;
397 /* Make sure there are no NULL libraries as input. */
398 for (i = 0; i < length; i++)
399 if (inNames->elements[i] == NULL)
400 return SJME_ERROR_NULL_ARGUMENTS;
402 /* Allocate temporary storage on the stack for the libraries we want. */
403 working = sjme_alloca(sizeof(*working) * length);
404 inHashes = sjme_alloca(sizeof(*inHashes) * length);
405 if (working == NULL || inHashes == NULL)
406 return sjme_error_outOfMemory(NULL, length);
408 /* Clear memory. */
409 memset(working, 0, sizeof(*working) * length);
410 memset(inHashes, 0, sizeof(*inHashes) * length);
412 /* First hash all the input libraries, so we can quickly scan through. */
413 for (i = 0; i < length; i++)
414 inHashes[i] = sjme_string_hash(inNames->elements[i]);
416 /* Obtain the list of libraries within the suite. */
417 suiteLibs = NULL;
418 if (sjme_error_is(error = sjme_rom_suiteLibraries(inSuite,
419 &suiteLibs) || suiteLibs == NULL))
420 return sjme_error_default(error);
422 /* Go through each library and get hash matches. */
423 numSuiteLibs = suiteLibs->length;
424 for (i = 0; i < numSuiteLibs; i++)
426 /* Get hash of this library. */
427 lib = suiteLibs->elements[i];
428 if (sjme_error_is(error = sjme_rom_libraryHash(lib,
429 &hash)))
430 return sjme_error_default(error);
432 /* Look for match in output. */
433 for (at = 0; at < length; at++)
434 if (working[at] == NULL && inHashes[at] == hash &&
435 0 == strcmp(inNames->elements[at], lib->name))
436 working[at] = lib;
439 /* Scan through and fail if any are null, that is not found. */
440 for (at = 0; at < length; at++)
441 if (working[at] == NULL)
442 return SJME_ERROR_LIBRARY_NOT_FOUND;
444 /* Return the libraries which gets placed into a list as a copy. */
445 return sjme_list_newA(inSuite->cache.common.allocPool,
446 sjme_rom_library, 0, length, outLibs, working);
449 sjme_errorCode sjme_rom_suiteLibraries(
450 sjme_attrInNotNull sjme_rom_suite inSuite,
451 sjme_attrOutNotNull sjme_list_sjme_rom_library** outLibs)
453 sjme_rom_suiteCache* cache;
454 sjme_rom_suiteListLibrariesFunc listFunc;
455 sjme_list_sjme_rom_library* result;
456 sjme_errorCode error;
458 if (inSuite == NULL || outLibs == NULL)
459 return SJME_ERROR_NULL_ARGUMENTS;
461 /* Must be a valid cache. */
462 cache = &inSuite->cache;
463 if (cache->common.allocPool == NULL)
464 return SJME_ERROR_ILLEGAL_STATE;
466 /* Has this been processed already? */
467 if (cache->libraries != NULL)
469 /* Debug. */
470 sjme_message("Using existing cache: %p", cache->libraries);
472 *outLibs = cache->libraries;
473 return SJME_ERROR_NONE;
476 /* Check list function. */
477 listFunc = inSuite->functions->list;
478 if (listFunc == NULL)
479 return SJME_ERROR_ILLEGAL_STATE;
481 /* Call the list function. */
482 result = NULL;
483 if (sjme_error_is(error = listFunc(inSuite,
484 &result)) || result == NULL)
485 return sjme_error_default(error);
487 /* Store it within the cache. */
488 cache->libraries = result;
490 /* Success! */
491 *outLibs = result;
492 return SJME_ERROR_NONE;
494 sjme_errorCode sjme_rom_suiteFromMerge(
495 sjme_attrInNotNull sjme_alloc_pool* pool,
496 sjme_attrOutNotNull sjme_rom_suite* outSuite,
497 sjme_attrInNotNull sjme_rom_suite* inSuites,
498 sjme_attrInPositive sjme_jint numInSuites)
500 if (pool == NULL || outSuite == NULL || inSuites == NULL)
501 return SJME_ERROR_NULL_ARGUMENTS;
503 if (numInSuites < 0)
504 return SJME_ERROR_INVALID_ARGUMENT;
506 sjme_todo("Implement this?");
507 return SJME_ERROR_UNKNOWN;
510 sjme_errorCode sjme_rom_suiteFromPayload(
511 sjme_attrInNotNull sjme_alloc_pool* pool,
512 sjme_attrOutNotNull sjme_rom_suite* outSuite,
513 sjme_attrInNotNull const sjme_payload_config* payloadConfig)
515 sjme_jint i, numActive, numLibraries;
517 if (pool == NULL || outSuite == NULL || payloadConfig == NULL)
518 return SJME_ERROR_NULL_ARGUMENTS;
520 /* Count the number of active ROMs. */
521 numActive = 0;
522 numLibraries = 0;
523 for (i = 0; i < SJME_NVM_PAYLOAD_MAX_ROMS; i++)
524 if (payloadConfig->roms[i].isActive)
526 /* Count up! */
527 numActive++;
529 /* Anything that is a library we need to build a container. */
530 if (payloadConfig->roms[i].isLibrary)
531 numLibraries++;
534 /* If there is nothing active then nothing needs to be done. */
535 if (numActive == 0)
537 *outSuite = NULL;
538 return SJME_ERROR_NONE;
541 sjme_todo("Implement this?");
542 return SJME_ERROR_UNKNOWN;
545 sjme_errorCode sjme_rom_suiteNew(
546 sjme_attrInNotNull sjme_alloc_pool* pool,
547 sjme_attrOutNotNull sjme_rom_suite* outSuite,
548 sjme_attrInNotNull const sjme_rom_suiteFunctions* inFunctions,
549 sjme_attrInNullable const sjme_frontEnd* inFrontEnd)
551 sjme_rom_suiteInitCacheFunc initCacheFunc;
552 sjme_rom_suite result;
553 sjme_errorCode error;
555 if (pool == NULL || outSuite == NULL || inFunctions == NULL)
556 return SJME_ERROR_NULL_ARGUMENTS;
558 /* There needs to be a cache initializer. */
559 initCacheFunc = inFunctions->initCache;
560 if (initCacheFunc == NULL)
561 return SJME_ERROR_INVALID_ARGUMENT;
563 /* Allocate resultant suite. */
564 result = NULL;
565 if (sjme_error_is(error = sjme_alloc(pool,
566 SJME_SIZEOF_SUITE_CORE_N(inFunctions->uncommonTypeSize),
567 (sjme_pointer*)&result)) || result == NULL)
568 return sjme_error_default(error);
570 /* Setup some basic cache details. */
571 result->functions = inFunctions;
572 result->cache.common.allocPool = pool;
573 result->cache.common.uncommonSize = inFunctions->uncommonTypeSize;
575 /* Seed front end information? */
576 if (inFrontEnd != NULL)
577 result->cache.common.frontEnd = *inFrontEnd;
579 /* Initialize cache. */
580 if (sjme_error_is(error = initCacheFunc(result)))
582 /* Cleanup bad pointer. */
583 sjme_alloc_free(result);
585 return sjme_error_default(error);
588 /* Initialize fields. */
589 result->functions = inFunctions;
590 result->cache.common.allocPool = pool;
592 /* Use result. */
593 *outSuite = result;
594 return SJME_ERROR_NONE;