|
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 |
|
325 #define __PHYSFS_SI64(x) ((PHYSFS_sint64) (x)) |
|
326 #define __PHYSFS_UI64(x) ((PHYSFS_uint64) (x)) |
|
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 |