|
1 /* |
|
2 * HOG support routines for PhysicsFS. |
|
3 * |
|
4 * This driver handles Descent I/II HOG archives. |
|
5 * |
|
6 * The format is very simple: |
|
7 * |
|
8 * The file always starts with the 3-byte signature "DHF" (Descent |
|
9 * HOG file). After that the files of a HOG are just attached after |
|
10 * another, divided by a 17 bytes header, which specifies the name |
|
11 * and length (in bytes) of the forthcoming file! So you just read |
|
12 * the header with its information of how big the following file is, |
|
13 * and then skip exact that number of bytes to get to the next file |
|
14 * in that HOG. |
|
15 * |
|
16 * char sig[3] = {'D', 'H', 'F'}; // "DHF"=Descent HOG File |
|
17 * |
|
18 * struct { |
|
19 * char file_name[13]; // Filename, padded to 13 bytes with 0s |
|
20 * int file_size; // filesize in bytes |
|
21 * char data[file_size]; // The file data |
|
22 * } FILE_STRUCT; // Repeated until the end of the file. |
|
23 * |
|
24 * (That info is from http://www.descent2.com/ddn/specs/hog/) |
|
25 * |
|
26 * Please see the file LICENSE.txt in the source's root directory. |
|
27 * |
|
28 * This file written by Bradley Bell. |
|
29 * Based on grp.c by Ryan C. Gordon. |
|
30 */ |
|
31 |
|
32 #define __PHYSICSFS_INTERNAL__ |
|
33 #include "physfs_internal.h" |
|
34 |
|
35 #if PHYSFS_SUPPORTS_HOG |
|
36 |
|
37 static UNPKentry *hogLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 *_entCount) |
|
38 { |
|
39 const PHYSFS_uint64 iolen = io->length(io); |
|
40 PHYSFS_uint32 entCount = 0; |
|
41 void *ptr = NULL; |
|
42 UNPKentry *entries = NULL; |
|
43 UNPKentry *entry = NULL; |
|
44 PHYSFS_uint32 size = 0; |
|
45 PHYSFS_uint32 pos = 3; |
|
46 |
|
47 while (pos < iolen) |
|
48 { |
|
49 entCount++; |
|
50 ptr = allocator.Realloc(ptr, sizeof (UNPKentry) * entCount); |
|
51 GOTO_IF_MACRO(ptr == NULL, PHYSFS_ERR_OUT_OF_MEMORY, failed); |
|
52 entries = (UNPKentry *) ptr; |
|
53 entry = &entries[entCount-1]; |
|
54 |
|
55 GOTO_IF_MACRO(!__PHYSFS_readAll(io, &entry->name, 13), ERRPASS, failed); |
|
56 pos += 13; |
|
57 GOTO_IF_MACRO(!__PHYSFS_readAll(io, &size, 4), ERRPASS, failed); |
|
58 pos += 4; |
|
59 |
|
60 entry->size = PHYSFS_swapULE32(size); |
|
61 entry->startPos = pos; |
|
62 pos += size; |
|
63 |
|
64 /* skip over entry */ |
|
65 GOTO_IF_MACRO(!io->seek(io, pos), ERRPASS, failed); |
|
66 } /* while */ |
|
67 |
|
68 *_entCount = entCount; |
|
69 return entries; |
|
70 |
|
71 failed: |
|
72 allocator.Free(entries); |
|
73 return NULL; |
|
74 } /* hogLoadEntries */ |
|
75 |
|
76 |
|
77 static void *HOG_openArchive(PHYSFS_Io *io, const char *name, int forWriting) |
|
78 { |
|
79 PHYSFS_uint8 buf[3]; |
|
80 PHYSFS_uint32 count = 0; |
|
81 UNPKentry *entries = NULL; |
|
82 |
|
83 assert(io != NULL); /* shouldn't ever happen. */ |
|
84 BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL); |
|
85 BAIL_IF_MACRO(!__PHYSFS_readAll(io, buf, 3), ERRPASS, NULL); |
|
86 BAIL_IF_MACRO(memcmp(buf, "DHF", 3) != 0, PHYSFS_ERR_UNSUPPORTED, NULL); |
|
87 |
|
88 entries = hogLoadEntries(io, &count); |
|
89 BAIL_IF_MACRO(!entries, ERRPASS, NULL); |
|
90 return UNPK_openArchive(io, entries, count); |
|
91 } /* HOG_openArchive */ |
|
92 |
|
93 |
|
94 const PHYSFS_Archiver __PHYSFS_Archiver_HOG = |
|
95 { |
|
96 { |
|
97 "HOG", |
|
98 "Descent I/II HOG file format", |
|
99 "Bradley Bell <btb@icculus.org>", |
|
100 "http://icculus.org/physfs/", |
|
101 }, |
|
102 HOG_openArchive, /* openArchive() method */ |
|
103 UNPK_enumerateFiles, /* enumerateFiles() method */ |
|
104 UNPK_openRead, /* openRead() method */ |
|
105 UNPK_openWrite, /* openWrite() method */ |
|
106 UNPK_openAppend, /* openAppend() method */ |
|
107 UNPK_remove, /* remove() method */ |
|
108 UNPK_mkdir, /* mkdir() method */ |
|
109 UNPK_closeArchive, /* closeArchive() method */ |
|
110 UNPK_stat /* stat() method */ |
|
111 }; |
|
112 |
|
113 #endif /* defined PHYSFS_SUPPORTS_HOG */ |
|
114 |
|
115 /* end of hog.c ... */ |
|
116 |