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 if (PHYSFS_init(argv0))
31 PHYSFS_permitSymbolicLinks(1);
40 return PHYSFS_deinit();
43 const char *fs_error(void)
45 return PHYSFS_getLastError();
48 /* -------------------------------------------------------------------------- */
50 const char *fs_base_dir(void)
52 return PHYSFS_getBaseDir();
55 int fs_add_path(const char *path)
57 return PHYSFS_addToSearchPath(path, 0);
60 int fs_set_write_dir(const char *path)
62 return PHYSFS_setWriteDir(path);
65 const char *fs_get_write_dir(void)
67 return PHYSFS_getWriteDir();
70 /* -------------------------------------------------------------------------- */
72 Array fs_dir_scan(const char *path, int (*filter)(struct dir_item *))
74 return dir_scan(path, filter, PHYSFS_enumerateFiles, PHYSFS_freeList);
77 void fs_dir_free(Array items)
82 /* -------------------------------------------------------------------------- */
84 fs_file fs_open(const char *path, const char *mode)
88 assert((mode[0] == 'r' && !mode[1]) ||
89 (mode[0] == 'w' && (!mode[1] || mode[1] == '+')));
91 if ((fh = malloc(sizeof (*fh))))
96 fh->handle = PHYSFS_openRead(path);
100 fh->handle = (mode[1] == '+' ?
101 PHYSFS_openAppend(path) :
102 PHYSFS_openWrite(path));
108 PHYSFS_setBuffer(fh->handle, 0x2000);
120 int fs_close(fs_file fh)
122 if (PHYSFS_close(fh->handle))
130 /* -------------------------------------------------------------------------- */
132 int fs_mkdir(const char *path)
134 return PHYSFS_mkdir(path);
137 int fs_exists(const char *path)
139 return PHYSFS_exists(path);
142 int fs_remove(const char *path)
144 return PHYSFS_delete(path);
147 /* -------------------------------------------------------------------------- */
149 int fs_read(void *data, int size, int count, fs_file fh)
151 return PHYSFS_read(fh->handle, data, size, count);
154 int fs_write(const void *data, int size, int count, fs_file fh)
156 return PHYSFS_write(fh->handle, data, size, count);
159 int fs_flush(fs_file fh)
161 return PHYSFS_flush(fh->handle);
164 long fs_tell(fs_file fh)
166 return PHYSFS_tell(fh->handle);
169 int fs_seek(fs_file fh, long offset, int whence)
171 PHYSFS_uint64 pos = 0;
172 PHYSFS_sint64 cur = PHYSFS_tell(fh->handle);
173 PHYSFS_sint64 len = PHYSFS_fileLength(fh->handle);
194 return PHYSFS_seek(fh->handle, pos);
197 int fs_eof(fs_file fh)
199 return PHYSFS_eof(fh->handle);
202 int fs_length(fs_file fh)
204 return PHYSFS_fileLength(fh->handle);
207 /* -------------------------------------------------------------------------- */
210 * The code below does not use the PhysicsFS API.
213 /* -------------------------------------------------------------------------- */
215 static int cmp_dir_items(const void *A, const void *B)
217 const struct dir_item *a = A, *b = B;
218 return strcmp(a->path, b->path);
221 static int is_archive(struct dir_item *item)
223 return strcmp(item->path + strlen(item->path) - 4, ".zip") == 0;
226 static void add_archives(const char *path)
231 if ((archives = dir_scan(path, is_archive, NULL, NULL)))
233 array_sort(archives, cmp_dir_items);
235 for (i = 0; i < array_len(archives); i++)
236 fs_add_path(DIR_ITEM_GET(archives, i)->path);
242 int fs_add_path_with_archives(const char *path)
245 return fs_add_path(path);
248 /* -------------------------------------------------------------------------- */
250 int fs_rename(const char *src, const char *dst)
252 const char *write_dir;
253 char *real_src, *real_dst;
256 if ((write_dir = fs_get_write_dir()))
258 real_src = concat_string(write_dir, "/", src, NULL);
259 real_dst = concat_string(write_dir, "/", dst, NULL);
261 rc = file_rename(real_src, real_dst);
270 /* -------------------------------------------------------------------------- */
272 int fs_getc(fs_file fh)
276 if (fs_read(&c, 1, 1, fh) != 1)
282 int fs_putc(int c, fs_file fh)
284 unsigned char b = (unsigned char) c;
286 if (fs_write(&b, 1, 1, fh) != 1)
292 int fs_puts(const char *src, fs_file fh)
295 if (fs_putc(*src++, fh) < 0)
301 char *fs_gets(char *dst, int count, fs_file fh)
313 while (count > 1 && (c = fs_getc(fh)) >= 0)
319 /* Normalize possible CRLF and break. */
331 /* Note carriage return. */
344 /* -------------------------------------------------------------------------- */
347 * Write out a multiline string to a file with appropriately converted
348 * linefeed characters.
350 static int write_lines(const char *start, int length, fs_file fh)
353 static const char crlf[] = "\r\n";
355 static const char crlf[] = "\n";
358 int total_written = 0;
364 while (total_written < length)
366 lf = strchr(start, '\n');
368 datalen = lf ? (int) (lf - start) : length - total_written;
369 written = fs_write(start, 1, datalen, fh);
374 total_written += written;
376 if (written < datalen)
381 if (fs_puts(crlf, fh) < 0)
389 return total_written;
392 /* -------------------------------------------------------------------------- */
395 * Trying to avoid defining a feature test macro for every platform by
396 * declaring vsnprintf with the C99 signature. This is probably bad.
402 extern int vsnprintf(char *, size_t, const char *, va_list);
404 int fs_printf(fs_file fh, const char *fmt, ...)
412 len = vsnprintf(NULL, 0, fmt, ap) + 1;
415 if ((buff = malloc(len)))
420 vsnprintf(buff, len, fmt, ap);
424 * HACK. This assumes fs_printf is always called with the
425 * intention of writing text, and not arbitrary data.
428 written = write_lines(buff, strlen(buff), fh);
438 /* -------------------------------------------------------------------------- */
440 void *fs_load(const char *path, int *datalen)
447 if ((fh = fs_open(path, "r")))
449 if ((*datalen = fs_length(fh)) > 0)
451 if ((data = malloc(*datalen)))
453 if (fs_read(data, *datalen, 1, fh) != 1)
468 /* -------------------------------------------------------------------------- */