archiver_unpacked.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. /*
  2. * High-level PhysicsFS archiver for simple unpacked file formats.
  3. *
  4. * This is a framework that basic archivers build on top of. It's for simple
  5. * formats that can just hand back a list of files and the offsets of their
  6. * uncompressed data. There are an alarming number of formats like this.
  7. *
  8. * RULES: Archive entries must be uncompressed, must not have subdirs,
  9. * must be case insensitive filenames < 32 chars. We can relax some of these
  10. * rules as necessary.
  11. *
  12. * Please see the file LICENSE.txt in the source's root directory.
  13. *
  14. * This file written by Ryan C. Gordon.
  15. */
  16. #define __PHYSICSFS_INTERNAL__
  17. #include "physfs_internal.h"
  18. typedef struct
  19. {
  20. PHYSFS_Io *io;
  21. PHYSFS_uint32 entryCount;
  22. UNPKentry *entries;
  23. } UNPKinfo;
  24. typedef struct
  25. {
  26. PHYSFS_Io *io;
  27. UNPKentry *entry;
  28. PHYSFS_uint32 curPos;
  29. } UNPKfileinfo;
  30. void UNPK_dirClose(dvoid *opaque)
  31. {
  32. UNPKinfo *info = ((UNPKinfo *) opaque);
  33. info->io->destroy(info->io);
  34. allocator.Free(info->entries);
  35. allocator.Free(info);
  36. } /* UNPK_dirClose */
  37. static PHYSFS_sint64 UNPK_read(PHYSFS_Io *io, void *buffer, PHYSFS_uint64 len)
  38. {
  39. UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque;
  40. const UNPKentry *entry = finfo->entry;
  41. const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos);
  42. PHYSFS_sint64 rc;
  43. if (bytesLeft < len)
  44. len = bytesLeft;
  45. rc = finfo->io->read(finfo->io, buffer, len);
  46. if (rc > 0)
  47. finfo->curPos += (PHYSFS_uint32) rc;
  48. return rc;
  49. } /* UNPK_read */
  50. static PHYSFS_sint64 UNPK_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
  51. {
  52. BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
  53. } /* UNPK_write */
  54. static PHYSFS_sint64 UNPK_tell(PHYSFS_Io *io)
  55. {
  56. return ((UNPKfileinfo *) io->opaque)->curPos;
  57. } /* UNPK_tell */
  58. static int UNPK_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
  59. {
  60. UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque;
  61. const UNPKentry *entry = finfo->entry;
  62. int rc;
  63. BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
  64. rc = finfo->io->seek(finfo->io, entry->startPos + offset);
  65. if (rc)
  66. finfo->curPos = (PHYSFS_uint32) offset;
  67. return rc;
  68. } /* UNPK_seek */
  69. static PHYSFS_sint64 UNPK_length(PHYSFS_Io *io)
  70. {
  71. const UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque;
  72. return ((PHYSFS_sint64) finfo->entry->size);
  73. } /* UNPK_length */
  74. static PHYSFS_Io *UNPK_duplicate(PHYSFS_Io *_io)
  75. {
  76. UNPKfileinfo *origfinfo = (UNPKfileinfo *) _io->opaque;
  77. PHYSFS_Io *io = NULL;
  78. PHYSFS_Io *retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
  79. UNPKfileinfo *finfo = (UNPKfileinfo *) allocator.Malloc(sizeof (UNPKfileinfo));
  80. GOTO_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, UNPK_duplicate_failed);
  81. GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, UNPK_duplicate_failed);
  82. io = origfinfo->io->duplicate(origfinfo->io);
  83. GOTO_IF_MACRO(io == NULL, NULL, UNPK_duplicate_failed);
  84. finfo->io = io;
  85. finfo->entry = origfinfo->entry;
  86. finfo->curPos = 0;
  87. memcpy(retval, _io, sizeof (PHYSFS_Io));
  88. retval->opaque = finfo;
  89. return retval;
  90. UNPK_duplicate_failed:
  91. if (finfo != NULL) allocator.Free(finfo);
  92. if (retval != NULL) allocator.Free(retval);
  93. if (io != NULL) io->destroy(io);
  94. return NULL;
  95. } /* UNPK_duplicate */
  96. static int UNPK_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
  97. static void UNPK_destroy(PHYSFS_Io *io)
  98. {
  99. UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque;
  100. finfo->io->destroy(finfo->io);
  101. allocator.Free(finfo);
  102. allocator.Free(io);
  103. } /* UNPK_destroy */
  104. static const PHYSFS_Io UNPK_Io =
  105. {
  106. UNPK_read,
  107. UNPK_write,
  108. UNPK_seek,
  109. UNPK_tell,
  110. UNPK_length,
  111. UNPK_duplicate,
  112. UNPK_flush,
  113. UNPK_destroy,
  114. NULL
  115. };
  116. static int entryCmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
  117. {
  118. if (one != two)
  119. {
  120. const UNPKentry *a = (const UNPKentry *) _a;
  121. return strcmp(a[one].name, a[two].name);
  122. } /* if */
  123. return 0;
  124. } /* entryCmp */
  125. static void entrySwap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
  126. {
  127. if (one != two)
  128. {
  129. UNPKentry tmp;
  130. UNPKentry *first = &(((UNPKentry *) _a)[one]);
  131. UNPKentry *second = &(((UNPKentry *) _a)[two]);
  132. memcpy(&tmp, first, sizeof (UNPKentry));
  133. memcpy(first, second, sizeof (UNPKentry));
  134. memcpy(second, &tmp, sizeof (UNPKentry));
  135. } /* if */
  136. } /* entrySwap */
  137. void UNPK_enumerateFiles(dvoid *opaque, const char *dname,
  138. int omitSymLinks, PHYSFS_EnumFilesCallback cb,
  139. const char *origdir, void *callbackdata)
  140. {
  141. /* no directories in UNPK files. */
  142. if (*dname == '\0')
  143. {
  144. UNPKinfo *info = (UNPKinfo *) opaque;
  145. UNPKentry *entry = info->entries;
  146. PHYSFS_uint32 max = info->entryCount;
  147. PHYSFS_uint32 i;
  148. for (i = 0; i < max; i++, entry++)
  149. cb(callbackdata, origdir, entry->name);
  150. } /* if */
  151. } /* UNPK_enumerateFiles */
  152. static UNPKentry *findEntry(const UNPKinfo *info, const char *name)
  153. {
  154. UNPKentry *a = info->entries;
  155. PHYSFS_sint32 lo = 0;
  156. PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
  157. PHYSFS_sint32 middle;
  158. int rc;
  159. while (lo <= hi)
  160. {
  161. middle = lo + ((hi - lo) / 2);
  162. rc = __PHYSFS_utf8strcasecmp(name, a[middle].name);
  163. if (rc == 0) /* found it! */
  164. return &a[middle];
  165. else if (rc > 0)
  166. lo = middle + 1;
  167. else
  168. hi = middle - 1;
  169. } /* while */
  170. BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
  171. } /* findEntry */
  172. PHYSFS_Io *UNPK_openRead(dvoid *opaque, const char *fnm, int *fileExists)
  173. {
  174. PHYSFS_Io *retval = NULL;
  175. UNPKinfo *info = (UNPKinfo *) opaque;
  176. UNPKfileinfo *finfo = NULL;
  177. UNPKentry *entry;
  178. entry = findEntry(info, fnm);
  179. *fileExists = (entry != NULL);
  180. GOTO_IF_MACRO(entry == NULL, NULL, UNPK_openRead_failed);
  181. retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
  182. GOTO_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, UNPK_openRead_failed);
  183. finfo = (UNPKfileinfo *) allocator.Malloc(sizeof (UNPKfileinfo));
  184. GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, UNPK_openRead_failed);
  185. finfo->io = info->io->duplicate(info->io);
  186. GOTO_IF_MACRO(finfo->io == NULL, NULL, UNPK_openRead_failed);
  187. if (!finfo->io->seek(finfo->io, entry->startPos))
  188. GOTO_MACRO(NULL, UNPK_openRead_failed);
  189. finfo->curPos = 0;
  190. finfo->entry = entry;
  191. memcpy(retval, &UNPK_Io, sizeof (*retval));
  192. retval->opaque = finfo;
  193. return retval;
  194. UNPK_openRead_failed:
  195. if (finfo != NULL)
  196. {
  197. if (finfo->io != NULL)
  198. finfo->io->destroy(finfo->io);
  199. allocator.Free(finfo);
  200. } /* if */
  201. if (retval != NULL)
  202. allocator.Free(retval);
  203. return NULL;
  204. } /* UNPK_openRead */
  205. PHYSFS_Io *UNPK_openWrite(dvoid *opaque, const char *name)
  206. {
  207. BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
  208. } /* UNPK_openWrite */
  209. PHYSFS_Io *UNPK_openAppend(dvoid *opaque, const char *name)
  210. {
  211. BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
  212. } /* UNPK_openAppend */
  213. int UNPK_remove(dvoid *opaque, const char *name)
  214. {
  215. BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
  216. } /* UNPK_remove */
  217. int UNPK_mkdir(dvoid *opaque, const char *name)
  218. {
  219. BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
  220. } /* UNPK_mkdir */
  221. int UNPK_stat(dvoid *opaque, const char *filename, int *exists,
  222. PHYSFS_Stat *stat)
  223. {
  224. const UNPKinfo *info = (const UNPKinfo *) opaque;
  225. const UNPKentry *entry = findEntry(info, filename);
  226. *exists = (entry != 0);
  227. if (!entry)
  228. return 0;
  229. stat->filesize = entry->size;
  230. stat->filetype = PHYSFS_FILETYPE_REGULAR;
  231. stat->modtime = -1;
  232. stat->createtime = -1;
  233. stat->accesstime = -1;
  234. stat->readonly = 1;
  235. return 1;
  236. } /* UNPK_stat */
  237. dvoid *UNPK_openArchive(PHYSFS_Io *io, UNPKentry *e, const PHYSFS_uint32 num)
  238. {
  239. UNPKinfo *info = (UNPKinfo *) allocator.Malloc(sizeof (UNPKinfo));
  240. if (info == NULL)
  241. {
  242. allocator.Free(e);
  243. BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
  244. } /* if */
  245. __PHYSFS_sort(e, num, entryCmp, entrySwap);
  246. info->io = io;
  247. info->entryCount = num;
  248. info->entries = e;
  249. return info;
  250. } /* UNPK_openArchive */
  251. /* end of archiver_unpacked.c ... */