Adjust sourcize.c to use _snprintf if using MSVC.
[SquirrelJME.git] / nanocoat / src / romLibraryZip.c
blob71da7bea746924803a8ce7d967a961359520479d
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>
11 #include <stdio.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"
22 /**
23 * Initialization data for Zip libraries.
25 * @since 2024/09/07
27 typedef struct sjme_rom_zipLibraryInitData
29 /** The Zip to access. */
30 sjme_zip zip;
32 /** The prefix for entry access. */
33 sjme_lpcstr prefix;
34 } sjme_rom_zipLibraryInitData;
36 static sjme_errorCode sjme_rom_zipLibraryClose(
37 sjme_attrInNotNull sjme_rom_library inLibrary)
39 sjme_errorCode error;
40 sjme_zip zip;
42 if (inLibrary == NULL)
43 return SJME_ERROR_NULL_ARGUMENTS;
45 /* Recover zip, ignore if already closed. */
46 zip = inLibrary->handle;
47 if (zip == NULL)
48 return SJME_ERROR_NONE;
50 /* Close it. */
51 if (sjme_error_is(error = sjme_closeable_close(
52 SJME_AS_CLOSEABLE(zip))))
53 return sjme_error_default(error);
55 /* Remove reference to it. */
56 inLibrary->handle = NULL;
58 /* Success! */
59 return SJME_ERROR_NONE;
62 static sjme_errorCode sjme_rom_zipLibraryInit(
63 sjme_attrInNotNull sjme_rom_library inLibrary,
64 sjme_attrInNullable sjme_pointer data)
66 sjme_errorCode error;
67 sjme_rom_zipLibraryInitData* init;
69 init = data;
70 if (inLibrary == NULL || init == NULL)
71 return SJME_ERROR_NULL_ARGUMENTS;
73 /* Remember handle to the Zip for accessing later. */
74 inLibrary->handle = init->zip;
76 /* Setup prefix, if there is one. */
77 if (init->prefix != NULL)
78 if (sjme_error_is(error = sjme_alloc_strdup(
79 inLibrary->cache.common.allocPool,
80 (sjme_lpstr*)&inLibrary->prefix, init->prefix)))
81 return sjme_error_default(error);
83 /* Success! */
84 return SJME_ERROR_NONE;
87 static sjme_errorCode sjme_rom_zipLibraryResourceStream(
88 sjme_attrInNotNull sjme_rom_library inLibrary,
89 sjme_attrOutNotNull sjme_stream_input* outStream,
90 sjme_attrInNotNull sjme_lpcstr resourceName)
92 sjme_errorCode error;
93 sjme_zip zip;
94 sjme_zip_entry entry;
95 sjme_cchar actualName[SJME_MAX_PATH];
97 if (inLibrary == NULL || outStream == NULL || resourceName == NULL)
98 return SJME_ERROR_NULL_ARGUMENTS;
100 /* Recover zip. */
101 zip = inLibrary->handle;
102 if (zip == NULL)
103 return SJME_ERROR_ILLEGAL_STATE;
105 /* Determine the actual name of the entry. */
106 memset(actualName, 0, sizeof(actualName));
107 if (inLibrary->prefix != NULL)
108 snprintf(actualName, SJME_MAX_PATH - 1, "%s/%s",
109 inLibrary->prefix, resourceName);
110 else
111 snprintf(actualName, SJME_MAX_PATH - 1, "%s/%s",
112 inLibrary->prefix, resourceName);
114 /* Locate the entry. */
115 memset(&entry, 0, sizeof(entry));
116 if (sjme_error_is(error = sjme_zip_locateEntry(zip,
117 &entry, actualName)))
119 /* File not found maps to resource not found. */
120 if (error == SJME_ERROR_FILE_NOT_FOUND)
121 return SJME_ERROR_RESOURCE_NOT_FOUND;
123 return sjme_error_default(error);
126 /* Open input stream over resource. */
127 return sjme_zip_entryRead(&entry, outStream);
130 /** Library functions for Zip access. */
131 static const sjme_rom_libraryFunctions sjme_rom_zipLibraryFunctions =
133 .close = sjme_rom_zipLibraryClose,
134 .init = sjme_rom_zipLibraryInit,
135 .resourceStream = sjme_rom_zipLibraryResourceStream,
138 sjme_errorCode sjme_rom_libraryFromZip(
139 sjme_attrInNotNull sjme_alloc_pool* pool,
140 sjme_attrOutNotNull sjme_rom_library* outLibrary,
141 sjme_attrInNotNull sjme_lpcstr libName,
142 sjme_attrInNullable sjme_lpcstr prefix,
143 sjme_attrInNotNull sjme_zip zip)
145 sjme_errorCode error;
146 sjme_rom_library result;
147 sjme_rom_zipLibraryInitData init;
149 if (pool == NULL || outLibrary == NULL || zip == NULL)
150 return SJME_ERROR_NULL_ARGUMENTS;
152 /* Setup initialization data. */
153 memset(&init, 0, sizeof(init));
154 init.zip = zip;
155 init.prefix = prefix;
157 /* Setup new library. */
158 result = NULL;
159 if (sjme_error_is(error = sjme_rom_libraryNew(pool,
160 &result, libName, &init,
161 &sjme_rom_zipLibraryFunctions, NULL)) ||
162 result == NULL)
163 goto fail_libraryNew;
165 /* Count up Zip, since we are using it now. */
166 if (sjme_error_is(error = sjme_alloc_weakRef(zip, NULL)))
167 goto fail_refUp;
169 /* Success! */
170 *outLibrary = result;
171 return SJME_ERROR_NONE;
173 fail_refUp:
174 fail_libraryNew:
175 return sjme_error_default(error);
178 sjme_errorCode sjme_rom_libraryFromZipMemory(
179 sjme_attrInNotNull sjme_alloc_pool* pool,
180 sjme_attrOutNotNull sjme_rom_library* outLibrary,
181 sjme_attrInNotNull sjme_lpcstr libName,
182 sjme_attrInNotNull sjme_cpointer base,
183 sjme_attrInPositive sjme_jint length)
185 sjme_seekable seekable;
186 sjme_errorCode error;
188 if (pool == NULL || outLibrary == NULL || base == NULL)
189 return SJME_ERROR_NULL_ARGUMENTS;
191 if (length < 0)
192 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
194 /* Get source seekable. */
195 seekable = NULL;
196 if (sjme_error_is(error = sjme_seekable_openMemory(pool,
197 &seekable, (sjme_pointer)base, length)) ||
198 seekable == NULL)
199 return sjme_error_default(error);
201 /* This is just an alias for the other function. */
202 return sjme_rom_libraryFromZipSeekable(pool, outLibrary,
203 libName, seekable);
206 sjme_errorCode sjme_rom_libraryFromZipSeekable(
207 sjme_attrInNotNull sjme_alloc_pool* pool,
208 sjme_attrOutNotNull sjme_rom_library* outLibrary,
209 sjme_attrInNotNull sjme_lpcstr libName,
210 sjme_attrInNotNull sjme_seekable seekable)
212 sjme_errorCode error;
213 sjme_zip zip;
215 if (pool == NULL || outLibrary == NULL || seekable == NULL)
216 return SJME_ERROR_NULL_ARGUMENTS;
218 /* Try opening as a Zip file. */
219 zip = NULL;
220 if (sjme_error_is(error = sjme_zip_openSeekable(pool, &zip,
221 seekable)) || zip == NULL)
222 return sjme_error_default(error);
224 /* Forward Zip loading. */
225 return sjme_rom_libraryFromZip(pool, outLibrary, libName,
226 NULL, zip);