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/nvm/rom.h"
14 #include "sjme/alloc.h"
15 #include "sjme/debug.h"
16 #include "sjme/nvm/payload.h"
17 #include "sjme/nvm/romInternal.h"
18 #include "sjme/util.h"
20 #include "sjme/cleanup.h"
21 #include "sjme/listUtil.h"
23 static sjme_errorCode
sjme_rom_zipSuiteDefaultLaunch(
24 sjme_attrInNotNull sjme_alloc_pool
* inPool
,
25 sjme_attrInNotNull sjme_rom_suite inSuite
,
26 sjme_attrOutNotNull sjme_lpstr
* outMainClass
,
27 sjme_attrOutNotNull sjme_list_sjme_lpstr
** outMainArgs
,
28 sjme_attrOutNotNull sjme_list_sjme_jint
** outById
,
29 sjme_attrOutNotNull sjme_list_sjme_lpstr
** outByName
)
34 sjme_zip_entry zipEntry
;
35 sjme_stream_input inputStream
;
37 sjme_cchar buf
[BUF_SIZE
];
39 sjme_list_sjme_lpstr
* strings
;
40 sjme_list_sjme_jint
* ints
;
42 if (inPool
== NULL
|| inSuite
== NULL
|| outMainClass
== NULL
||
43 outMainArgs
== NULL
|| outById
== NULL
|| outByName
== NULL
)
44 return SJME_ERROR_NULL_ARGUMENTS
;
47 zip
= inSuite
->handle
;
49 /* These are available from three entries essentially */
51 memset(&zipEntry
, 0, sizeof(zipEntry
));
52 if (!sjme_error_is(sjme_zip_locateEntry(zip
,
53 &zipEntry
, "SQUIRRELJME.SQC/launcher.main")))
57 if (sjme_error_is(error
= sjme_zip_entryRead(&zipEntry
,
58 &inputStream
)) || inputStream
== NULL
)
59 return sjme_error_default(error
);
61 /* Read everything in. */
62 memset(buf
, 0, sizeof(buf
));
64 if (sjme_error_is(error
= sjme_stream_inputReadFully(
66 buf
, BUF_SIZE
- 1)) || valid
== INT32_MAX
)
67 return sjme_error_default(error
);
69 /* Duplicate main class. */
71 if (sjme_error_is(error
= sjme_alloc_strdup(
72 inPool
, &str
, (sjme_lpcstr
)&buf
[2])) || str
== NULL
)
73 return sjme_error_default(error
);
79 if (sjme_error_is(error
= sjme_closeable_close(
80 SJME_AS_CLOSEABLE(inputStream
))))
81 return sjme_error_default(error
);
85 memset(&zipEntry
, 0, sizeof(zipEntry
));
86 if (!sjme_error_is(sjme_zip_locateEntry(zip
,
87 &zipEntry
, "SQUIRRELJME.SQC/launcher.args")))
91 if (sjme_error_is(error
= sjme_zip_entryRead(&zipEntry
,
92 &inputStream
)) || inputStream
== NULL
)
93 return sjme_error_default(error
);
97 if (sjme_error_is(error
= sjme_listUtil_binListUtf(
99 inputStream
)) || strings
== NULL
)
100 return sjme_error_default(error
);
103 *outMainArgs
= strings
;
106 if (sjme_error_is(error
= sjme_closeable_close(
107 SJME_AS_CLOSEABLE(inputStream
))))
108 return sjme_error_default(error
);
112 memset(&zipEntry
, 0, sizeof(zipEntry
));
113 if (!sjme_error_is(sjme_zip_locateEntry(zip
,
114 &zipEntry
, "SQUIRRELJME.SQC/launcher.path")))
118 if (sjme_error_is(error
= sjme_zip_entryRead(&zipEntry
,
119 &inputStream
)) || inputStream
== NULL
)
120 return sjme_error_default(error
);
122 /* Parse integers. */
124 if (sjme_error_is(error
= sjme_listUtil_binListInt(
125 inPool
, SJME_AS_LISTP_VOID(&ints
),
126 inputStream
)) || ints
== NULL
)
127 return sjme_error_default(error
);
133 if (sjme_error_is(error
= sjme_closeable_close(
134 SJME_AS_CLOSEABLE(inputStream
))))
135 return sjme_error_default(error
);
139 return SJME_ERROR_NONE
;
143 static sjme_errorCode
sjme_rom_zipSuiteInit(
144 sjme_attrInNotNull sjme_rom_suite inSuite
,
145 sjme_attrInNullable sjme_pointer data
)
148 return SJME_ERROR_NULL_ARGUMENTS
;
150 /* Set handle, which is the Zip itself. */
151 inSuite
->handle
= data
;
154 return SJME_ERROR_NONE
;
157 static sjme_errorCode
sjme_rom_zipSuiteLibraryId(
158 sjme_attrInNotNull sjme_rom_suite inSuite
,
159 sjme_attrInNotNull sjme_rom_library inLibrary
,
160 sjme_attrOutNotNull sjme_jint
* outId
)
162 sjme_list_sjme_rom_library
* libs
;
165 if (inSuite
== NULL
|| inLibrary
== NULL
|| outId
== NULL
)
166 return SJME_ERROR_NULL_ARGUMENTS
;
168 /* This needs to be known. */
169 libs
= inSuite
->cache
.libraries
;
170 if (inSuite
->cache
.libraries
== NULL
)
171 return SJME_ERROR_ILLEGAL_STATE
;
173 /* Find the right one, its ID is just its index. */
174 for (i
= 0, n
= libs
->length
; i
< n
; i
++)
175 if (inLibrary
== libs
->elements
[i
])
178 return SJME_ERROR_NONE
;
182 return SJME_ERROR_LIBRARY_NOT_FOUND
;
185 static sjme_errorCode
sjme_rom_zipSuiteListLibraries(
186 sjme_attrInNotNull sjme_rom_suite inSuite
,
187 sjme_attrOutNotNull sjme_list_sjme_rom_library
** outLibraries
)
189 sjme_errorCode error
;
191 sjme_zip_entry zipEntry
;
192 sjme_stream_input inputStream
;
193 sjme_alloc_pool
* inPool
;
194 sjme_list_sjme_lpstr
* suiteNames
;
195 sjme_list_sjme_rom_library
* result
;
196 sjme_rom_library lib
;
198 sjme_cchar prefix
[SJME_MAX_PATH
];
200 if (inSuite
== NULL
|| outLibraries
== NULL
)
201 return SJME_ERROR_NULL_ARGUMENTS
;
204 inPool
= inSuite
->cache
.common
.allocPool
;
205 zip
= inSuite
->handle
;
213 memset(&zipEntry
, 0, sizeof(zipEntry
));
214 if (sjme_error_is(error
= sjme_zip_locateEntry(zip
,
215 &zipEntry
, "SQUIRRELJME.SQC/suites.list")))
216 return sjme_error_default(error
);
219 if (sjme_error_is(error
= sjme_zip_entryRead(&zipEntry
,
220 &inputStream
)) || inputStream
== NULL
)
223 /* Load entry strings. */
224 if (sjme_error_is(error
= sjme_listUtil_binListUtf(inPool
,
225 &suiteNames
, inputStream
)) || suiteNames
== NULL
)
228 /* Close entry, we do not need it anymore. */
229 if (sjme_error_is(error
= sjme_closeable_close(
230 SJME_AS_CLOSEABLE(inputStream
))))
231 goto fail_closeEntry
;
234 /* Setup target library list */
235 n
= suiteNames
->length
;
236 if (sjme_error_is(error
= sjme_list_alloc(inPool
,
237 n
, &result
, sjme_rom_library
, 0)) || result
== NULL
)
238 goto fail_allocResult
;
240 /* Load in each library with its own Zip variant. */
241 for (i
= 0; i
< n
; i
++)
243 /* Determine prefix to be used. */
244 memset(prefix
, 0, sizeof(prefix
));
245 snprintf(prefix
, SJME_MAX_PATH
- 1,
246 "SQUIRRELJME.SQC/%s",
247 suiteNames
->elements
[i
]);
249 /* Load in single library with the specified prefix. */
251 if (sjme_error_is(error
= sjme_rom_libraryFromZip(
252 inPool
, &lib
, suiteNames
->elements
[i
],
254 goto fail_loadLibrary
;
257 result
->elements
[i
] = lib
;
260 /* We no longer need the names. */
261 if (sjme_error_is(error
= sjme_alloc_free(suiteNames
)))
262 goto fail_freeSuiteNames
;
266 *outLibraries
= result
;
267 return SJME_ERROR_NONE
;
274 /* Make sure all libraries are removed. */
275 for (i
= 0, n
= result
->length
; i
< n
; i
++)
276 if (result
->elements
[i
] != NULL
)
277 sjme_closeable_close(
278 SJME_AS_CLOSEABLE(result
->elements
[i
]));
280 /* Then free the actual result. */
281 sjme_alloc_free(result
);
286 if (suiteNames
!= NULL
)
287 sjme_alloc_free(suiteNames
);
291 if (inputStream
!= NULL
)
292 sjme_closeable_close(SJME_AS_CLOSEABLE(inputStream
));
295 return sjme_error_default(error
);
298 static sjme_errorCode
sjme_rom_zipSuiteLoadLibrary()
301 return sjme_error_notImplemented(0);
304 /** Functions for Zip based suites. */
305 static sjme_rom_suiteFunctions sjme_rom_zipSuiteFunctions
=
307 .defaultLaunch
= sjme_rom_zipSuiteDefaultLaunch
,
308 .init
= sjme_rom_zipSuiteInit
,
309 .libraryId
= sjme_rom_zipSuiteLibraryId
,
310 .list
= sjme_rom_zipSuiteListLibraries
,
311 .loadLibrary
= sjme_rom_zipSuiteLoadLibrary
,
314 sjme_errorCode
sjme_rom_suiteFromZipSeekable(
315 sjme_attrInNotNull sjme_alloc_pool
* pool
,
316 sjme_attrOutNotNull sjme_rom_suite
* outSuite
,
317 sjme_attrInNotNull sjme_seekable seekable
)
319 sjme_errorCode error
;
321 sjme_rom_suite result
;
323 if (pool
== NULL
|| outSuite
== NULL
|| seekable
== NULL
)
324 return SJME_ERROR_NULL_ARGUMENTS
;
326 /* Try opening as a Zip file. */
328 if (sjme_error_is(error
= sjme_zip_openSeekable(pool
, &zip
,
329 seekable
)) || zip
== NULL
)
330 return sjme_error_default(error
);
332 /* Setup new suite. */
334 if (sjme_error_is(error
= sjme_rom_suiteNew(pool
,
336 &sjme_rom_zipSuiteFunctions
, NULL
)) ||
340 /* Count up Zip as we are using it. */
341 if (sjme_error_is(error
= sjme_alloc_weakRef(zip
, NULL
)))
346 return SJME_ERROR_NONE
;
350 /* Close the zip before failing. */
351 sjme_closeable_close(SJME_AS_CLOSEABLE(zip
));
353 return sjme_error_default(error
);