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 | |
32 | #define __PHYSICSFS_INTERNAL__ |
33 | #include "physfs_internal.h" |
34 | |
35 | #if PHYSFS_SUPPORTS_QPAK |
36 | |
37 | #define QPAK_SIG 0x4B434150 /* "PACK" in ASCII. */ |
38 | |
39 | static int qpakLoadEntries(PHYSFS_Io *io, const PHYSFS_uint32 count, void *arc) |
40 | { |
41 | PHYSFS_uint32 i; |
42 | for (i = 0; i < count; i++) |
43 | { |
44 | PHYSFS_uint32 size; |
45 | PHYSFS_uint32 pos; |
46 | char name[56]; |
47 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, name, 56), 0); |
48 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &pos, 4), 0); |
49 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &size, 4), 0); |
50 | size = PHYSFS_swapULE32(size); |
51 | pos = PHYSFS_swapULE32(pos); |
52 | BAIL_IF_ERRPASS(!UNPK_addEntry(arc, name, 0, -1, -1, pos, size), 0); |
53 | } /* for */ |
54 | |
55 | return 1; |
56 | } /* qpakLoadEntries */ |
57 | |
58 | |
59 | static void *QPAK_openArchive(PHYSFS_Io *io, const char *name, |
60 | int forWriting, int *claimed) |
61 | { |
62 | PHYSFS_uint32 val = 0; |
63 | PHYSFS_uint32 pos = 0; |
64 | PHYSFS_uint32 count = 0; |
65 | void *unpkarc; |
66 | |
67 | assert(io != NULL); /* shouldn't ever happen. */ |
68 | |
69 | BAIL_IF(forWriting, PHYSFS_ERR_READ_ONLY, NULL); |
70 | |
71 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &val, 4), NULL); |
72 | if (PHYSFS_swapULE32(val) != QPAK_SIG) |
73 | BAIL(PHYSFS_ERR_UNSUPPORTED, NULL); |
74 | |
75 | *claimed = 1; |
76 | |
77 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &val, 4), NULL); |
78 | pos = PHYSFS_swapULE32(val); /* directory table offset. */ |
79 | |
80 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &val, 4), NULL); |
81 | count = PHYSFS_swapULE32(val); |
82 | |
83 | /* corrupted archive? */ |
84 | BAIL_IF((count % 64) != 0, PHYSFS_ERR_CORRUPT, NULL); |
85 | count /= 64; |
86 | |
87 | BAIL_IF_ERRPASS(!io->seek(io, pos), NULL); |
88 | |
89 | /* !!! FIXME: check case_sensitive and only_usascii params for this archive. */ |
90 | unpkarc = UNPK_openArchive(io, 1, 0); |
91 | BAIL_IF_ERRPASS(!unpkarc, NULL); |
92 | |
93 | if (!qpakLoadEntries(io, count, unpkarc)) |
94 | { |
95 | UNPK_abandonArchive(unpkarc); |
96 | return NULL; |
97 | } /* if */ |
98 | |
99 | return unpkarc; |
100 | } /* QPAK_openArchive */ |
101 | |
102 | |
103 | const PHYSFS_Archiver __PHYSFS_Archiver_QPAK = |
104 | { |
105 | CURRENT_PHYSFS_ARCHIVER_API_VERSION, |
106 | { |
107 | "PAK" , |
108 | "Quake I/II format" , |
109 | "Ryan C. Gordon <icculus@icculus.org>" , |
110 | "https://icculus.org/physfs/" , |
111 | 0, /* supportsSymlinks */ |
112 | }, |
113 | QPAK_openArchive, |
114 | UNPK_enumerate, |
115 | UNPK_openRead, |
116 | UNPK_openWrite, |
117 | UNPK_openAppend, |
118 | UNPK_remove, |
119 | UNPK_mkdir, |
120 | UNPK_stat, |
121 | UNPK_closeArchive |
122 | }; |
123 | |
124 | #endif /* defined PHYSFS_SUPPORTS_QPAK */ |
125 | |
126 | /* end of physfs_archiver_qpak.c ... */ |
127 | |
128 | |