7768
|
1 |
/*
|
|
2 |
* Internal function/structure declaration. Do NOT include in your
|
|
3 |
* application.
|
|
4 |
*
|
|
5 |
* Please see the file LICENSE.txt in the source's root directory.
|
|
6 |
*
|
|
7 |
* This file written by Ryan C. Gordon.
|
|
8 |
*/
|
|
9 |
|
|
10 |
#ifndef _INCLUDE_PHYSFS_INTERNAL_H_
|
|
11 |
#define _INCLUDE_PHYSFS_INTERNAL_H_
|
|
12 |
|
|
13 |
#ifndef __PHYSICSFS_INTERNAL__
|
|
14 |
#error Do not include this header from your applications.
|
|
15 |
#endif
|
|
16 |
|
|
17 |
#include "physfs.h"
|
|
18 |
|
|
19 |
/* The holy trinity. */
|
|
20 |
#include <stdio.h>
|
|
21 |
#include <stdlib.h>
|
|
22 |
#include <string.h>
|
|
23 |
|
|
24 |
#include "physfs_platforms.h"
|
|
25 |
|
|
26 |
#include <assert.h>
|
|
27 |
|
|
28 |
/* !!! FIXME: remove this when revamping stack allocation code... */
|
|
29 |
#if defined(_MSC_VER) || defined(__MINGW32__)
|
|
30 |
#include <malloc.h>
|
|
31 |
#endif
|
|
32 |
|
|
33 |
#if PHYSFS_PLATFORM_SOLARIS
|
|
34 |
#include <alloca.h>
|
|
35 |
#endif
|
|
36 |
|
|
37 |
#ifdef __cplusplus
|
|
38 |
extern "C" {
|
|
39 |
#endif
|
|
40 |
|
|
41 |
#ifdef __GNUC__
|
|
42 |
#define PHYSFS_MINIMUM_GCC_VERSION(major, minor) \
|
|
43 |
( ((__GNUC__ << 16) + __GNUC_MINOR__) >= (((major) << 16) + (minor)) )
|
|
44 |
#else
|
|
45 |
#define PHYSFS_MINIMUM_GCC_VERSION(major, minor) (0)
|
|
46 |
#endif
|
|
47 |
|
|
48 |
#ifdef __cplusplus
|
|
49 |
/* C++ always has a real inline keyword. */
|
|
50 |
#elif (defined macintosh) && !(defined __MWERKS__)
|
|
51 |
# define inline
|
|
52 |
#elif (defined _MSC_VER)
|
|
53 |
# define inline __inline
|
|
54 |
#endif
|
|
55 |
|
|
56 |
#if PHYSFS_PLATFORM_LINUX && !defined(_FILE_OFFSET_BITS)
|
|
57 |
#define _FILE_OFFSET_BITS 64
|
|
58 |
#endif
|
|
59 |
|
|
60 |
/*
|
|
61 |
* Interface for small allocations. If you need a little scratch space for
|
|
62 |
* a throwaway buffer or string, use this. It will make small allocations
|
|
63 |
* on the stack if possible, and use allocator.Malloc() if they are too
|
|
64 |
* large. This helps reduce malloc pressure.
|
|
65 |
* There are some rules, though:
|
|
66 |
* NEVER return a pointer from this, as stack-allocated buffers go away
|
|
67 |
* when your function returns.
|
|
68 |
* NEVER allocate in a loop, as stack-allocated pointers will pile up. Call
|
|
69 |
* a function that uses smallAlloc from your loop, so the allocation can
|
|
70 |
* free each time.
|
|
71 |
* NEVER call smallAlloc with any complex expression (it's a macro that WILL
|
|
72 |
* have side effects...it references the argument multiple times). Use a
|
|
73 |
* variable or a literal.
|
|
74 |
* NEVER free a pointer from this with anything but smallFree. It will not
|
|
75 |
* be a valid pointer to the allocator, regardless of where the memory came
|
|
76 |
* from.
|
|
77 |
* NEVER realloc a pointer from this.
|
|
78 |
* NEVER forget to use smallFree: it may not be a pointer from the stack.
|
|
79 |
* NEVER forget to check for NULL...allocation can fail here, of course!
|
|
80 |
*/
|
|
81 |
#define __PHYSFS_SMALLALLOCTHRESHOLD 256
|
|
82 |
void *__PHYSFS_initSmallAlloc(void *ptr, PHYSFS_uint64 len);
|
|
83 |
|
|
84 |
#define __PHYSFS_smallAlloc(bytes) ( \
|
|
85 |
__PHYSFS_initSmallAlloc( \
|
|
86 |
(((bytes) < __PHYSFS_SMALLALLOCTHRESHOLD) ? \
|
|
87 |
alloca((size_t)((bytes)+sizeof(void*))) : NULL), (bytes)) \
|
|
88 |
)
|
|
89 |
|
|
90 |
void __PHYSFS_smallFree(void *ptr);
|
|
91 |
|
|
92 |
|
|
93 |
/* Use the allocation hooks. */
|
|
94 |
#define malloc(x) Do not use malloc() directly.
|
|
95 |
#define realloc(x, y) Do not use realloc() directly.
|
|
96 |
#define free(x) Do not use free() directly.
|
|
97 |
/* !!! FIXME: add alloca check here. */
|
|
98 |
|
|
99 |
#ifndef PHYSFS_SUPPORTS_ZIP
|
|
100 |
#define PHYSFS_SUPPORTS_ZIP 1
|
|
101 |
#endif
|
|
102 |
#ifndef PHYSFS_SUPPORTS_7Z
|
|
103 |
#define PHYSFS_SUPPORTS_7Z 0
|
|
104 |
#endif
|
|
105 |
#ifndef PHYSFS_SUPPORTS_GRP
|
|
106 |
#define PHYSFS_SUPPORTS_GRP 0
|
|
107 |
#endif
|
|
108 |
#ifndef PHYSFS_SUPPORTS_HOG
|
|
109 |
#define PHYSFS_SUPPORTS_HOG 0
|
|
110 |
#endif
|
|
111 |
#ifndef PHYSFS_SUPPORTS_MVL
|
|
112 |
#define PHYSFS_SUPPORTS_MVL 0
|
|
113 |
#endif
|
|
114 |
#ifndef PHYSFS_SUPPORTS_WAD
|
|
115 |
#define PHYSFS_SUPPORTS_WAD 0
|
|
116 |
#endif
|
|
117 |
#ifndef PHYSFS_SUPPORTS_ISO9660
|
|
118 |
#define PHYSFS_SUPPORTS_ISO9660 0
|
|
119 |
#endif
|
|
120 |
|
|
121 |
/* The latest supported PHYSFS_Io::version value. */
|
|
122 |
#define CURRENT_PHYSFS_IO_API_VERSION 0
|
|
123 |
|
|
124 |
/* Opaque data for file and dir handlers... */
|
|
125 |
typedef void PHYSFS_Dir;
|
|
126 |
|
|
127 |
typedef struct
|
|
128 |
{
|
|
129 |
/*
|
|
130 |
* Basic info about this archiver...
|
|
131 |
*/
|
|
132 |
const PHYSFS_ArchiveInfo info;
|
|
133 |
|
|
134 |
|
|
135 |
/*
|
|
136 |
* DIRECTORY ROUTINES:
|
|
137 |
* These functions are for dir handles. Generate a handle with the
|
|
138 |
* openArchive() method, then pass it as the "opaque" PHYSFS_Dir to the
|
|
139 |
* others.
|
|
140 |
*
|
|
141 |
* Symlinks should always be followed (except in stat()); PhysicsFS will
|
|
142 |
* use the stat() method to check for symlinks and make a judgement on
|
|
143 |
* whether to continue to call other methods based on that.
|
|
144 |
*/
|
|
145 |
|
|
146 |
/*
|
|
147 |
* Open a dirhandle for dir/archive data provided by (io).
|
|
148 |
* (name) is a filename associated with (io), but doesn't necessarily
|
|
149 |
* map to anything, let alone a real filename. This possibly-
|
|
150 |
* meaningless name is in platform-dependent notation.
|
|
151 |
* (forWrite) is non-zero if this is to be used for
|
|
152 |
* the write directory, and zero if this is to be used for an
|
|
153 |
* element of the search path.
|
|
154 |
* Returns NULL on failure. We ignore any error code you set here.
|
|
155 |
* Returns non-NULL on success. The pointer returned will be
|
|
156 |
* passed as the "opaque" parameter for later calls.
|
|
157 |
*/
|
|
158 |
PHYSFS_Dir *(*openArchive)(PHYSFS_Io *io, const char *name, int forWrite);
|
|
159 |
|
|
160 |
/*
|
|
161 |
* List all files in (dirname). Each file is passed to (cb),
|
|
162 |
* where a copy is made if appropriate, so you should dispose of
|
|
163 |
* it properly upon return from the callback.
|
|
164 |
* You should omit symlinks if (omitSymLinks) is non-zero.
|
|
165 |
* If you have a failure, report as much as you can.
|
|
166 |
* (dirname) is in platform-independent notation.
|
|
167 |
*/
|
|
168 |
void (*enumerateFiles)(PHYSFS_Dir *opaque, const char *dirname,
|
|
169 |
int omitSymLinks, PHYSFS_EnumFilesCallback cb,
|
|
170 |
const char *origdir, void *callbackdata);
|
|
171 |
|
|
172 |
/*
|
|
173 |
* Open file for reading.
|
|
174 |
* This filename, (fnm), is in platform-independent notation.
|
|
175 |
* If you can't handle multiple opens of the same file,
|
|
176 |
* you can opt to fail for the second call.
|
|
177 |
* Fail if the file does not exist.
|
|
178 |
* Returns NULL on failure, and calls __PHYSFS_setError().
|
|
179 |
* Returns non-NULL on success. The pointer returned will be
|
|
180 |
* passed as the "opaque" parameter for later file calls.
|
|
181 |
*
|
|
182 |
* Regardless of success or failure, please set *exists to
|
|
183 |
* non-zero if the file existed (even if it's a broken symlink!),
|
|
184 |
* zero if it did not.
|
|
185 |
*/
|
|
186 |
PHYSFS_Io *(*openRead)(PHYSFS_Dir *opaque, const char *fnm, int *exists);
|
|
187 |
|
|
188 |
/*
|
|
189 |
* Open file for writing.
|
|
190 |
* If the file does not exist, it should be created. If it exists,
|
|
191 |
* it should be truncated to zero bytes. The writing
|
|
192 |
* offset should be the start of the file.
|
|
193 |
* This filename is in platform-independent notation.
|
|
194 |
* If you can't handle multiple opens of the same file,
|
|
195 |
* you can opt to fail for the second call.
|
|
196 |
* Returns NULL on failure, and calls __PHYSFS_setError().
|
|
197 |
* Returns non-NULL on success. The pointer returned will be
|
|
198 |
* passed as the "opaque" parameter for later file calls.
|
|
199 |
*/
|
|
200 |
PHYSFS_Io *(*openWrite)(PHYSFS_Dir *opaque, const char *filename);
|
|
201 |
|
|
202 |
/*
|
|
203 |
* Open file for appending.
|
|
204 |
* If the file does not exist, it should be created. The writing
|
|
205 |
* offset should be the end of the file.
|
|
206 |
* This filename is in platform-independent notation.
|
|
207 |
* If you can't handle multiple opens of the same file,
|
|
208 |
* you can opt to fail for the second call.
|
|
209 |
* Returns NULL on failure, and calls __PHYSFS_setError().
|
|
210 |
* Returns non-NULL on success. The pointer returned will be
|
|
211 |
* passed as the "opaque" parameter for later file calls.
|
|
212 |
*/
|
|
213 |
PHYSFS_Io *(*openAppend)(PHYSFS_Dir *opaque, const char *filename);
|
|
214 |
|
|
215 |
/*
|
|
216 |
* Delete a file in the archive/directory.
|
|
217 |
* Return non-zero on success, zero on failure.
|
|
218 |
* This filename is in platform-independent notation.
|
|
219 |
* This method may be NULL.
|
|
220 |
* On failure, call __PHYSFS_setError().
|
|
221 |
*/
|
|
222 |
int (*remove)(PHYSFS_Dir *opaque, const char *filename);
|
|
223 |
|
|
224 |
/*
|
|
225 |
* Create a directory in the archive/directory.
|
|
226 |
* If the application is trying to make multiple dirs, PhysicsFS
|
|
227 |
* will split them up into multiple calls before passing them to
|
|
228 |
* your driver.
|
|
229 |
* Return non-zero on success, zero on failure.
|
|
230 |
* This filename is in platform-independent notation.
|
|
231 |
* This method may be NULL.
|
|
232 |
* On failure, call __PHYSFS_setError().
|
|
233 |
*/
|
|
234 |
int (*mkdir)(PHYSFS_Dir *opaque, const char *filename);
|
|
235 |
|
|
236 |
/*
|
|
237 |
* Close directories/archives, and free any associated memory,
|
|
238 |
* including the original PHYSFS_Io and (opaque) itself, if
|
|
239 |
* applicable. Implementation can assume that it won't be called if
|
|
240 |
* there are still files open from this archive.
|
|
241 |
*/
|
|
242 |
void (*closeArchive)(PHYSFS_Dir *opaque);
|
|
243 |
|
|
244 |
/*
|
|
245 |
* Obtain basic file metadata.
|
|
246 |
* Returns non-zero on success, zero on failure.
|
|
247 |
* On failure, call __PHYSFS_setError().
|
|
248 |
*/
|
|
249 |
int (*stat)(PHYSFS_Dir *opaque, const char *fn,
|
|
250 |
int *exists, PHYSFS_Stat *stat);
|
|
251 |
} PHYSFS_Archiver;
|
|
252 |
|
|
253 |
|
|
254 |
/*
|
|
255 |
* Call this to set the message returned by PHYSFS_getLastError().
|
|
256 |
* Please only use the ERR_* constants above, or add new constants to the
|
|
257 |
* above group, but I want these all in one place.
|
|
258 |
*
|
|
259 |
* Calling this with a NULL argument is a safe no-op.
|
|
260 |
*/
|
|
261 |
void __PHYSFS_setError(const PHYSFS_ErrorCode err);
|
|
262 |
|
|
263 |
|
|
264 |
/* This byteorder stuff was lifted from SDL. http://www.libsdl.org/ */
|
|
265 |
#define PHYSFS_LIL_ENDIAN 1234
|
|
266 |
#define PHYSFS_BIG_ENDIAN 4321
|
|
267 |
|
|
268 |
#if defined(__i386__) || defined(__ia64__) || \
|
|
269 |
defined(_M_IX86) || defined(_M_IA64) || defined(_M_X64) || \
|
|
270 |
(defined(__alpha__) || defined(__alpha)) || \
|
|
271 |
defined(__arm__) || defined(ARM) || \
|
|
272 |
(defined(__mips__) && defined(__MIPSEL__)) || \
|
|
273 |
defined(__SYMBIAN32__) || \
|
|
274 |
defined(__x86_64__) || \
|
|
275 |
defined(__LITTLE_ENDIAN__)
|
|
276 |
#define PHYSFS_BYTEORDER PHYSFS_LIL_ENDIAN
|
|
277 |
#else
|
|
278 |
#define PHYSFS_BYTEORDER PHYSFS_BIG_ENDIAN
|
|
279 |
#endif
|
|
280 |
|
|
281 |
|
|
282 |
/*
|
|
283 |
* When sorting the entries in an archive, we use a modified QuickSort.
|
|
284 |
* When there are less then PHYSFS_QUICKSORT_THRESHOLD entries left to sort,
|
|
285 |
* we switch over to a BubbleSort for the remainder. Tweak to taste.
|
|
286 |
*
|
|
287 |
* You can override this setting by defining PHYSFS_QUICKSORT_THRESHOLD
|
|
288 |
* before #including "physfs_internal.h".
|
|
289 |
*/
|
|
290 |
#ifndef PHYSFS_QUICKSORT_THRESHOLD
|
|
291 |
#define PHYSFS_QUICKSORT_THRESHOLD 4
|
|
292 |
#endif
|
|
293 |
|
|
294 |
/*
|
|
295 |
* Sort an array (or whatever) of (max) elements. This uses a mixture of
|
|
296 |
* a QuickSort and BubbleSort internally.
|
|
297 |
* (cmpfn) is used to determine ordering, and (swapfn) does the actual
|
|
298 |
* swapping of elements in the list.
|
|
299 |
*
|
|
300 |
* See zip.c for an example.
|
|
301 |
*/
|
|
302 |
void __PHYSFS_sort(void *entries, size_t max,
|
|
303 |
int (*cmpfn)(void *, size_t, size_t),
|
|
304 |
void (*swapfn)(void *, size_t, size_t));
|
|
305 |
|
|
306 |
/*
|
|
307 |
* This isn't a formal error code, it's just for BAIL_MACRO.
|
|
308 |
* It means: there was an error, but someone else already set it for us.
|
|
309 |
*/
|
|
310 |
#define ERRPASS PHYSFS_ERR_OK
|
|
311 |
|
|
312 |
/* These get used all over for lessening code clutter. */
|
|
313 |
#define BAIL_MACRO(e, r) do { if (e) __PHYSFS_setError(e); return r; } while (0)
|
|
314 |
#define BAIL_IF_MACRO(c, e, r) do { if (c) { if (e) __PHYSFS_setError(e); return r; } } while (0)
|
|
315 |
#define BAIL_MACRO_MUTEX(e, m, r) do { if (e) __PHYSFS_setError(e); __PHYSFS_platformReleaseMutex(m); return r; } while (0)
|
|
316 |
#define BAIL_IF_MACRO_MUTEX(c, e, m, r) do { if (c) { if (e) __PHYSFS_setError(e); __PHYSFS_platformReleaseMutex(m); return r; } } while (0)
|
|
317 |
#define GOTO_MACRO(e, g) do { if (e) __PHYSFS_setError(e); goto g; } while (0)
|
|
318 |
#define GOTO_IF_MACRO(c, e, g) do { if (c) { if (e) __PHYSFS_setError(e); goto g; } } while (0)
|
|
319 |
#define GOTO_MACRO_MUTEX(e, m, g) do { if (e) __PHYSFS_setError(e); __PHYSFS_platformReleaseMutex(m); goto g; } while (0)
|
|
320 |
#define GOTO_IF_MACRO_MUTEX(c, e, m, g) do { if (c) { if (e) __PHYSFS_setError(e); __PHYSFS_platformReleaseMutex(m); goto g; } } while (0)
|
|
321 |
|
|
322 |
#define __PHYSFS_ARRAYLEN(x) ( (sizeof (x)) / (sizeof (x[0])) )
|
|
323 |
|
|
324 |
#ifdef PHYSFS_NO_64BIT_SUPPORT
|
9188
|
325 |
#define __PHYSFS_SI64(x) ((PHYSFS_sint64) (x))
|
|
326 |
#define __PHYSFS_UI64(x) ((PHYSFS_uint64) (x))
|
7768
|
327 |
#elif (defined __GNUC__)
|
|
328 |
#define __PHYSFS_SI64(x) x##LL
|
|
329 |
#define __PHYSFS_UI64(x) x##ULL
|
|
330 |
#elif (defined _MSC_VER)
|
|
331 |
#define __PHYSFS_SI64(x) x##i64
|
|
332 |
#define __PHYSFS_UI64(x) x##ui64
|
|
333 |
#else
|
|
334 |
#define __PHYSFS_SI64(x) ((PHYSFS_sint64) (x))
|
|
335 |
#define __PHYSFS_UI64(x) ((PHYSFS_uint64) (x))
|
|
336 |
#endif
|
|
337 |
|
|
338 |
|
|
339 |
/*
|
|
340 |
* Check if a ui64 will fit in the platform's address space.
|
|
341 |
* The initial sizeof check will optimize this macro out entirely on
|
|
342 |
* 64-bit (and larger?!) platforms, and the other condition will
|
|
343 |
* return zero or non-zero if the variable will fit in the platform's
|
|
344 |
* size_t, suitable to pass to malloc. This is kinda messy, but effective.
|
|
345 |
*/
|
|
346 |
#define __PHYSFS_ui64FitsAddressSpace(s) ( \
|
|
347 |
(sizeof (PHYSFS_uint64) <= sizeof (size_t)) || \
|
|
348 |
((s) < (__PHYSFS_UI64(0xFFFFFFFFFFFFFFFF) >> (64-(sizeof(size_t)*8)))) \
|
|
349 |
)
|
|
350 |
|
|
351 |
|
|
352 |
/*
|
|
353 |
* This is a strcasecmp() or stricmp() replacement that expects both strings
|
|
354 |
* to be in UTF-8 encoding. It will do "case folding" to decide if the
|
|
355 |
* Unicode codepoints in the strings match.
|
|
356 |
*
|
|
357 |
* It will report which string is "greater than" the other, but be aware that
|
|
358 |
* this doesn't necessarily mean anything: 'a' may be "less than" 'b', but
|
|
359 |
* a random Kanji codepoint has no meaningful alphabetically relationship to
|
|
360 |
* a Greek Lambda, but being able to assign a reliable "value" makes sorting
|
|
361 |
* algorithms possible, if not entirely sane. Most cases should treat the
|
|
362 |
* return value as "equal" or "not equal".
|
|
363 |
*/
|
|
364 |
int __PHYSFS_utf8stricmp(const char *s1, const char *s2);
|
|
365 |
|
|
366 |
/*
|
|
367 |
* This works like __PHYSFS_utf8stricmp(), but takes a character (NOT BYTE
|
|
368 |
* COUNT) argument, like strcasencmp().
|
|
369 |
*/
|
|
370 |
int __PHYSFS_utf8strnicmp(const char *s1, const char *s2, PHYSFS_uint32 l);
|
|
371 |
|
|
372 |
/*
|
|
373 |
* stricmp() that guarantees to only work with low ASCII. The C runtime
|
|
374 |
* stricmp() might try to apply a locale/codepage/etc, which we don't want.
|
|
375 |
*/
|
|
376 |
int __PHYSFS_stricmpASCII(const char *s1, const char *s2);
|
|
377 |
|
|
378 |
/*
|
|
379 |
* strnicmp() that guarantees to only work with low ASCII. The C runtime
|
|
380 |
* strnicmp() might try to apply a locale/codepage/etc, which we don't want.
|
|
381 |
*/
|
|
382 |
int __PHYSFS_strnicmpASCII(const char *s1, const char *s2, PHYSFS_uint32 l);
|
|
383 |
|
|
384 |
|
|
385 |
/*
|
|
386 |
* The current allocator. Not valid before PHYSFS_init is called!
|
|
387 |
*/
|
|
388 |
extern PHYSFS_Allocator __PHYSFS_AllocatorHooks;
|
|
389 |
|
|
390 |
/* convenience macro to make this less cumbersome internally... */
|
|
391 |
#define allocator __PHYSFS_AllocatorHooks
|
|
392 |
|
|
393 |
/*
|
|
394 |
* Create a PHYSFS_Io for a file in the physical filesystem.
|
|
395 |
* This path is in platform-dependent notation. (mode) must be 'r', 'w', or
|
|
396 |
* 'a' for Read, Write, or Append.
|
|
397 |
*/
|
|
398 |
PHYSFS_Io *__PHYSFS_createNativeIo(const char *path, const int mode);
|
|
399 |
|
|
400 |
/*
|
|
401 |
* Create a PHYSFS_Io for a buffer of memory (READ-ONLY). If you already
|
|
402 |
* have one of these, just use its duplicate() method, and it'll increment
|
|
403 |
* its refcount without allocating a copy of the buffer.
|
|
404 |
*/
|
|
405 |
PHYSFS_Io *__PHYSFS_createMemoryIo(const void *buf, PHYSFS_uint64 len,
|
|
406 |
void (*destruct)(void *));
|
|
407 |
|
|
408 |
|
|
409 |
/*
|
|
410 |
* Read (len) bytes from (io) into (buf). Returns non-zero on success,
|
|
411 |
* zero on i/o error. Literally: "return (io->read(io, buf, len) == len);"
|
|
412 |
*/
|
|
413 |
int __PHYSFS_readAll(PHYSFS_Io *io, void *buf, const PHYSFS_uint64 len);
|
|
414 |
|
|
415 |
|
|
416 |
/* These are shared between some archivers. */
|
|
417 |
|
|
418 |
typedef struct
|
|
419 |
{
|
|
420 |
char name[56];
|
|
421 |
PHYSFS_uint32 startPos;
|
|
422 |
PHYSFS_uint32 size;
|
|
423 |
} UNPKentry;
|
|
424 |
|
|
425 |
void UNPK_closeArchive(PHYSFS_Dir *opaque);
|
|
426 |
PHYSFS_Dir *UNPK_openArchive(PHYSFS_Io *io,UNPKentry *e,const PHYSFS_uint32 n);
|
|
427 |
void UNPK_enumerateFiles(PHYSFS_Dir *opaque, const char *dname,
|
|
428 |
int omitSymLinks, PHYSFS_EnumFilesCallback cb,
|
|
429 |
const char *origdir, void *callbackdata);
|
|
430 |
PHYSFS_Io *UNPK_openRead(PHYSFS_Dir *opaque, const char *fnm, int *fileExists);
|
|
431 |
PHYSFS_Io *UNPK_openWrite(PHYSFS_Dir *opaque, const char *name);
|
|
432 |
PHYSFS_Io *UNPK_openAppend(PHYSFS_Dir *opaque, const char *name);
|
|
433 |
int UNPK_remove(PHYSFS_Dir *opaque, const char *name);
|
|
434 |
int UNPK_mkdir(PHYSFS_Dir *opaque, const char *name);
|
|
435 |
int UNPK_stat(PHYSFS_Dir *opaque, const char *fn, int *exist, PHYSFS_Stat *st);
|
|
436 |
|
|
437 |
|
|
438 |
/*--------------------------------------------------------------------------*/
|
|
439 |
/*--------------------------------------------------------------------------*/
|
|
440 |
/*------------ ----------------*/
|
|
441 |
/*------------ You MUST implement the following functions ----------------*/
|
|
442 |
/*------------ if porting to a new platform. ----------------*/
|
|
443 |
/*------------ (see platform/unix.c for an example) ----------------*/
|
|
444 |
/*------------ ----------------*/
|
|
445 |
/*--------------------------------------------------------------------------*/
|
|
446 |
/*--------------------------------------------------------------------------*/
|
|
447 |
|
|
448 |
|
|
449 |
/*
|
|
450 |
* The dir separator; '/' on unix, '\\' on win32, ":" on MacOS, etc...
|
|
451 |
* Obviously, this isn't a function. If you need more than one char for this,
|
|
452 |
* you'll need to pull some old pieces of PhysicsFS out of revision control.
|
|
453 |
*/
|
|
454 |
#if PHYSFS_PLATFORM_WINDOWS
|
|
455 |
#define __PHYSFS_platformDirSeparator '\\'
|
|
456 |
#else
|
|
457 |
#define __PHYSFS_platformDirSeparator '/'
|
|
458 |
#endif
|
|
459 |
|
|
460 |
/*
|
|
461 |
* Initialize the platform. This is called when PHYSFS_init() is called from
|
|
462 |
* the application.
|
|
463 |
*
|
|
464 |
* Return zero if there was a catastrophic failure (which prevents you from
|
|
465 |
* functioning at all), and non-zero otherwise.
|
|
466 |
*/
|
|
467 |
int __PHYSFS_platformInit(void);
|
|
468 |
|
|
469 |
|
|
470 |
/*
|
|
471 |
* Deinitialize the platform. This is called when PHYSFS_deinit() is called
|
|
472 |
* from the application. You can use this to clean up anything you've
|
|
473 |
* allocated in your platform driver.
|
|
474 |
*
|
|
475 |
* Return zero if there was a catastrophic failure (which prevents you from
|
|
476 |
* functioning at all), and non-zero otherwise.
|
|
477 |
*/
|
|
478 |
int __PHYSFS_platformDeinit(void);
|
|
479 |
|
|
480 |
|
|
481 |
/*
|
|
482 |
* Open a file for reading. (filename) is in platform-dependent notation. The
|
|
483 |
* file pointer should be positioned on the first byte of the file.
|
|
484 |
*
|
|
485 |
* The return value will be some platform-specific datatype that is opaque to
|
|
486 |
* the caller; it could be a (FILE *) under Unix, or a (HANDLE *) under win32.
|
|
487 |
*
|
|
488 |
* The same file can be opened for read multiple times, and each should have
|
|
489 |
* a unique file handle; this is frequently employed to prevent race
|
|
490 |
* conditions in the archivers.
|
|
491 |
*
|
|
492 |
* Call __PHYSFS_setError() and return (NULL) if the file can't be opened.
|
|
493 |
*/
|
|
494 |
void *__PHYSFS_platformOpenRead(const char *filename);
|
|
495 |
|
|
496 |
|
|
497 |
/*
|
|
498 |
* Open a file for writing. (filename) is in platform-dependent notation. If
|
|
499 |
* the file exists, it should be truncated to zero bytes, and if it doesn't
|
|
500 |
* exist, it should be created as a zero-byte file. The file pointer should
|
|
501 |
* be positioned on the first byte of the file.
|
|
502 |
*
|
|
503 |
* The return value will be some platform-specific datatype that is opaque to
|
|
504 |
* the caller; it could be a (FILE *) under Unix, or a (HANDLE *) under win32,
|
|
505 |
* etc.
|
|
506 |
*
|
|
507 |
* Opening a file for write multiple times has undefined results.
|
|
508 |
*
|
|
509 |
* Call __PHYSFS_setError() and return (NULL) if the file can't be opened.
|
|
510 |
*/
|
|
511 |
void *__PHYSFS_platformOpenWrite(const char *filename);
|
|
512 |
|
|
513 |
|
|
514 |
/*
|
|
515 |
* Open a file for appending. (filename) is in platform-dependent notation. If
|
|
516 |
* the file exists, the file pointer should be place just past the end of the
|
|
517 |
* file, so that the first write will be one byte after the current end of
|
|
518 |
* the file. If the file doesn't exist, it should be created as a zero-byte
|
|
519 |
* file. The file pointer should be positioned on the first byte of the file.
|
|
520 |
*
|
|
521 |
* The return value will be some platform-specific datatype that is opaque to
|
|
522 |
* the caller; it could be a (FILE *) under Unix, or a (HANDLE *) under win32,
|
|
523 |
* etc.
|
|
524 |
*
|
|
525 |
* Opening a file for append multiple times has undefined results.
|
|
526 |
*
|
|
527 |
* Call __PHYSFS_setError() and return (NULL) if the file can't be opened.
|
|
528 |
*/
|
|
529 |
void *__PHYSFS_platformOpenAppend(const char *filename);
|
|
530 |
|
|
531 |
/*
|
|
532 |
* Read more data from a platform-specific file handle. (opaque) should be
|
|
533 |
* cast to whatever data type your platform uses. Read a maximum of (len)
|
|
534 |
* 8-bit bytes to the area pointed to by (buf). If there isn't enough data
|
|
535 |
* available, return the number of bytes read, and position the file pointer
|
|
536 |
* immediately after those bytes.
|
|
537 |
* On success, return (len) and position the file pointer immediately past
|
|
538 |
* the end of the last read byte. Return (-1) if there is a catastrophic
|
|
539 |
* error, and call __PHYSFS_setError() to describe the problem; the file
|
|
540 |
* pointer should not move in such a case. A partial read is success; only
|
|
541 |
* return (-1) on total failure; presumably, the next read call after a
|
|
542 |
* partial read will fail as such.
|
|
543 |
*/
|
|
544 |
PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buf, PHYSFS_uint64 len);
|
|
545 |
|
|
546 |
/*
|
|
547 |
* Write more data to a platform-specific file handle. (opaque) should be
|
|
548 |
* cast to whatever data type your platform uses. Write a maximum of (len)
|
|
549 |
* 8-bit bytes from the area pointed to by (buffer). If there is a problem,
|
|
550 |
* return the number of bytes written, and position the file pointer
|
|
551 |
* immediately after those bytes. Return (-1) if there is a catastrophic
|
|
552 |
* error, and call __PHYSFS_setError() to describe the problem; the file
|
|
553 |
* pointer should not move in such a case. A partial write is success; only
|
|
554 |
* return (-1) on total failure; presumably, the next write call after a
|
|
555 |
* partial write will fail as such.
|
|
556 |
*/
|
|
557 |
PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
|
|
558 |
PHYSFS_uint64 len);
|
|
559 |
|
|
560 |
/*
|
|
561 |
* Set the file pointer to a new position. (opaque) should be cast to
|
|
562 |
* whatever data type your platform uses. (pos) specifies the number
|
|
563 |
* of 8-bit bytes to seek to from the start of the file. Seeking past the
|
|
564 |
* end of the file is an error condition, and you should check for it.
|
|
565 |
*
|
|
566 |
* Not all file types can seek; this is to be expected by the caller.
|
|
567 |
*
|
|
568 |
* On error, call __PHYSFS_setError() and return zero. On success, return
|
|
569 |
* a non-zero value.
|
|
570 |
*/
|
|
571 |
int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos);
|
|
572 |
|
|
573 |
|
|
574 |
/*
|
|
575 |
* Get the file pointer's position, in an 8-bit byte offset from the start of
|
|
576 |
* the file. (opaque) should be cast to whatever data type your platform
|
|
577 |
* uses.
|
|
578 |
*
|
|
579 |
* Not all file types can "tell"; this is to be expected by the caller.
|
|
580 |
*
|
|
581 |
* On error, call __PHYSFS_setError() and return -1. On success, return >= 0.
|
|
582 |
*/
|
|
583 |
PHYSFS_sint64 __PHYSFS_platformTell(void *opaque);
|
|
584 |
|
|
585 |
|
|
586 |
/*
|
|
587 |
* Determine the current size of a file, in 8-bit bytes, from an open file.
|
|
588 |
*
|
|
589 |
* The caller expects that this information may not be available for all
|
|
590 |
* file types on all platforms.
|
|
591 |
*
|
|
592 |
* Return -1 if you can't do it, and call __PHYSFS_setError(). Otherwise,
|
|
593 |
* return the file length in 8-bit bytes.
|
|
594 |
*/
|
|
595 |
PHYSFS_sint64 __PHYSFS_platformFileLength(void *handle);
|
|
596 |
|
|
597 |
|
|
598 |
/*
|
|
599 |
* !!! FIXME: comment me.
|
|
600 |
*/
|
|
601 |
int __PHYSFS_platformStat(const char *fn, int *exists, PHYSFS_Stat *stat);
|
|
602 |
|
|
603 |
/*
|
|
604 |
* Flush any pending writes to disk. (opaque) should be cast to whatever data
|
|
605 |
* type your platform uses. Be sure to check for errors; the caller expects
|
|
606 |
* that this function can fail if there was a flushing error, etc.
|
|
607 |
*
|
|
608 |
* Return zero on failure, non-zero on success.
|
|
609 |
*/
|
|
610 |
int __PHYSFS_platformFlush(void *opaque);
|
|
611 |
|
|
612 |
/*
|
|
613 |
* Close file and deallocate resources. (opaque) should be cast to whatever
|
|
614 |
* data type your platform uses. This should close the file in any scenario:
|
|
615 |
* flushing is a separate function call, and this function should never fail.
|
|
616 |
*
|
|
617 |
* You should clean up all resources associated with (opaque); the pointer
|
|
618 |
* will be considered invalid after this call.
|
|
619 |
*/
|
|
620 |
void __PHYSFS_platformClose(void *opaque);
|
|
621 |
|
|
622 |
/*
|
|
623 |
* Platform implementation of PHYSFS_getCdRomDirsCallback()...
|
|
624 |
* CD directories are discovered and reported to the callback one at a time.
|
|
625 |
* Pointers passed to the callback are assumed to be invalid to the
|
|
626 |
* application after the callback returns, so you can free them or whatever.
|
|
627 |
* Callback does not assume results will be sorted in any meaningful way.
|
|
628 |
*/
|
|
629 |
void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data);
|
|
630 |
|
|
631 |
/*
|
|
632 |
* Calculate the base dir, if your platform needs special consideration.
|
|
633 |
* Just return NULL if the standard routines will suffice. (see
|
|
634 |
* calculateBaseDir() in physfs.c ...)
|
|
635 |
* Your string must end with a dir separator if you don't return NULL.
|
|
636 |
* Caller will allocator.Free() the retval if it's not NULL.
|
|
637 |
*/
|
|
638 |
char *__PHYSFS_platformCalcBaseDir(const char *argv0);
|
|
639 |
|
|
640 |
/*
|
|
641 |
* Get the platform-specific user dir.
|
|
642 |
* As of PhysicsFS 2.1, returning NULL means fatal error.
|
|
643 |
* Your string must end with a dir separator if you don't return NULL.
|
|
644 |
* Caller will allocator.Free() the retval if it's not NULL.
|
|
645 |
*/
|
|
646 |
char *__PHYSFS_platformCalcUserDir(void);
|
|
647 |
|
|
648 |
|
|
649 |
/* This is the cached version from PHYSFS_init(). This is a fast call. */
|
|
650 |
const char *__PHYSFS_getUserDir(void); /* not deprecated internal version. */
|
|
651 |
|
|
652 |
|
|
653 |
/*
|
|
654 |
* Get the platform-specific pref dir.
|
|
655 |
* Returning NULL means fatal error.
|
|
656 |
* Your string must end with a dir separator if you don't return NULL.
|
|
657 |
* Caller will allocator.Free() the retval if it's not NULL.
|
|
658 |
* Caller will make missing directories if necessary; this just reports
|
|
659 |
* the final path.
|
|
660 |
*/
|
|
661 |
char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app);
|
|
662 |
|
|
663 |
|
|
664 |
/*
|
|
665 |
* Return a pointer that uniquely identifies the current thread.
|
|
666 |
* On a platform without threading, (0x1) will suffice. These numbers are
|
|
667 |
* arbitrary; the only requirement is that no two threads have the same
|
|
668 |
* pointer.
|
|
669 |
*/
|
|
670 |
void *__PHYSFS_platformGetThreadID(void);
|
|
671 |
|
|
672 |
|
|
673 |
/*
|
|
674 |
* Enumerate a directory of files. This follows the rules for the
|
|
675 |
* PHYSFS_Archiver->enumerateFiles() method (see above), except that the
|
|
676 |
* (dirName) that is passed to this function is converted to
|
|
677 |
* platform-DEPENDENT notation by the caller. The PHYSFS_Archiver version
|
|
678 |
* uses platform-independent notation. Note that ".", "..", and other
|
|
679 |
* metaentries should always be ignored.
|
|
680 |
*/
|
|
681 |
void __PHYSFS_platformEnumerateFiles(const char *dirname,
|
|
682 |
int omitSymLinks,
|
|
683 |
PHYSFS_EnumFilesCallback callback,
|
|
684 |
const char *origdir,
|
|
685 |
void *callbackdata);
|
|
686 |
|
|
687 |
/*
|
|
688 |
* Make a directory in the actual filesystem. (path) is specified in
|
|
689 |
* platform-dependent notation. On error, return zero and set the error
|
|
690 |
* message. Return non-zero on success.
|
|
691 |
*/
|
|
692 |
int __PHYSFS_platformMkDir(const char *path);
|
|
693 |
|
|
694 |
|
|
695 |
/*
|
|
696 |
* Remove a file or directory entry in the actual filesystem. (path) is
|
|
697 |
* specified in platform-dependent notation. Note that this deletes files
|
|
698 |
* _and_ directories, so you might need to do some determination.
|
|
699 |
* Non-empty directories should report an error and not delete themselves
|
|
700 |
* or their contents.
|
|
701 |
*
|
|
702 |
* Deleting a symlink should remove the link, not what it points to.
|
|
703 |
*
|
|
704 |
* On error, return zero and set the error message. Return non-zero on success.
|
|
705 |
*/
|
|
706 |
int __PHYSFS_platformDelete(const char *path);
|
|
707 |
|
|
708 |
|
|
709 |
/*
|
|
710 |
* Create a platform-specific mutex. This can be whatever datatype your
|
|
711 |
* platform uses for mutexes, but it is cast to a (void *) for abstractness.
|
|
712 |
*
|
|
713 |
* Return (NULL) if you couldn't create one. Systems without threads can
|
|
714 |
* return any arbitrary non-NULL value.
|
|
715 |
*/
|
|
716 |
void *__PHYSFS_platformCreateMutex(void);
|
|
717 |
|
|
718 |
/*
|
|
719 |
* Destroy a platform-specific mutex, and clean up any resources associated
|
|
720 |
* with it. (mutex) is a value previously returned by
|
|
721 |
* __PHYSFS_platformCreateMutex(). This can be a no-op on single-threaded
|
|
722 |
* platforms.
|
|
723 |
*/
|
|
724 |
void __PHYSFS_platformDestroyMutex(void *mutex);
|
|
725 |
|
|
726 |
/*
|
|
727 |
* Grab possession of a platform-specific mutex. Mutexes should be recursive;
|
|
728 |
* that is, the same thread should be able to call this function multiple
|
|
729 |
* times in a row without causing a deadlock. This function should block
|
|
730 |
* until a thread can gain possession of the mutex.
|
|
731 |
*
|
|
732 |
* Return non-zero if the mutex was grabbed, zero if there was an
|
|
733 |
* unrecoverable problem grabbing it (this should not be a matter of
|
|
734 |
* timing out! We're talking major system errors; block until the mutex
|
|
735 |
* is available otherwise.)
|
|
736 |
*
|
|
737 |
* _DO NOT_ call __PHYSFS_setError() in here! Since setError calls this
|
|
738 |
* function, you'll cause an infinite recursion. This means you can't
|
|
739 |
* use the BAIL_*MACRO* macros, either.
|
|
740 |
*/
|
|
741 |
int __PHYSFS_platformGrabMutex(void *mutex);
|
|
742 |
|
|
743 |
/*
|
|
744 |
* Relinquish possession of the mutex when this method has been called
|
|
745 |
* once for each time that platformGrabMutex was called. Once possession has
|
|
746 |
* been released, the next thread in line to grab the mutex (if any) may
|
|
747 |
* proceed.
|
|
748 |
*
|
|
749 |
* _DO NOT_ call __PHYSFS_setError() in here! Since setError calls this
|
|
750 |
* function, you'll cause an infinite recursion. This means you can't
|
|
751 |
* use the BAIL_*MACRO* macros, either.
|
|
752 |
*/
|
|
753 |
void __PHYSFS_platformReleaseMutex(void *mutex);
|
|
754 |
|
|
755 |
/*
|
|
756 |
* Called at the start of PHYSFS_init() to prepare the allocator, if the user
|
|
757 |
* hasn't selected their own allocator via PHYSFS_setAllocator().
|
|
758 |
* If the platform has a custom allocator, it should fill in the fields of
|
|
759 |
* (a) with the proper function pointers and return non-zero.
|
|
760 |
* If the platform just wants to use malloc()/free()/etc, return zero
|
|
761 |
* immediately and the higher level will handle it. The Init and Deinit
|
|
762 |
* fields of (a) are optional...set them to NULL if you don't need them.
|
|
763 |
* Everything else must be implemented. All rules follow those for
|
|
764 |
* PHYSFS_setAllocator(). If Init isn't NULL, it will be called shortly
|
|
765 |
* after this function returns non-zero.
|
|
766 |
*/
|
|
767 |
int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a);
|
|
768 |
|
|
769 |
#ifdef __cplusplus
|
|
770 |
}
|
|
771 |
#endif
|
|
772 |
|
|
773 |
#endif
|
|
774 |
|
|
775 |
/* end of physfs_internal.h ... */
|
|
776 |
|