1 | /* |
2 | * SLB support routines for PhysicsFS. |
3 | * |
4 | * This driver handles SLB archives ("slab files"). This uncompressed format |
5 | * is used in I-War / Independence War and Independence War: Defiance. |
6 | * |
7 | * The format begins with four zero bytes (version?), the file count and the |
8 | * location of the table of contents. Each ToC entry contains a 64-byte buffer |
9 | * containing a zero-terminated filename, the offset of the data, and its size. |
10 | * All the filenames begin with the separator character '\'. |
11 | * |
12 | * Please see the file LICENSE.txt in the source's root directory. |
13 | * |
14 | * This file written by Aleksi Nurmi, based on the GRP archiver by |
15 | * Ryan C. Gordon. |
16 | */ |
17 | |
18 | #define __PHYSICSFS_INTERNAL__ |
19 | #include "physfs_internal.h" |
20 | |
21 | #if PHYSFS_SUPPORTS_SLB |
22 | |
23 | static int slbLoadEntries(PHYSFS_Io *io, const PHYSFS_uint32 count, void *arc) |
24 | { |
25 | PHYSFS_uint32 i; |
26 | for (i = 0; i < count; i++) |
27 | { |
28 | PHYSFS_uint32 pos; |
29 | PHYSFS_uint32 size; |
30 | char name[64]; |
31 | char backslash; |
32 | char *ptr; |
33 | |
34 | /* don't include the '\' in the beginning */ |
35 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &backslash, 1), 0); |
36 | BAIL_IF(backslash != '\\', PHYSFS_ERR_CORRUPT, 0); |
37 | |
38 | /* read the rest of the buffer, 63 bytes */ |
39 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, name, 63), 0); |
40 | name[63] = '\0'; /* in case the name lacks the null terminator */ |
41 | |
42 | /* convert backslashes */ |
43 | for (ptr = name; *ptr; ptr++) |
44 | { |
45 | if (*ptr == '\\') |
46 | *ptr = '/'; |
47 | } /* for */ |
48 | |
49 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &pos, 4), 0); |
50 | pos = PHYSFS_swapULE32(pos); |
51 | |
52 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &size, 4), 0); |
53 | size = PHYSFS_swapULE32(size); |
54 | |
55 | BAIL_IF_ERRPASS(!UNPK_addEntry(arc, name, 0, -1, -1, pos, size), 0); |
56 | } /* for */ |
57 | |
58 | return 1; |
59 | } /* slbLoadEntries */ |
60 | |
61 | |
62 | static void *SLB_openArchive(PHYSFS_Io *io, const char *name, |
63 | int forWriting, int *claimed) |
64 | { |
65 | PHYSFS_uint32 version; |
66 | PHYSFS_uint32 count; |
67 | PHYSFS_uint32 tocPos; |
68 | void *unpkarc; |
69 | |
70 | /* There's no identifier on an SLB file, so we assume it's _not_ if the |
71 | file count or tocPos is zero. Beyond that, we'll assume it's |
72 | bogus/corrupt if the entries' filenames don't start with '\' or the |
73 | tocPos is past the end of the file (seek will fail). This probably |
74 | covers all meaningful cases where we would accidentally accept a non-SLB |
75 | file with this archiver. */ |
76 | |
77 | assert(io != NULL); /* shouldn't ever happen. */ |
78 | |
79 | BAIL_IF(forWriting, PHYSFS_ERR_READ_ONLY, NULL); |
80 | |
81 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &version, sizeof (version)), NULL); |
82 | version = PHYSFS_swapULE32(version); |
83 | BAIL_IF(version != 0, PHYSFS_ERR_UNSUPPORTED, NULL); |
84 | |
85 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &count, sizeof (count)), NULL); |
86 | count = PHYSFS_swapULE32(count); |
87 | BAIL_IF(!count, PHYSFS_ERR_UNSUPPORTED, NULL); |
88 | |
89 | /* offset of the table of contents */ |
90 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &tocPos, sizeof (tocPos)), NULL); |
91 | tocPos = PHYSFS_swapULE32(tocPos); |
92 | BAIL_IF(!tocPos, PHYSFS_ERR_UNSUPPORTED, NULL); |
93 | |
94 | /* seek to the table of contents */ |
95 | BAIL_IF_ERRPASS(!io->seek(io, tocPos), NULL); |
96 | |
97 | /* !!! FIXME: check case_sensitive and only_usascii params for this archive. */ |
98 | unpkarc = UNPK_openArchive(io, 1, 0); |
99 | BAIL_IF_ERRPASS(!unpkarc, NULL); |
100 | |
101 | if (!slbLoadEntries(io, count, unpkarc)) |
102 | { |
103 | UNPK_abandonArchive(unpkarc); |
104 | return NULL; |
105 | } /* if */ |
106 | |
107 | *claimed = 1; /* oh well. */ |
108 | |
109 | return unpkarc; |
110 | } /* SLB_openArchive */ |
111 | |
112 | |
113 | const PHYSFS_Archiver __PHYSFS_Archiver_SLB = |
114 | { |
115 | CURRENT_PHYSFS_ARCHIVER_API_VERSION, |
116 | { |
117 | "SLB" , |
118 | "I-War / Independence War Slab file" , |
119 | "Aleksi Nurmi <aleksi.nurmi@gmail.com>" , |
120 | "https://bitbucket.org/ahnurmi/" , |
121 | 0, /* supportsSymlinks */ |
122 | }, |
123 | SLB_openArchive, |
124 | UNPK_enumerate, |
125 | UNPK_openRead, |
126 | UNPK_openWrite, |
127 | UNPK_openAppend, |
128 | UNPK_remove, |
129 | UNPK_mkdir, |
130 | UNPK_stat, |
131 | UNPK_closeArchive |
132 | }; |
133 | |
134 | #endif /* defined PHYSFS_SUPPORTS_SLB */ |
135 | |
136 | /* end of physfs_archiver_slb.c ... */ |
137 | |