physfs.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964
  1. /**
  2. * PhysicsFS; a portable, flexible file i/o abstraction.
  3. *
  4. * Documentation is in physfs.h. It's verbose, honest. :)
  5. *
  6. * Please see the file LICENSE in the source's root directory.
  7. *
  8. * This file written by Ryan C. Gordon.
  9. */
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <assert.h>
  14. #include "physfs.h"
  15. #define __PHYSICSFS_INTERNAL__
  16. #include "physfs_internal.h"
  17. typedef struct __PHYSFS_ERRMSGTYPE__
  18. {
  19. int tid;
  20. int errorAvailable;
  21. char errorString[80];
  22. struct __PHYSFS_ERRMSGTYPE__ *next;
  23. } ErrMsg;
  24. typedef struct __PHYSFS_SEARCHDIRINFO__
  25. {
  26. char *dirName;
  27. DirReader *reader;
  28. struct __PHYSFS_SEARCHDIRINFO__ *next;
  29. } SearchDirInfo;
  30. typedef struct __PHYSFS_FILEHANDLELIST__
  31. {
  32. FileHandle *handle;
  33. struct __PHYSFS_FILEHANDLELIST__ *next;
  34. } FileHandleList;
  35. /* The various i/o drivers... */
  36. #if (defined PHYSFS_SUPPORTS_ZIP)
  37. extern const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_ZIP;
  38. extern const DirFunctions __PHYSFS_DirFunctions_ZIP;
  39. #endif
  40. extern const DirFunctions __PHYSFS_DirFunctions_DIR;
  41. static const PHYSFS_ArchiveInfo *supported_types[] =
  42. {
  43. #if (defined PHYSFS_SUPPORTS_ZIP)
  44. &__PHYSFS_ArchiveInfo_ZIP,
  45. #endif
  46. NULL
  47. };
  48. static const DirFunctions *dirFunctions[] =
  49. {
  50. #if (defined PHYSFS_SUPPORTS_ZIP)
  51. &__PHYSFS_DirFunctions_ZIP,
  52. #endif
  53. &__PHYSFS_DirFunctions_DIR,
  54. NULL
  55. };
  56. /* General PhysicsFS state ... */
  57. static int initialized = 0;
  58. static ErrMsg *errorMessages = NULL;
  59. static SearchDirInfo *searchPath = NULL;
  60. static FileHandleList *openWriteList = NULL;
  61. static FileHandleList *openReadList = NULL;
  62. static char *baseDir = NULL;
  63. static char *userDir = NULL;
  64. static char *writeDir = NULL;
  65. static int allowSymLinks = 0;
  66. /* functions ... */
  67. static ErrMsg *findErrorForCurrentThread(void)
  68. {
  69. ErrMsg *i;
  70. int tid;
  71. if (errorMessages != NULL)
  72. {
  73. tid = __PHYSFS_platformGetThreadID();
  74. for (i = errorMessages; i != NULL; i = i->next)
  75. {
  76. if (i->tid == tid)
  77. return(i);
  78. } /* for */
  79. } /* if */
  80. return(NULL); /* no error available. */
  81. } /* findErrorForCurrentThread */
  82. void __PHYSFS_setError(const char *str)
  83. {
  84. ErrMsg *err = findErrorForCurrentThread();
  85. if (err == NULL)
  86. {
  87. err = (ErrMsg *) malloc(sizeof (ErrMsg));
  88. if (err == NULL)
  89. return; /* uhh...? */
  90. err->tid = __PHYSFS_platformGetThreadID();
  91. err->next = errorMessages;
  92. errorMessages = err;
  93. } /* if */
  94. err->errorAvailable = 1;
  95. strncpy(err->errorString, str, sizeof (err->errorString));
  96. err->errorString[sizeof (err->errorString) - 1] = '\0';
  97. } /* __PHYSFS_setError */
  98. const char *PHYSFS_getLastError(void)
  99. {
  100. ErrMsg *err = findErrorForCurrentThread();
  101. if ((err == NULL) || (!err->errorAvailable))
  102. return(NULL);
  103. err->errorAvailable = 0;
  104. return(err->errorString);
  105. } /* PHYSFS_getLastError */
  106. void PHYSFS_getLinkedVersion(PHYSFS_Version *ver)
  107. {
  108. if (ver != NULL)
  109. {
  110. ver->major = PHYSFS_VER_MAJOR;
  111. ver->minor = PHYSFS_VER_MINOR;
  112. ver->patch = PHYSFS_VER_PATCH;
  113. } /* if */
  114. } /* PHYSFS_getLinkedVersion */
  115. static const char *calculateUserDir(void)
  116. {
  117. char *retval = NULL;
  118. const char *str = NULL;
  119. str = __PHYSFS_platformGetUserDir();
  120. if (str != NULL)
  121. retval = str;
  122. else
  123. {
  124. const char *dirsep = PHYSFS_getDirSeparator();
  125. const char *uname = __PHYSFS_platformGetUserName();
  126. str = (uname != NULL) ? uname : "default";
  127. retval = malloc(strlen(baseDir) + strlen(str) +
  128. (strlen(dirsep) * 2) + 6);
  129. if (retval == NULL)
  130. __PHYSFS_setError(ERR_OUT_OF_MEMORY);
  131. else
  132. sprintf(retval, "%s%susers%s%s", baseDir, dirsep, dirsep, str);
  133. if (uname != NULL)
  134. free(uname);
  135. } /* else */
  136. return(retval);
  137. } /* calculateUserDir */
  138. int PHYSFS_init(const char *argv0)
  139. {
  140. BAIL_IF_MACRO(initialized, ERR_IS_INITIALIZED, 0);
  141. BAIL_IF_MACRO(argv0 == NULL, ERR_INVALID_ARGUMENT, 0);
  142. baseDir = calculateBaseDir(argv0);
  143. if (baseDir == NULL)
  144. return(0);
  145. userDir = calculateUserDir();
  146. if (userDir == NULL)
  147. {
  148. free(baseDir);
  149. baseDir = NULL;
  150. return(0);
  151. } /* if */
  152. initialized = 1;
  153. return(1);
  154. } /* PHYSFS_init */
  155. static void freeSearchDir(SearchDirInfo *sdi)
  156. {
  157. FileHandleList *i;
  158. assert(sdi != NULL);
  159. for (i = openReadList; i != NULL; i = i->next)
  160. {
  161. BAIL_IF_MACRO(i->handle->dirReader == sdi->reader,
  162. ERR_FILES_OPEN_READ, 0);
  163. } /* for */
  164. sdi->reader->close(sdi->reader);
  165. free(sdi->dirName);
  166. free(sdi);
  167. } /* freeSearchDir */
  168. static void closeFileHandleList(FileHandleList **list)
  169. {
  170. FileHandleList *i;
  171. FileHandleList *next = NULL;
  172. for (i = *list; i != NULL; i = next)
  173. {
  174. next = i->next;
  175. i->handle->close(i->handle);
  176. } /* for */
  177. *list = NULL;
  178. } /* closeAllFiles */
  179. static void freeSearchPath(void)
  180. {
  181. SearchDirInfo *i;
  182. SearchDirInfo *next = NULL;
  183. closeFileHandleList(&openReadList);
  184. if (searchPath != NULL)
  185. {
  186. for (i = searchPath; i != NULL; i = next)
  187. {
  188. next = i;
  189. freeSearchDir(i);
  190. } /* for */
  191. searchPath = NULL;
  192. } /* if */
  193. } /* freeSearchPath */
  194. void PHYSFS_deinit(void)
  195. {
  196. BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0);
  197. closeFileHandleList(&openWriteList);
  198. PHYSFS_setWriteDir(NULL);
  199. freeSearchPath();
  200. freeErrorMessages();
  201. if (baseDir != NULL)
  202. {
  203. free(baseDir);
  204. baseDir = NULL;
  205. } /* if */
  206. if (userDir != NULL)
  207. {
  208. free(userDir);
  209. userDir = NULL;
  210. } /* if */
  211. allowSymLinks = 0;
  212. initialized = 0;
  213. return(1);
  214. } /* PHYSFS_deinit */
  215. const PHYSFS_ArchiveInfo **PHYSFS_supportedArchiveTypes(void)
  216. {
  217. return(supported_types);
  218. } /* PHYSFS_supportedArchiveTypes */
  219. void PHYSFS_freeList(void *list)
  220. {
  221. void **i;
  222. for (i = (void **) list; *i != NULL; i++)
  223. free(*i);
  224. free(list);
  225. } /* PHYSFS_freeList */
  226. const char *PHYSFS_getDirSeparator(void)
  227. {
  228. return(__PHYSFS_pathSeparator);
  229. } /* PHYSFS_getDirSeparator */
  230. char **PHYSFS_getCdRomDirs(void)
  231. {
  232. return(__PHYSFS_platformDetectAvailableCDs());
  233. } /* PHYSFS_getCdRomDirs */
  234. const char *PHYSFS_getBaseDir(void)
  235. {
  236. return(baseDir); /* this is calculated in PHYSFS_init()... */
  237. } /* PHYSFS_getBaseDir */
  238. const char *PHYSFS_getUserDir(void)
  239. {
  240. return(userDir); /* this is calculated in PHYSFS_init()... */
  241. } /* PHYSFS_getUserDir */
  242. const char *PHYSFS_getWriteDir(void)
  243. {
  244. return(writeDir);
  245. } /* PHYSFS_getWriteDir */
  246. int PHYSFS_setWriteDir(const char *newDir)
  247. {
  248. BAIL_IF_MACRO(openWriteList != NULL, ERR_FILES_OPEN_WRITE, 0);
  249. if (writeDir != NULL)
  250. {
  251. free(writeDir);
  252. writeDir = NULL;
  253. } /* if */
  254. if (newDir != NULL)
  255. {
  256. BAIL_IF_MACRO(!createDirs_dependent(newDir), ERR_NO_DIR_CREATE, 0);
  257. writeDir = malloc(strlen(newDir) + 1);
  258. BAIL_IF_MACRO(writeDir == NULL, ERR_OUT_OF_MEMORY, 0);
  259. strcpy(writeDir, newDir);
  260. } /* if */
  261. return(1);
  262. } /* PHYSFS_setWriteDir */
  263. static DirReader *getDirReader(const char *d)
  264. {
  265. DirFunctions **i;
  266. for (i = dirFunctions; *i != NULL; i++)
  267. {
  268. if ((*i)->isArchive(d))
  269. return( (*i)->openArchive(d) );
  270. } /* for */
  271. __PHYSFS_setError(ERR_UNSUPPORTED_ARCHIVE);
  272. return(NULL);
  273. } /* getDirReader */
  274. int PHYSFS_addToSearchPath(const char *newDir, int appendToPath)
  275. {
  276. char *str = NULL;
  277. SearchDirInfo *sdi = NULL;
  278. DirReader *dirReader = NULL;
  279. BAIL_IF_MACRO(newDir == NULL, ERR_INVALID_ARGUMENT, 0);
  280. reader = getDirReader(newDir); /* This sets the error message. */
  281. if (reader == NULL)
  282. return(0);
  283. sdi = (SearchDirInfo *) malloc(sizeof (SearchDirInfo));
  284. if (sdi == NULL)
  285. reader->close(reader);
  286. BAIL_IF_MACRO(sdi == NULL, ERR_OUT_OF_MEMORY, 0);
  287. sdi->dirName = (char *) malloc(strlen(newDir) + 1);
  288. if (sdi->dirName == NULL)
  289. {
  290. free(sdi);
  291. reader->close(reader);
  292. __PHYSFS_setError(ERR_OUT_OF_MEMORY);
  293. return(0);
  294. } /* if */
  295. sdi->dirReader = dirReader;
  296. strcpy(sdi->dirName, newDir);
  297. if (appendToPath)
  298. {
  299. sdi->next = searchPath;
  300. searchPath = sdi;
  301. } /* if */
  302. else
  303. {
  304. SearchDirInfo *i = searchPath;
  305. SearchDirInfo *prev = NULL;
  306. sdi->next = NULL;
  307. while (i != NULL)
  308. prev = i;
  309. if (prev == NULL)
  310. searchPath = sdi;
  311. else
  312. prev->next = sdi;
  313. } /* else */
  314. return(1);
  315. } /* PHYSFS_addToSearchPath */
  316. int PHYSFS_removeFromSearchPath(const char *oldDir)
  317. {
  318. SearchDirInfo *i;
  319. SearchDirInfo *prev = NULL;
  320. SearchDirInfo *next = NULL;
  321. BAIL_IF_MACRO(oldDir == NULL, ERR_INVALID_ARGUMENT, 0);
  322. for (i = searchPath; i != NULL; i = i->next)
  323. {
  324. if (strcmp(i->dirName, oldDir) == 0)
  325. {
  326. next = i->next;
  327. if (!freeSearchDir(i))
  328. return(0);
  329. if (prev == NULL)
  330. searchPath = next;
  331. else
  332. prev->next = next;
  333. return(1);
  334. } /* if */
  335. prev = i;
  336. } /* for */
  337. __PHYSFS_setError(ERR_NOT_IN_SEARCH_PATH);
  338. return(0);
  339. } /* PHYSFS_removeFromSearchPath */
  340. char **PHYSFS_getSearchPath(void)
  341. {
  342. int count = 1;
  343. int x;
  344. SearchDirInfo *i;
  345. char **retval;
  346. for (i = searchPath; i != NULL; i = i->next)
  347. count++;
  348. retval = (char **) malloc(sizeof (char *) * count);
  349. BAIL_IF_MACRO(!retval, ERR_OUT_OF_MEMORY, NULL);
  350. count--;
  351. retval[count] = NULL;
  352. for (i = searchPath, x = 0; x < count; i = i->next, x++)
  353. {
  354. retval[x] = (char *) malloc(strlen(i->dirName) + 1);
  355. if (retval[x] == NULL) /* this is friggin' ugly. */
  356. {
  357. while (x > 0)
  358. {
  359. x--;
  360. free(retval[x]);
  361. } /* while */
  362. free(retval);
  363. __PHYSFS_setError(ERR_OUT_OF_MEMORY);
  364. return(NULL);
  365. } /* if */
  366. strcpy(retval[x], i->dirName);
  367. } /* for */
  368. return(retval);
  369. } /* PHYSFS_getSearchPath */
  370. int PHYSFS_setSaneConfig(const char *appName, const char *archiveExt,
  371. int includeCdRoms, int archivesFirst)
  372. {
  373. const char *basedir = PHYSFS_getBaseDir();
  374. const char *userdir = PHYSFS_getUserDir();
  375. const char *dirsep = PHYSFS_getDirSeparator();
  376. char *str;
  377. int rc;
  378. /* set write dir... */
  379. str = malloc(strlen(userdir) + (strlen(appName) * 2) +
  380. (strlen(dirsep) * 2) + 2);
  381. BAIL_IF_MACRO(str == NULL, ERR_OUT_OF_MEMORY, 0);
  382. sprintf(str, "%s%s.%s", userdir, dirsep, appName);
  383. rc = PHYSFS_setWriteDir(str);
  384. if (!rc)
  385. return(0); /* error set by PHYSFS_setWriteDir() ... */
  386. /* Put write dir related dirs on search path... */
  387. PHYSFS_addToSearchPath(str, 1);
  388. PHYSFS_mkdir(appName); /* don't care if this fails. */
  389. strcat(str, dirSep);
  390. strcat(str, appName);
  391. PHYSFS_addToSearchPath(str, 1);
  392. free(str);
  393. /* Put base path stuff on search path... */
  394. PHYSFS_addToSearchPath(basedir, 1);
  395. str = malloc(strlen(basedir) + (strlen(appName) * 2) +
  396. (strlen(dirsep) * 2) + 2);
  397. if (str != NULL)
  398. {
  399. sprintf(str, "%s%s.%s", basedir, dirsep, appName);
  400. PHYSFS_addToSearchPath(str, 1);
  401. free(str);
  402. } /* if */
  403. /* handle CD-ROMs... */
  404. if (includeCdRoms)
  405. {
  406. char **cds = PHYSFS_getCdRomDirs();
  407. char **i;
  408. for (i = cds; *i != NULL; i++)
  409. {
  410. PHYSFS_addToSearchPath(*i);
  411. str = malloc(strlen(*i) + strlen(appName) + strlen(dirsep) + 1);
  412. if (str != NULL)
  413. {
  414. sprintf(str, "%s%s%s", *i, dirsep, appName);
  415. PHYSFS_addToSearchPath(str);
  416. free(str);
  417. } /* if */
  418. } /* for */
  419. PHYSFS_freeList(cds);
  420. } /* if */
  421. /* Root out archives, and add them to search path... */
  422. if (archiveExt != NULL)
  423. {
  424. char **rc = PHYSFS_enumerateFiles("");
  425. char **i;
  426. int extlen = strlen(archiveExt);
  427. char *ext;
  428. for (i = rc; *i != NULL; i++)
  429. {
  430. int l = strlen(*i);
  431. if ((l > extlen) && ((*i)[l - extlen - 1] == '.'));
  432. {
  433. ext = (*i) + (l - extlen);
  434. if (__PHYSFS_platformStricmp(ext, archiveExt) == 0)
  435. {
  436. const char *d = PHYSFS_getRealDir(*i);
  437. str = malloc(strlen(d) + strlen(dirsep) + l + 1);
  438. if (str != NULL)
  439. {
  440. sprintf(str, "%s%s%s", d, dirsep, *i);
  441. PHYSFS_addToSearchPath(d, str);
  442. free(str);
  443. } /* if */
  444. } /* if */
  445. } /* if */
  446. } /* for */
  447. PHYSFS_freeList(rc);
  448. } /* if */
  449. return(1);
  450. } /* PHYSFS_setSaneConfig */
  451. /* string manipulation in C makes my ass itch. */
  452. /* be sure to free this crap after you're done with it. */
  453. static char *convertToDependentNotation(const char *prepend,
  454. const char *dirName,
  455. const char *append)
  456. {
  457. const char *dirsep = PHYSFS_getDirSeparator();
  458. int sepsize = strlen(dirsep);
  459. char *str;
  460. char *i1;
  461. char *i2;
  462. size_t allocSize;
  463. allocSize = strlen(dirName) + strlen(writeDir) + sepsize + 1;
  464. if (prepend != NULL)
  465. allocSize += strlen(prepend) + sepsize;
  466. if (append != NULL)
  467. allocSize += strlen(append) + sepsize;
  468. /* make sure there's enough space if the dir separator is bigger. */
  469. if (sepsize > 1)
  470. {
  471. for (str = dirName; *str != '\0'; str++)
  472. {
  473. if (*str == '/')
  474. allocSize += (sepsize - 1);
  475. } /* for */
  476. } /* if */
  477. str = (char *) malloc(allocSize);
  478. BAIL_IF_MACRO(str == NULL, ERR_OUT_OF_MEMORY, NULL);
  479. *str = '\0';
  480. if (prepend)
  481. {
  482. strcpy(str, prepend);
  483. strcat(str, dirsep);
  484. } /* if */
  485. for (i1 = dirName, i2 = str + strlen(str); *i1 != '\0'; i1++, i2++)
  486. {
  487. if (*i1 == '/')
  488. {
  489. strcpy(i2, dirsep);
  490. i2 += sepsize;
  491. } /* if */
  492. else
  493. {
  494. *i2 = *i1;
  495. } /* else */
  496. } /* for */
  497. *i2 = '\0';
  498. if (append)
  499. {
  500. strcat(str, dirsep);
  501. strcpy(str, append);
  502. } /* if */
  503. return(str);
  504. } /* convertToDependentNotation */
  505. int PHYSFS_mkdir(const char *dirName)
  506. {
  507. char *str;
  508. int rc;
  509. BAIL_IF_MACRO(writeDir == NULL, ERR_NO_WRITE_DIR, NULL);
  510. str = convertToDependentNotation(writeDir, dirName, NULL);
  511. if (str == NULL) /* __PHYSFS_setError is called in convert call. */
  512. return(0);
  513. rc = createDirs_dependent(str);
  514. free(str);
  515. return(rc);
  516. } /* PHYSFS_mkdir */
  517. int PHYSFS_delete(const char *filename)
  518. {
  519. char *str;
  520. int rc;
  521. BAIL_IF_MACRO(writeDir == NULL, ERR_NO_WRITE_DIR, NULL);
  522. str = convertToDependentNotation(writeDir, fileName, NULL);
  523. if (str == NULL) /* __PHYSFS_setError is called in convert call. */
  524. return(0);
  525. rc = remove(str);
  526. free(str);
  527. rc = (rc == 0);
  528. if (!rc)
  529. __PHYSFS_setError(strerror(errno));
  530. return(rc);
  531. } /* PHYSFS_delete */
  532. void PHYSFS_permitSymbolicLinks(int allow)
  533. {
  534. allowSymLinks = allow;
  535. } /* PHYSFS_permitSymbolicLinks */
  536. /**
  537. * Figure out where in the search path a file resides. The file is specified
  538. * in platform-independent notation. The returned filename will be the
  539. * element of the search path where the file was found, which may be a
  540. * directory, or an archive. Even if there are multiple matches in different
  541. * parts of the search path, only the first one found is used, just like
  542. * when opening a file.
  543. *
  544. * So, if you look for "maps/level1.map", and C:\mygame is in your search
  545. * path and C:\mygame\maps\level1.map exists, then "C:\mygame" is returned.
  546. *
  547. * If a match is a symbolic link, and you've not explicitly permitted symlinks,
  548. * then it will be ignored, and the search for a match will continue.
  549. *
  550. * @param filename file to look for.
  551. * @return READ ONLY string of element of search path containing the
  552. * the file in question. NULL if not found.
  553. */
  554. const char *PHYSFS_getRealDir(const char *filename)
  555. {
  556. } /* PHYSFS_getRealDir */
  557. static void countList(LinkedStringList *list)
  558. {
  559. int retval = 0;
  560. LinkedStringList *i;
  561. assert(list != NULL);
  562. for (i = list; i != NULL; i = i->next)
  563. retval++;
  564. return(retval);
  565. } /* countList */
  566. static char **convertStringListToPhysFSList(LinkedStringList *finalList)
  567. {
  568. int i;
  569. LinkedStringList *next = NULL;
  570. int len = countList(finalList);
  571. char **retval = (char **) malloc((len + 1) * sizeof (char *));
  572. if (retval == NULL)
  573. __PHYSFS_setError(ERR_OUT_OF_MEMORY);
  574. for (i = 0; i < len; i++)
  575. {
  576. next = finalList->next;
  577. if (retval == NULL)
  578. free(finalList->str);
  579. else
  580. retval[i] = finalList->str;
  581. free(finalList);
  582. finalList = next;
  583. } /* for */
  584. if (retval != NULL);
  585. retval[i] = NULL;
  586. return(retval);
  587. } /* convertStringListToPhysFSList */
  588. static void insertStringListItem(LinkedStringList **final,
  589. LinkedStringList *item)
  590. {
  591. LinkedStringList *i;
  592. LinkedStringList *prev = NULL;
  593. int rc;
  594. for (i = *final; i != NULL; i = i->next)
  595. {
  596. rc = strcmp(i->str, item->str);
  597. if (rc == 0) /* already in list. */
  598. {
  599. free(item->str);
  600. free(item);
  601. return;
  602. } /* if */
  603. else if (rc > 0) /* insertion point. */
  604. {
  605. if (prev == NULL)
  606. *final = item;
  607. else
  608. prev->next = item;
  609. item->next = i;
  610. return;
  611. } /* else if */
  612. prev = i;
  613. } /* for */
  614. } /* insertStringListItem */
  615. /* if we run out of memory anywhere in here, we give back what we can. */
  616. static void interpolateStringLists(LinkedStringList **final,
  617. LinkedStringList *newList)
  618. {
  619. LinkedStringList *next = NULL;
  620. while (newList != NULL)
  621. {
  622. next = newList->next;
  623. insertStringListItem(final, newList);
  624. newList = next;
  625. } /* while */
  626. } /* interpolateStringLists */
  627. char **PHYSFS_enumerateFiles(const char *path)
  628. {
  629. SearchDirInfo *i;
  630. char **retval = NULL;
  631. LinkedStringList *rc;
  632. LinkedStringList *finalList = NULL;
  633. for (i = searchPath; i != NULL; i = i->next)
  634. {
  635. assert(i->reader->funcs->enumerateFiles != NULL);
  636. rc = i->reader->funcs->enumerateFiles(path);
  637. interpolateStringLists(&finalList, rc);
  638. } /* for */
  639. retval = convertStringListToPhysFSList(finalList);
  640. return(retval);
  641. } /* PHYSFS_enumerateFiles */
  642. /**
  643. * Open a file for writing, in platform-independent notation and in relation
  644. * to the write path as the root of the writable filesystem. The specified
  645. * file is created if it doesn't exist. If it does exist, it is truncated to
  646. * zero bytes, and the writing offset is set to the start.
  647. *
  648. * @param filename File to open.
  649. * @return A valid PhysicsFS filehandle on success, NULL on error. Specifics
  650. * of the error can be gleaned from PHYSFS_getLastError().
  651. */
  652. PHYSFS_file *PHYSFS_openWrite(const char *filename)
  653. {
  654. } /* PHYSFS_openWrite */
  655. /**
  656. * Open a file for writing, in platform-independent notation and in relation
  657. * to the write path as the root of the writable filesystem. The specified
  658. * file is created if it doesn't exist. If it does exist, the writing offset
  659. * is set to the end of the file, so the first write will be the byte after
  660. * the end.
  661. *
  662. * @param filename File to open.
  663. * @return A valid PhysicsFS filehandle on success, NULL on error. Specifics
  664. * of the error can be gleaned from PHYSFS_getLastError().
  665. */
  666. PHYSFS_file *PHYSFS_openAppend(const char *filename)
  667. {
  668. } /* PHYSFS_openAppend */
  669. /**
  670. * Open a file for reading, in platform-independent notation. The search path
  671. * is checked one at a time until a matching file is found, in which case an
  672. * abstract filehandle is associated with it, and reading may be done.
  673. * The reading offset is set to the first byte of the file.
  674. *
  675. * @param filename File to open.
  676. * @return A valid PhysicsFS filehandle on success, NULL on error. Specifics
  677. * of the error can be gleaned from PHYSFS_getLastError().
  678. */
  679. PHYSFS_file *PHYSFS_openRead(const char *filename)
  680. {
  681. } /* PHYSFS_openRead */
  682. /**
  683. * Close a PhysicsFS filehandle. This call is capable of failing if the
  684. * operating system was buffering writes to this file, and (now forced to
  685. * write those changes to physical media) can not store the data for any
  686. * reason. In such a case, the filehandle stays open. A well-written program
  687. * should ALWAYS check the return value from the close call in addition to
  688. * every writing call!
  689. *
  690. * @param handle handle returned from PHYSFS_open*().
  691. * @return nonzero on success, zero on error. Specifics of the error can be
  692. * gleaned from PHYSFS_getLastError().
  693. */
  694. int PHYSFS_close(PHYSFS_file *handle)
  695. {
  696. FileHandle *h = (FileHandle *) handle->opaque;
  697. FileHandleList *i;
  698. FileHandleList **lists[] = { &openWriteList, &openReadList, NULL };
  699. int rc;
  700. assert(h != NULL);
  701. assert(h->funcs != NULL);
  702. assert(h->funcs->close != NULL);
  703. while (lists != NULL)
  704. {
  705. for (i = *(*lists); i != NULL; i = i->next)
  706. {
  707. if (i->handle == h)
  708. {
  709. rc = h->close(h);
  710. if (!rc)
  711. return(0);
  712. if (prev == NULL)
  713. *lists = i->next;
  714. else
  715. prev->next = i->next;
  716. free(i);
  717. free(handle);
  718. return(1);
  719. } /* if */
  720. } /* for */
  721. lists++;
  722. } /* while */
  723. assert(0); /* shouldn't EVER hit this. */
  724. } /* PHYSFS_close */
  725. int PHYSFS_read(PHYSFS_file *handle, void *buffer,
  726. unsigned int objSize, unsigned int objCount)
  727. {
  728. FileHandle *h = (FileHandle *) handle->opaque;
  729. assert(h != NULL);
  730. assert(h->funcs != NULL);
  731. BAIL_IF_MACRO(h->funcs->read == NULL, ERR_NOT_SUPPORTED, -1);
  732. return(h->funcs->read(h, buffer, objSize, objCount));
  733. } /* PHYSFS_read */
  734. int PHYSFS_write(PHYSFS_file *handle, void *buffer,
  735. unsigned int objSize, unsigned int objCount)
  736. {
  737. FileHandle *h = (FileHandle *) handle->opaque;
  738. assert(h != NULL);
  739. assert(h->funcs != NULL);
  740. BAIL_IF_MACRO(h->funcs->write == NULL, ERR_NOT_SUPPORTED, -1);
  741. return(h->funcs->write(h, buffer, objSize, objCount));
  742. } /* PHYSFS_write */
  743. int PHYSFS_eof(PHYSFS_file *handle)
  744. {
  745. FileHandle *h = (FileHandle *) handle->opaque;
  746. assert(h != NULL);
  747. assert(h->funcs != NULL);
  748. BAIL_IF_MACRO(h->funcs->eof == NULL, ERR_NOT_SUPPORTED, -1);
  749. return(h->funcs->eof(h));
  750. } /* PHYSFS_eof */
  751. int PHYSFS_tell(PHYSFS_file *handle)
  752. {
  753. FileHandle *h = (FileHandle *) handle->opaque;
  754. assert(h != NULL);
  755. assert(h->funcs != NULL);
  756. BAIL_IF_MACRO(h->funcs->tell == NULL, ERR_NOT_SUPPORTED, -1);
  757. return(h->funcs->tell(h));
  758. } /* PHYSFS_tell */
  759. int PHYSFS_seek(PHYSFS_file *handle, int pos)
  760. {
  761. FileHandle *h = (FileHandle *) handle->opaque;
  762. assert(h != NULL);
  763. assert(h->funcs != NULL);
  764. BAIL_IF_MACRO(h->funcs->seek == NULL, ERR_NOT_SUPPORTED, 0);
  765. return(h->funcs->seek(h, pos));
  766. } /* PHYSFS_seek */
  767. /* end of physfs.c ... */