physfs_archiver_grp.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. /*
  2. * GRP support routines for PhysicsFS.
  3. *
  4. * This driver handles BUILD engine archives ("groupfiles"). This format
  5. * (but not this driver) was put together by Ken Silverman.
  6. *
  7. * The format is simple enough. In Ken's words:
  8. *
  9. * What's the .GRP file format?
  10. *
  11. * The ".grp" file format is just a collection of a lot of files stored
  12. * into 1 big one. I tried to make the format as simple as possible: The
  13. * first 12 bytes contains my name, "KenSilverman". The next 4 bytes is
  14. * the number of files that were compacted into the group file. Then for
  15. * each file, there is a 16 byte structure, where the first 12 bytes are
  16. * the filename, and the last 4 bytes are the file's size. The rest of
  17. * the group file is just the raw data packed one after the other in the
  18. * same order as the list of files.
  19. *
  20. * (That info is from http://www.advsys.net/ken/build.htm ...)
  21. *
  22. * Please see the file LICENSE.txt in the source's root directory.
  23. *
  24. * This file written by Ryan C. Gordon.
  25. */
  26. #define __PHYSICSFS_INTERNAL__
  27. #include "physfs_internal.h"
  28. #if PHYSFS_SUPPORTS_GRP
  29. static int grpLoadEntries(PHYSFS_Io *io, const PHYSFS_uint32 count, void *arc)
  30. {
  31. PHYSFS_uint32 pos = 16 + (16 * count); /* past sig+metadata. */
  32. PHYSFS_uint32 i;
  33. for (i = 0; i < count; i++)
  34. {
  35. char *ptr;
  36. char name[13];
  37. PHYSFS_uint32 size;
  38. BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, name, 12), 0);
  39. BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &size, 4), 0);
  40. name[12] = '\0'; /* name isn't null-terminated in file. */
  41. if ((ptr = strchr(name, ' ')) != NULL)
  42. *ptr = '\0'; /* trim extra spaces. */
  43. size = PHYSFS_swapULE32(size);
  44. BAIL_IF_ERRPASS(!UNPK_addEntry(arc, name, 0, -1, -1, pos, size), 0);
  45. pos += size;
  46. } /* for */
  47. return 1;
  48. } /* grpLoadEntries */
  49. static void *GRP_openArchive(PHYSFS_Io *io, const char *name,
  50. int forWriting, int *claimed)
  51. {
  52. PHYSFS_uint8 buf[12];
  53. PHYSFS_uint32 count = 0;
  54. void *unpkarc = NULL;
  55. assert(io != NULL); /* shouldn't ever happen. */
  56. BAIL_IF(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
  57. BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, buf, sizeof (buf)), NULL);
  58. if (memcmp(buf, "KenSilverman", sizeof (buf)) != 0)
  59. BAIL(PHYSFS_ERR_UNSUPPORTED, NULL);
  60. *claimed = 1;
  61. BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &count, sizeof(count)), NULL);
  62. count = PHYSFS_swapULE32(count);
  63. unpkarc = UNPK_openArchive(io);
  64. BAIL_IF_ERRPASS(!unpkarc, NULL);
  65. if (!grpLoadEntries(io, count, unpkarc))
  66. {
  67. UNPK_abandonArchive(unpkarc);
  68. return NULL;
  69. } /* if */
  70. return unpkarc;
  71. } /* GRP_openArchive */
  72. const PHYSFS_Archiver __PHYSFS_Archiver_GRP =
  73. {
  74. CURRENT_PHYSFS_ARCHIVER_API_VERSION,
  75. {
  76. "GRP",
  77. "Build engine Groupfile format",
  78. "Ryan C. Gordon <icculus@icculus.org>",
  79. "https://icculus.org/physfs/",
  80. 0, /* supportsSymlinks */
  81. },
  82. GRP_openArchive,
  83. UNPK_enumerate,
  84. UNPK_openRead,
  85. UNPK_openWrite,
  86. UNPK_openAppend,
  87. UNPK_remove,
  88. UNPK_mkdir,
  89. UNPK_stat,
  90. UNPK_closeArchive
  91. };
  92. #endif /* defined PHYSFS_SUPPORTS_GRP */
  93. /* end of physfs_archiver_grp.c ... */