13 * This file implements the virtual file system layer. Most file
14 * system and input/output operations are handled here. There are
15 * basically two groups of functions here: low-level functions
16 * implemented directly using the PhysicsFS 1.0 API and higher-level
17 * functions implemented using the former group.
20 /* -------------------------------------------------------------------------- */
27 int fs_init(const char *argv0)
29 return PHYSFS_init(argv0);
34 return PHYSFS_deinit();
37 /* -------------------------------------------------------------------------- */
39 const char *fs_base_dir(void)
41 return PHYSFS_getBaseDir();
44 int fs_add_path(const char *path)
46 return PHYSFS_addToSearchPath(path, 0);
49 int fs_set_write_dir(const char *path)
51 return PHYSFS_setWriteDir(path);
54 const char *fs_get_write_dir(void)
56 return PHYSFS_getWriteDir();
59 /* -------------------------------------------------------------------------- */
61 Array fs_dir_scan(const char *path, int (*filter)(struct dir_item *))
63 return dir_scan(path, filter, PHYSFS_enumerateFiles, PHYSFS_freeList);
66 void fs_dir_free(Array items)
71 /* -------------------------------------------------------------------------- */
73 fs_file fs_open(const char *path, const char *mode)
77 assert((mode[0] == 'r' && !mode[1]) ||
78 (mode[0] == 'w' && (!mode[1] || mode[1] == '+')));
80 if ((fh = malloc(sizeof (*fh))))
85 fh->handle = PHYSFS_openRead(path);
89 fh->handle = (mode[1] == '+' ?
90 PHYSFS_openAppend(path) :
91 PHYSFS_openWrite(path));
97 PHYSFS_setBuffer(fh->handle, 0x2000);
109 int fs_close(fs_file fh)
111 if (PHYSFS_close(fh->handle))
119 /* -------------------------------------------------------------------------- */
121 int fs_mkdir(const char *path)
123 return PHYSFS_mkdir(path);
126 int fs_exists(const char *path)
128 return PHYSFS_exists(path);
131 int fs_remove(const char *path)
133 return PHYSFS_delete(path);
136 /* -------------------------------------------------------------------------- */
138 int fs_read(void *data, int size, int count, fs_file fh)
140 return PHYSFS_read(fh->handle, data, size, count);
143 int fs_write(const void *data, int size, int count, fs_file fh)
145 return PHYSFS_write(fh->handle, data, size, count);
148 int fs_flush(fs_file fh)
150 return PHYSFS_flush(fh->handle);
153 long fs_tell(fs_file fh)
155 return PHYSFS_tell(fh->handle);
158 int fs_seek(fs_file fh, long offset, int whence)
160 PHYSFS_uint64 pos = 0;
161 PHYSFS_sint64 cur = PHYSFS_tell(fh->handle);
162 PHYSFS_sint64 len = PHYSFS_fileLength(fh->handle);
183 return PHYSFS_seek(fh->handle, pos);
186 int fs_eof(fs_file fh)
188 return PHYSFS_eof(fh->handle);
191 /* -------------------------------------------------------------------------- */
194 * The code below does not use the PhysicsFS API.
197 /* -------------------------------------------------------------------------- */
199 static int cmp_dir_items(const void *A, const void *B)
201 const struct dir_item *a = A, *b = B;
202 return strcmp(a->path, b->path);
205 static int is_archive(struct dir_item *item)
207 return strcmp(item->path + strlen(item->path) - 4, ".zip") == 0;
210 static void add_archives(const char *path)
215 if ((archives = dir_scan(path, is_archive, NULL, NULL)))
217 array_sort(archives, cmp_dir_items);
219 for (i = 0; i < array_len(archives); i++)
220 fs_add_path(DIR_ITEM_GET(archives, i)->path);
226 int fs_add_path_with_archives(const char *path)
229 return fs_add_path(path);
232 /* -------------------------------------------------------------------------- */
234 int fs_rename(const char *src, const char *dst)
236 const char *write_dir;
237 char *real_src, *real_dst;
240 if ((write_dir = fs_get_write_dir()))
242 real_src = concat_string(write_dir, "/", src, NULL);
243 real_dst = concat_string(write_dir, "/", dst, NULL);
245 rc = file_rename(real_src, real_dst);
254 /* -------------------------------------------------------------------------- */
256 int fs_getc(fs_file fh)
260 if (fs_read(&c, 1, 1, fh) != 1)
266 int fs_putc(int c, fs_file fh)
268 unsigned char b = (unsigned char) c;
270 if (fs_write(&b, 1, 1, fh) != 1)
276 int fs_puts(const char *src, fs_file fh)
279 if (fs_putc(*src++, fh) < 0)
285 char *fs_gets(char *dst, int count, fs_file fh)
294 while (count > 1 && (c = fs_getc(fh)) >= 0)
300 /* Normalize possible CRLF and break. */
312 /* Note carriage return. */
323 return c < 0 ? NULL : dst;
326 /* -------------------------------------------------------------------------- */
329 * Write out a multiline string to a file with appropriately converted
330 * linefeed characters.
332 static int write_lines(const char *start, int length, fs_file fh)
335 static const char crlf[] = "\r\n";
337 static const char crlf[] = "\n";
340 int total_written = 0;
346 while (total_written < length)
348 lf = strchr(start, '\n');
350 datalen = lf ? (int) (lf - start) : length - total_written;
351 written = fs_write(start, 1, datalen, fh);
356 total_written += written;
358 if (written < datalen)
363 if (fs_puts(crlf, fh) < 0)
371 return total_written;
374 /* -------------------------------------------------------------------------- */
377 * Trying to avoid defining a feature test macro for every platform by
378 * declaring vsnprintf with the C99 signature. This is probably bad.
384 extern int vsnprintf(char *, size_t, const char *, va_list);
386 int fs_printf(fs_file fh, const char *fmt, ...)
394 len = vsnprintf(NULL, 0, fmt, ap) + 1;
397 if ((buff = malloc(len)))
402 vsnprintf(buff, len, fmt, ap);
406 * HACK. This assumes fs_printf is always called with the
407 * intention of writing text, and not arbitrary data.
410 written = write_lines(buff, strlen(buff), fh);
420 /* -------------------------------------------------------------------------- */