🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

127 lines
3.3 KiB

  1. /*
  2. * QPAK support routines for PhysicsFS.
  3. *
  4. * This archiver handles the archive format utilized by Quake 1 and 2.
  5. * Quake3-based games use the PkZip/Info-Zip format (which our
  6. * physfs_archiver_zip.c handles).
  7. *
  8. * ========================================================================
  9. *
  10. * This format info (in more detail) comes from:
  11. * https://web.archive.org/web/20040209101748/http://debian.fmi.uni-sofia.bg/~sergei/cgsr/docs/pak.txt
  12. *
  13. * Quake PAK Format
  14. *
  15. * Header
  16. * (4 bytes) signature = 'PACK'
  17. * (4 bytes) directory offset
  18. * (4 bytes) directory length
  19. *
  20. * Directory
  21. * (56 bytes) file name
  22. * (4 bytes) file position
  23. * (4 bytes) file length
  24. *
  25. * ========================================================================
  26. *
  27. * Please see the file LICENSE.txt in the source's root directory.
  28. *
  29. * This file written by Ryan C. Gordon.
  30. */
  31. #define __PHYSICSFS_INTERNAL__
  32. #include "physfs_internal.h"
  33. #if PHYSFS_SUPPORTS_QPAK
  34. #define QPAK_SIG 0x4B434150 /* "PACK" in ASCII. */
  35. static int qpakLoadEntries(PHYSFS_Io *io, const PHYSFS_uint32 count, void *arc)
  36. {
  37. PHYSFS_uint32 i;
  38. for (i = 0; i < count; i++)
  39. {
  40. PHYSFS_uint32 size;
  41. PHYSFS_uint32 pos;
  42. char name[56];
  43. BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, name, 56), 0);
  44. BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &pos, 4), 0);
  45. BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &size, 4), 0);
  46. size = PHYSFS_swapULE32(size);
  47. pos = PHYSFS_swapULE32(pos);
  48. BAIL_IF_ERRPASS(!UNPK_addEntry(arc, name, 0, -1, -1, pos, size), 0);
  49. } /* for */
  50. return 1;
  51. } /* qpakLoadEntries */
  52. static void *QPAK_openArchive(PHYSFS_Io *io, const char *name,
  53. int forWriting, int *claimed)
  54. {
  55. PHYSFS_uint32 val = 0;
  56. PHYSFS_uint32 pos = 0;
  57. PHYSFS_uint32 count = 0;
  58. void *unpkarc;
  59. assert(io != NULL); /* shouldn't ever happen. */
  60. BAIL_IF(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
  61. BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &val, 4), NULL);
  62. if (PHYSFS_swapULE32(val) != QPAK_SIG)
  63. BAIL(PHYSFS_ERR_UNSUPPORTED, NULL);
  64. *claimed = 1;
  65. BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &val, 4), NULL);
  66. pos = PHYSFS_swapULE32(val); /* directory table offset. */
  67. BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &val, 4), NULL);
  68. count = PHYSFS_swapULE32(val);
  69. /* corrupted archive? */
  70. BAIL_IF((count % 64) != 0, PHYSFS_ERR_CORRUPT, NULL);
  71. count /= 64;
  72. BAIL_IF_ERRPASS(!io->seek(io, pos), NULL);
  73. /* !!! FIXME: check case_sensitive and only_usascii params for this archive. */
  74. unpkarc = UNPK_openArchive(io, 1, 0);
  75. BAIL_IF_ERRPASS(!unpkarc, NULL);
  76. if (!qpakLoadEntries(io, count, unpkarc))
  77. {
  78. UNPK_abandonArchive(unpkarc);
  79. return NULL;
  80. } /* if */
  81. return unpkarc;
  82. } /* QPAK_openArchive */
  83. const PHYSFS_Archiver __PHYSFS_Archiver_QPAK =
  84. {
  85. CURRENT_PHYSFS_ARCHIVER_API_VERSION,
  86. {
  87. "PAK",
  88. "Quake I/II format",
  89. "Ryan C. Gordon <icculus@icculus.org>",
  90. "https://icculus.org/physfs/",
  91. 0, /* supportsSymlinks */
  92. },
  93. QPAK_openArchive,
  94. UNPK_enumerate,
  95. UNPK_openRead,
  96. UNPK_openWrite,
  97. UNPK_openAppend,
  98. UNPK_remove,
  99. UNPK_mkdir,
  100. UNPK_stat,
  101. UNPK_closeArchive
  102. };
  103. #endif /* defined PHYSFS_SUPPORTS_QPAK */
  104. /* end of physfs_archiver_qpak.c ... */