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 // -------------------------------------------------------------------------*/
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"
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
;
29 if (pool
== NULL
|| outLibrary
== NULL
|| base
== NULL
)
30 return SJME_ERROR_NULL_ARGUMENTS
;
33 return SJME_ERROR_INDEX_OUT_OF_BOUNDS
;
35 /* Get source seekable. */
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
);
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
;
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. */
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
;
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
;
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. */
174 if (sjme_error_is(error
= sjme_rom_libraryRawSize(library
,
175 &libSize
)) || libSize
< 0)
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
)
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. */
224 if (sjme_error_is(error
= library
->functions
->rawSize(
225 library
, &result
)) || result
< 0)
228 goto fail_unsupported
;
229 return sjme_error_default(error
);
234 return SJME_ERROR_NONE
;
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
;
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. */
270 if (sjme_error_is(error
= resourceFunc(library
,
271 &result
, rcName
)) || result
== NULL
)
272 return sjme_error_default(error
);
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
;
294 sjme_message("sjme_rom_resolveClassPathById(%p, %p, %p)",
295 inSuite
, inIds
, outLibs
);
297 /* How many are we looking for? */
298 length
= inIds
->length
;
300 return SJME_ERROR_INVALID_ARGUMENT
;
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
);
308 return sjme_error_outOfMemory(NULL
, length
);
310 /* Make sure it is cleared. */
311 memset(working
, 0, sizeof(*working
) * length
);
314 sjme_message("Getting library list...");
316 /* Obtain the list of libraries within the suite. */
318 if (sjme_error_is(error
= sjme_rom_suiteLibraries(inSuite
,
319 &suiteLibs
)) || suiteLibs
== NULL
)
320 return sjme_error_default(error
);
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)
336 sjme_message("Looking at library #%d: %p",
340 /* Need to initialize the ID? */
341 libId
= checkLibrary
->id
;
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
;
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
;
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
;
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
);
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. */
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
,
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
))
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
)
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. */
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
;
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
;
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. */
523 for (i
= 0; i
< SJME_NVM_PAYLOAD_MAX_ROMS
; i
++)
524 if (payloadConfig
->roms
[i
].isActive
)
529 /* Anything that is a library we need to build a container. */
530 if (payloadConfig
->roms
[i
].isLibrary
)
534 /* If there is nothing active then nothing needs to be done. */
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. */
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
;
594 return SJME_ERROR_NONE
;