physfs_archiver_grp.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  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, int forWriting)
  50. {
  51. PHYSFS_uint8 buf[12];
  52. PHYSFS_uint32 count = 0;
  53. void *unpkarc = NULL;
  54. assert(io != NULL); /* shouldn't ever happen. */
  55. BAIL_IF(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
  56. BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, buf, sizeof (buf)), NULL);
  57. if (memcmp(buf, "KenSilverman", sizeof (buf)) != 0)
  58. BAIL(PHYSFS_ERR_UNSUPPORTED, NULL);
  59. BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &count, sizeof(count)), NULL);
  60. count = PHYSFS_swapULE32(count);
  61. unpkarc = UNPK_openArchive(io);
  62. BAIL_IF_ERRPASS(!unpkarc, NULL);
  63. if (!grpLoadEntries(io, count, unpkarc))
  64. {
  65. UNPK_abandonArchive(unpkarc);
  66. return NULL;
  67. } /* if */
  68. return unpkarc;
  69. } /* GRP_openArchive */
  70. const PHYSFS_Archiver __PHYSFS_Archiver_GRP =
  71. {
  72. CURRENT_PHYSFS_ARCHIVER_API_VERSION,
  73. {
  74. "GRP",
  75. "Build engine Groupfile format",
  76. "Ryan C. Gordon <icculus@icculus.org>",
  77. "https://icculus.org/physfs/",
  78. 0, /* supportsSymlinks */
  79. },
  80. GRP_openArchive,
  81. UNPK_enumerateFiles,
  82. UNPK_openRead,
  83. UNPK_openWrite,
  84. UNPK_openAppend,
  85. UNPK_remove,
  86. UNPK_mkdir,
  87. UNPK_stat,
  88. UNPK_closeArchive
  89. };
  90. #endif /* defined PHYSFS_SUPPORTS_GRP */
  91. /* end of physfs_archiver_grp.c ... */