|
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 zip.c |
|
6 * archiver handles). |
|
7 * |
|
8 * ======================================================================== |
|
9 * |
|
10 * This format info (in more detail) comes from: |
|
11 * 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 UNPKentry *qpakLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 fileCount) |
|
40 { |
|
41 UNPKentry *entries = NULL; |
|
42 UNPKentry *entry = NULL; |
|
43 |
|
44 entries = (UNPKentry *) allocator.Malloc(sizeof (UNPKentry) * fileCount); |
|
45 BAIL_IF_MACRO(entries == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL); |
|
46 |
|
47 for (entry = entries; fileCount > 0; fileCount--, entry++) |
|
48 { |
|
49 if (!__PHYSFS_readAll(io, &entry->name, 56)) goto failed; |
|
50 if (!__PHYSFS_readAll(io, &entry->startPos, 4)) goto failed; |
|
51 if (!__PHYSFS_readAll(io, &entry->size, 4)) goto failed; |
|
52 entry->size = PHYSFS_swapULE32(entry->size); |
|
53 entry->startPos = PHYSFS_swapULE32(entry->startPos); |
|
54 } /* for */ |
|
55 |
|
56 return entries; |
|
57 |
|
58 failed: |
|
59 allocator.Free(entries); |
|
60 return NULL; |
|
61 } /* qpakLoadEntries */ |
|
62 |
|
63 |
|
64 static void *QPAK_openArchive(PHYSFS_Io *io, const char *name, int forWriting) |
|
65 { |
|
66 UNPKentry *entries = NULL; |
|
67 PHYSFS_uint32 val = 0; |
|
68 PHYSFS_uint32 pos = 0; |
|
69 PHYSFS_uint32 count = 0; |
|
70 |
|
71 assert(io != NULL); /* shouldn't ever happen. */ |
|
72 |
|
73 BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL); |
|
74 |
|
75 BAIL_IF_MACRO(!__PHYSFS_readAll(io, &val, 4), ERRPASS, NULL); |
|
76 if (PHYSFS_swapULE32(val) != QPAK_SIG) |
|
77 BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL); |
|
78 |
|
79 BAIL_IF_MACRO(!__PHYSFS_readAll(io, &val, 4), ERRPASS, NULL); |
|
80 pos = PHYSFS_swapULE32(val); /* directory table offset. */ |
|
81 |
|
82 BAIL_IF_MACRO(!__PHYSFS_readAll(io, &val, 4), ERRPASS, NULL); |
|
83 count = PHYSFS_swapULE32(val); |
|
84 |
|
85 /* corrupted archive? */ |
|
86 BAIL_IF_MACRO((count % 64) != 0, PHYSFS_ERR_CORRUPT, NULL); |
|
87 count /= 64; |
|
88 |
|
89 BAIL_IF_MACRO(!io->seek(io, pos), ERRPASS, NULL); |
|
90 |
|
91 entries = qpakLoadEntries(io, count); |
|
92 BAIL_IF_MACRO(!entries, ERRPASS, NULL); |
|
93 return UNPK_openArchive(io, entries, count); |
|
94 } /* QPAK_openArchive */ |
|
95 |
|
96 |
|
97 const PHYSFS_Archiver __PHYSFS_Archiver_QPAK = |
|
98 { |
|
99 { |
|
100 "PAK", |
|
101 "Quake I/II format", |
|
102 "Ryan C. Gordon <icculus@icculus.org>", |
|
103 "http://icculus.org/physfs/", |
|
104 }, |
|
105 QPAK_openArchive, /* openArchive() method */ |
|
106 UNPK_enumerateFiles, /* enumerateFiles() method */ |
|
107 UNPK_openRead, /* openRead() method */ |
|
108 UNPK_openWrite, /* openWrite() method */ |
|
109 UNPK_openAppend, /* openAppend() method */ |
|
110 UNPK_remove, /* remove() method */ |
|
111 UNPK_mkdir, /* mkdir() method */ |
|
112 UNPK_closeArchive, /* closeArchive() method */ |
|
113 UNPK_stat /* stat() method */ |
|
114 }; |
|
115 |
|
116 #endif /* defined PHYSFS_SUPPORTS_QPAK */ |
|
117 |
|
118 /* end of qpak.c ... */ |
|
119 |