Base for method reading.
[SquirrelJME.git] / nanocoat / src / romSuiteZip.c
blobc6684187e0ddf641e8428a7abb03061e41d50873
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 <stdio.h>
11 #include <string.h>
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"
19 #include "sjme/zip.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)
31 #define BUF_SIZE 256
32 sjme_errorCode error;
33 sjme_zip zip;
34 sjme_zip_entry zipEntry;
35 sjme_stream_input inputStream;
36 sjme_jint valid;
37 sjme_cchar buf[BUF_SIZE];
38 sjme_lpstr str;
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;
46 /* Recover Zip. */
47 zip = inSuite->handle;
49 /* These are available from three entries essentially */
50 /* launcher.main */
51 memset(&zipEntry, 0, sizeof(zipEntry));
52 if (!sjme_error_is(sjme_zip_locateEntry(zip,
53 &zipEntry, "SQUIRRELJME.SQC/launcher.main")))
55 /* Open entry. */
56 inputStream = NULL;
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));
63 valid = INT32_MAX;
64 if (sjme_error_is(error = sjme_stream_inputReadFully(
65 inputStream, &valid,
66 buf, BUF_SIZE - 1)) || valid == INT32_MAX)
67 return sjme_error_default(error);
69 /* Duplicate main class. */
70 str = NULL;
71 if (sjme_error_is(error = sjme_alloc_strdup(
72 inPool, &str, (sjme_lpcstr)&buf[2])) || str == NULL)
73 return sjme_error_default(error);
75 /* Give it. */
76 *outMainClass = str;
78 /* Close. */
79 if (sjme_error_is(error = sjme_closeable_close(
80 SJME_AS_CLOSEABLE(inputStream))))
81 return sjme_error_default(error);
84 /* launcher.args */
85 memset(&zipEntry, 0, sizeof(zipEntry));
86 if (!sjme_error_is(sjme_zip_locateEntry(zip,
87 &zipEntry, "SQUIRRELJME.SQC/launcher.args")))
89 /* Open entry. */
90 inputStream = NULL;
91 if (sjme_error_is(error = sjme_zip_entryRead(&zipEntry,
92 &inputStream)) || inputStream == NULL)
93 return sjme_error_default(error);
95 /* Parse strings. */
96 strings = NULL;
97 if (sjme_error_is(error = sjme_listUtil_binListUtf(
98 inPool, &strings,
99 inputStream)) || strings == NULL)
100 return sjme_error_default(error);
102 /* Give it. */
103 *outMainArgs = strings;
105 /* Close. */
106 if (sjme_error_is(error = sjme_closeable_close(
107 SJME_AS_CLOSEABLE(inputStream))))
108 return sjme_error_default(error);
111 /* launcher.path */
112 memset(&zipEntry, 0, sizeof(zipEntry));
113 if (!sjme_error_is(sjme_zip_locateEntry(zip,
114 &zipEntry, "SQUIRRELJME.SQC/launcher.path")))
116 /* Open entry. */
117 inputStream = NULL;
118 if (sjme_error_is(error = sjme_zip_entryRead(&zipEntry,
119 &inputStream)) || inputStream == NULL)
120 return sjme_error_default(error);
122 /* Parse integers. */
123 ints = NULL;
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);
129 /* Give it. */
130 *outById = ints;
132 /* Close. */
133 if (sjme_error_is(error = sjme_closeable_close(
134 SJME_AS_CLOSEABLE(inputStream))))
135 return sjme_error_default(error);
138 /* Success! */
139 return SJME_ERROR_NONE;
140 #undef BUF_SIZE
143 static sjme_errorCode sjme_rom_zipSuiteInit(
144 sjme_attrInNotNull sjme_rom_suite inSuite,
145 sjme_attrInNullable sjme_pointer data)
147 if (inSuite == NULL)
148 return SJME_ERROR_NULL_ARGUMENTS;
150 /* Set handle, which is the Zip itself. */
151 inSuite->handle = data;
153 /* Success! */
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;
163 sjme_jint i, n;
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])
177 *outId = i;
178 return SJME_ERROR_NONE;
181 /* Failed. */
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;
190 sjme_zip zip;
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;
197 sjme_jint n, i;
198 sjme_cchar prefix[SJME_MAX_PATH];
200 if (inSuite == NULL || outLibraries == NULL)
201 return SJME_ERROR_NULL_ARGUMENTS;
203 /* Recover Zip. */
204 inPool = inSuite->cache.common.allocPool;
205 zip = inSuite->handle;
207 /* Initialize. */
208 inputStream = NULL;
209 suiteNames = NULL;
210 result = NULL;
212 /* launcher.args */
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);
218 /* Open entry. */
219 if (sjme_error_is(error = sjme_zip_entryRead(&zipEntry,
220 &inputStream)) || inputStream == NULL)
221 goto fail_openEntry;
223 /* Load entry strings. */
224 if (sjme_error_is(error = sjme_listUtil_binListUtf(inPool,
225 &suiteNames, inputStream)) || suiteNames == NULL)
226 goto fail_loadNames;
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;
232 inputStream = NULL;
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. */
250 lib = NULL;
251 if (sjme_error_is(error = sjme_rom_libraryFromZip(
252 inPool, &lib, suiteNames->elements[i],
253 prefix, zip)))
254 goto fail_loadLibrary;
256 /* Use it! */
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;
263 suiteNames = NULL;
265 /* Success! */
266 *outLibraries = result;
267 return SJME_ERROR_NONE;
269 fail_freeSuiteNames:
270 fail_loadLibrary:
271 fail_allocResult:
272 if (result != NULL)
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);
282 result = NULL;
284 fail_closeEntry:
285 fail_loadNames:
286 if (suiteNames != NULL)
287 sjme_alloc_free(suiteNames);
288 suiteNames = NULL;
290 fail_openEntry:
291 if (inputStream != NULL)
292 sjme_closeable_close(SJME_AS_CLOSEABLE(inputStream));
293 inputStream = NULL;
295 return sjme_error_default(error);
298 static sjme_errorCode sjme_rom_zipSuiteLoadLibrary()
300 sjme_todo("Impl?");
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;
320 sjme_zip zip;
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. */
327 zip = NULL;
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. */
333 result = NULL;
334 if (sjme_error_is(error = sjme_rom_suiteNew(pool,
335 &result, zip,
336 &sjme_rom_zipSuiteFunctions, NULL)) ||
337 result == NULL)
338 goto fail_suiteNew;
340 /* Count up Zip as we are using it. */
341 if (sjme_error_is(error = sjme_alloc_weakRef(zip, NULL)))
342 goto fail_refUp;
344 /* Success! */
345 *outSuite = result;
346 return SJME_ERROR_NONE;
348 fail_refUp:
349 fail_suiteNew:
350 /* Close the zip before failing. */
351 sjme_closeable_close(SJME_AS_CLOSEABLE(zip));
353 return sjme_error_default(error);