Skip to content

Latest commit

 

History

History
323 lines (251 loc) · 8.09 KB

archiver_unpacked.c

File metadata and controls

323 lines (251 loc) · 8.09 KB
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/*
* High-level PhysicsFS archiver for simple unpacked file formats.
*
* This is a framework that basic archivers build on top of. It's for simple
* formats that can just hand back a list of files and the offsets of their
* uncompressed data. There are an alarming number of formats like this.
*
* RULES: Archive entries must be uncompressed, must not have subdirs,
* must be case insensitive filenames < 32 chars. We can relax some of these
* rules as necessary.
*
* Please see the file LICENSE.txt in the source's root directory.
*
* This file written by Ryan C. Gordon.
*/
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
typedef struct
{
PHYSFS_Io *io;
PHYSFS_uint32 entryCount;
UNPKentry *entries;
} UNPKinfo;
typedef struct
{
PHYSFS_Io *io;
UNPKentry *entry;
PHYSFS_uint32 curPos;
} UNPKfileinfo;
void UNPK_dirClose(dvoid *opaque)
{
UNPKinfo *info = ((UNPKinfo *) opaque);
info->io->destroy(info->io);
allocator.Free(info->entries);
allocator.Free(info);
} /* UNPK_dirClose */
static PHYSFS_sint64 UNPK_read(PHYSFS_Io *io, void *buffer, PHYSFS_uint64 len)
{
UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque;
const UNPKentry *entry = finfo->entry;
const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos);
PHYSFS_sint64 rc;
if (bytesLeft < len)
len = bytesLeft;
rc = finfo->io->read(finfo->io, buffer, len);
if (rc > 0)
finfo->curPos += (PHYSFS_uint32) rc;
return rc;
} /* UNPK_read */
static PHYSFS_sint64 UNPK_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
{
Mar 22, 2012
Mar 22, 2012
65
BAIL_MACRO(PHYSFS_ERR_READ_ONLY, -1);
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
} /* UNPK_write */
static PHYSFS_sint64 UNPK_tell(PHYSFS_Io *io)
{
return ((UNPKfileinfo *) io->opaque)->curPos;
} /* UNPK_tell */
static int UNPK_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
{
UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque;
const UNPKentry *entry = finfo->entry;
int rc;
Mar 20, 2012
Mar 20, 2012
81
BAIL_IF_MACRO(offset >= entry->size, PHYSFS_ERR_PAST_EOF, 0);
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
rc = finfo->io->seek(finfo->io, entry->startPos + offset);
if (rc)
finfo->curPos = (PHYSFS_uint32) offset;
return rc;
} /* UNPK_seek */
static PHYSFS_sint64 UNPK_length(PHYSFS_Io *io)
{
const UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque;
return ((PHYSFS_sint64) finfo->entry->size);
} /* UNPK_length */
static PHYSFS_Io *UNPK_duplicate(PHYSFS_Io *_io)
{
UNPKfileinfo *origfinfo = (UNPKfileinfo *) _io->opaque;
PHYSFS_Io *io = NULL;
PHYSFS_Io *retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
UNPKfileinfo *finfo = (UNPKfileinfo *) allocator.Malloc(sizeof (UNPKfileinfo));
Mar 20, 2012
Mar 20, 2012
103
104
GOTO_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, UNPK_duplicate_failed);
GOTO_IF_MACRO(!finfo, PHYSFS_ERR_OUT_OF_MEMORY, UNPK_duplicate_failed);
105
106
io = origfinfo->io->duplicate(origfinfo->io);
Mar 20, 2012
Mar 20, 2012
107
if (!io) goto UNPK_duplicate_failed;
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
finfo->io = io;
finfo->entry = origfinfo->entry;
finfo->curPos = 0;
memcpy(retval, _io, sizeof (PHYSFS_Io));
retval->opaque = finfo;
return retval;
UNPK_duplicate_failed:
if (finfo != NULL) allocator.Free(finfo);
if (retval != NULL) allocator.Free(retval);
if (io != NULL) io->destroy(io);
return NULL;
} /* UNPK_duplicate */
static int UNPK_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
static void UNPK_destroy(PHYSFS_Io *io)
{
UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque;
finfo->io->destroy(finfo->io);
allocator.Free(finfo);
allocator.Free(io);
} /* UNPK_destroy */
static const PHYSFS_Io UNPK_Io =
{
UNPK_read,
UNPK_write,
UNPK_seek,
UNPK_tell,
UNPK_length,
UNPK_duplicate,
UNPK_flush,
UNPK_destroy,
NULL
};
static int entryCmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
{
if (one != two)
{
const UNPKentry *a = (const UNPKentry *) _a;
return strcmp(a[one].name, a[two].name);
} /* if */
return 0;
} /* entryCmp */
static void entrySwap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
{
if (one != two)
{
UNPKentry tmp;
UNPKentry *first = &(((UNPKentry *) _a)[one]);
UNPKentry *second = &(((UNPKentry *) _a)[two]);
memcpy(&tmp, first, sizeof (UNPKentry));
memcpy(first, second, sizeof (UNPKentry));
memcpy(second, &tmp, sizeof (UNPKentry));
} /* if */
} /* entrySwap */
void UNPK_enumerateFiles(dvoid *opaque, const char *dname,
Mar 20, 2012
Mar 20, 2012
174
175
int omitSymLinks, PHYSFS_EnumFilesCallback cb,
const char *origdir, void *callbackdata)
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
{
/* no directories in UNPK files. */
if (*dname == '\0')
{
UNPKinfo *info = (UNPKinfo *) opaque;
UNPKentry *entry = info->entries;
PHYSFS_uint32 max = info->entryCount;
PHYSFS_uint32 i;
for (i = 0; i < max; i++, entry++)
cb(callbackdata, origdir, entry->name);
} /* if */
} /* UNPK_enumerateFiles */
static UNPKentry *findEntry(const UNPKinfo *info, const char *name)
{
UNPKentry *a = info->entries;
PHYSFS_sint32 lo = 0;
PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
PHYSFS_sint32 middle;
int rc;
while (lo <= hi)
{
middle = lo + ((hi - lo) / 2);
Mar 22, 2012
Mar 22, 2012
202
rc = __PHYSFS_utf8stricmp(name, a[middle].name);
203
204
205
206
207
208
209
210
if (rc == 0) /* found it! */
return &a[middle];
else if (rc > 0)
lo = middle + 1;
else
hi = middle - 1;
} /* while */
Mar 20, 2012
Mar 20, 2012
211
BAIL_MACRO(PHYSFS_ERR_NO_SUCH_PATH, NULL);
212
213
214
215
216
217
218
} /* findEntry */
PHYSFS_Io *UNPK_openRead(dvoid *opaque, const char *fnm, int *fileExists)
{
PHYSFS_Io *retval = NULL;
UNPKinfo *info = (UNPKinfo *) opaque;
Oct 18, 2011
Oct 18, 2011
219
UNPKfileinfo *finfo = NULL;
220
221
222
223
UNPKentry *entry;
entry = findEntry(info, fnm);
*fileExists = (entry != NULL);
Mar 20, 2012
Mar 20, 2012
224
GOTO_IF_MACRO(!entry, ERRPASS, UNPK_openRead_failed);
225
226
retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
Mar 20, 2012
Mar 20, 2012
227
GOTO_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, UNPK_openRead_failed);
228
229
finfo = (UNPKfileinfo *) allocator.Malloc(sizeof (UNPKfileinfo));
Mar 20, 2012
Mar 20, 2012
230
GOTO_IF_MACRO(!finfo, PHYSFS_ERR_OUT_OF_MEMORY, UNPK_openRead_failed);
231
232
finfo->io = info->io->duplicate(info->io);
Mar 20, 2012
Mar 20, 2012
233
GOTO_IF_MACRO(!finfo->io, ERRPASS, UNPK_openRead_failed);
234
235
if (!finfo->io->seek(finfo->io, entry->startPos))
Mar 20, 2012
Mar 20, 2012
236
goto UNPK_openRead_failed;
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
finfo->curPos = 0;
finfo->entry = entry;
memcpy(retval, &UNPK_Io, sizeof (*retval));
retval->opaque = finfo;
return retval;
UNPK_openRead_failed:
if (finfo != NULL)
{
if (finfo->io != NULL)
finfo->io->destroy(finfo->io);
allocator.Free(finfo);
} /* if */
if (retval != NULL)
allocator.Free(retval);
return NULL;
} /* UNPK_openRead */
PHYSFS_Io *UNPK_openWrite(dvoid *opaque, const char *name)
{
Mar 22, 2012
Mar 22, 2012
262
BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
263
264
265
266
267
} /* UNPK_openWrite */
PHYSFS_Io *UNPK_openAppend(dvoid *opaque, const char *name)
{
Mar 22, 2012
Mar 22, 2012
268
BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
269
270
271
272
273
} /* UNPK_openAppend */
int UNPK_remove(dvoid *opaque, const char *name)
{
Mar 22, 2012
Mar 22, 2012
274
BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
275
276
277
278
279
} /* UNPK_remove */
int UNPK_mkdir(dvoid *opaque, const char *name)
{
Mar 22, 2012
Mar 22, 2012
280
BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
281
282
283
284
} /* UNPK_mkdir */
int UNPK_stat(dvoid *opaque, const char *filename, int *exists,
Mar 20, 2012
Mar 20, 2012
285
PHYSFS_Stat *stat)
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
{
const UNPKinfo *info = (const UNPKinfo *) opaque;
const UNPKentry *entry = findEntry(info, filename);
*exists = (entry != 0);
if (!entry)
return 0;
stat->filesize = entry->size;
stat->filetype = PHYSFS_FILETYPE_REGULAR;
stat->modtime = -1;
stat->createtime = -1;
stat->accesstime = -1;
stat->readonly = 1;
return 1;
} /* UNPK_stat */
dvoid *UNPK_openArchive(PHYSFS_Io *io, UNPKentry *e, const PHYSFS_uint32 num)
{
UNPKinfo *info = (UNPKinfo *) allocator.Malloc(sizeof (UNPKinfo));
if (info == NULL)
{
allocator.Free(e);
Mar 20, 2012
Mar 20, 2012
311
BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
312
313
314
315
316
317
318
319
320
321
322
} /* if */
__PHYSFS_sort(e, num, entryCmp, entrySwap);
info->io = io;
info->entryCount = num;
info->entries = e;
return info;
} /* UNPK_openArchive */
/* end of archiver_unpacked.c ... */