Skip to content

Latest commit

 

History

History
477 lines (374 loc) · 12.4 KB

archiver_hog.c

File metadata and controls

477 lines (374 loc) · 12.4 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
/*
* HOG support routines for PhysicsFS.
*
* This driver handles Descent I/II HOG archives.
*
* The format is very simple:
*
* The file always starts with the 3-byte signature "DHF" (Descent
* HOG file). After that the files of a HOG are just attached after
* another, divided by a 17 bytes header, which specifies the name
* and length (in bytes) of the forthcoming file! So you just read
* the header with its information of how big the following file is,
* and then skip exact that number of bytes to get to the next file
* in that HOG.
*
* char sig[3] = {'D', 'H', 'F'}; // "DHF"=Descent HOG File
*
* struct {
* char file_name[13]; // Filename, padded to 13 bytes with 0s
* int file_size; // filesize in bytes
* char data[file_size]; // The file data
* } FILE_STRUCT; // Repeated until the end of the file.
*
* (That info is from http://www.descent2.com/ddn/specs/hog/)
*
Mar 11, 2007
Mar 11, 2007
26
* Please see the file LICENSE.txt in the source's root directory.
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
*
* This file written by Bradley Bell.
* Based on grp.c by Ryan C. Gordon.
*/
#if (defined PHYSFS_SUPPORTS_HOG)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "physfs.h"
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
/*
* One HOGentry is kept for each file in an open HOG archive.
*/
typedef struct
{
char name[13];
PHYSFS_uint32 startPos;
PHYSFS_uint32 size;
} HOGentry;
/*
* One HOGinfo is kept for each open HOG archive.
*/
typedef struct
{
Aug 30, 2010
Aug 30, 2010
57
PHYSFS_Io *io;
58
59
60
61
62
63
64
65
66
PHYSFS_uint32 entryCount;
HOGentry *entries;
} HOGinfo;
/*
* One HOGfileinfo is kept for each open file in a HOG archive.
*/
typedef struct
{
Aug 30, 2010
Aug 30, 2010
67
PHYSFS_Io *io;
68
69
70
71
72
HOGentry *entry;
PHYSFS_uint32 curPos;
} HOGfileinfo;
Aug 30, 2010
Aug 30, 2010
73
static inline int readAll(PHYSFS_Io *io, void *buf, const PHYSFS_uint64 len)
Aug 21, 2010
Aug 21, 2010
74
{
Aug 30, 2010
Aug 30, 2010
75
return (io->read(io, buf, len) == len);
Aug 21, 2010
Aug 21, 2010
76
77
78
} /* readAll */
Sep 26, 2004
Sep 26, 2004
79
static void HOG_dirClose(dvoid *opaque)
Sep 26, 2004
Sep 26, 2004
81
HOGinfo *info = ((HOGinfo *) opaque);
Aug 30, 2010
Aug 30, 2010
82
info->io->destroy(info->io);
Mar 14, 2005
Mar 14, 2005
83
84
allocator.Free(info->entries);
allocator.Free(info);
85
86
87
} /* HOG_dirClose */
Aug 30, 2010
Aug 30, 2010
88
static PHYSFS_sint64 HOG_read(PHYSFS_Io *io, void *buffer, PHYSFS_uint64 len)
Aug 30, 2010
Aug 30, 2010
90
HOGfileinfo *finfo = (HOGfileinfo *) io->opaque;
Aug 21, 2010
Aug 21, 2010
91
92
const HOGentry *entry = finfo->entry;
const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos);
93
94
PHYSFS_sint64 rc;
Aug 21, 2010
Aug 21, 2010
95
96
if (bytesLeft < len)
len = bytesLeft;
Aug 30, 2010
Aug 30, 2010
98
rc = finfo->io->read(finfo->io, buffer, len);
Aug 21, 2010
Aug 21, 2010
100
finfo->curPos += (PHYSFS_uint32) rc;
Jan 28, 2010
Jan 28, 2010
102
return rc;
103
104
105
} /* HOG_read */
Aug 30, 2010
Aug 30, 2010
106
static PHYSFS_sint64 HOG_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
107
108
109
110
111
{
BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
} /* HOG_write */
Aug 30, 2010
Aug 30, 2010
112
static PHYSFS_sint64 HOG_tell(PHYSFS_Io *io)
Aug 30, 2010
Aug 30, 2010
114
return ((HOGfileinfo *) io->opaque)->curPos;
115
116
117
} /* HOG_tell */
Aug 30, 2010
Aug 30, 2010
118
static int HOG_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
Aug 30, 2010
Aug 30, 2010
120
121
HOGfileinfo *finfo = (HOGfileinfo *) io->opaque;
const HOGentry *entry = finfo->entry;
122
123
124
int rc;
BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
Aug 30, 2010
Aug 30, 2010
125
rc = finfo->io->seek(finfo->io, entry->startPos + offset);
126
127
128
if (rc)
finfo->curPos = (PHYSFS_uint32) offset;
Jan 28, 2010
Jan 28, 2010
129
return rc;
130
131
132
} /* HOG_seek */
Aug 30, 2010
Aug 30, 2010
133
static PHYSFS_sint64 HOG_length(PHYSFS_Io *io)
Aug 30, 2010
Aug 30, 2010
135
const HOGfileinfo *finfo = (HOGfileinfo *) io->opaque;
Jan 28, 2010
Jan 28, 2010
136
return ((PHYSFS_sint64) finfo->entry->size);
Aug 30, 2010
Aug 30, 2010
137
} /* HOG_length */
Aug 30, 2010
Aug 30, 2010
140
static PHYSFS_Io *HOG_duplicate(PHYSFS_Io *_io)
Aug 30, 2010
Aug 30, 2010
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
HOGfileinfo *origfinfo = (HOGfileinfo *) _io->opaque;
PHYSFS_Io *io = NULL;
PHYSFS_Io *retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
HOGfileinfo *finfo = (HOGfileinfo *) allocator.Malloc(sizeof (HOGfileinfo));
GOTO_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, HOG_duplicate_failed);
GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, HOG_duplicate_failed);
io = origfinfo->io->duplicate(origfinfo->io);
GOTO_IF_MACRO(io == NULL, NULL, HOG_duplicate_failed);
finfo->io = io;
finfo->entry = origfinfo->entry;
finfo->curPos = 0;
memcpy(retval, _io, sizeof (PHYSFS_Io));
retval->opaque = finfo;
return retval;
HOG_duplicate_failed:
if (finfo != NULL) allocator.Free(finfo);
if (retval != NULL) allocator.Free(retval);
if (io != NULL) io->destroy(io);
return NULL;
} /* HOG_duplicate */
Aug 30, 2010
Aug 30, 2010
165
static int HOG_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
Aug 30, 2010
Aug 30, 2010
167
static void HOG_destroy(PHYSFS_Io *io)
Aug 30, 2010
Aug 30, 2010
169
170
171
172
173
HOGfileinfo *finfo = (HOGfileinfo *) io->opaque;
finfo->io->destroy(finfo->io);
allocator.Free(finfo);
allocator.Free(io);
} /* HOG_destroy */
Aug 30, 2010
Aug 30, 2010
176
177
178
179
180
181
182
183
184
185
186
187
static const PHYSFS_Io HOG_Io =
{
HOG_read,
HOG_write,
HOG_seek,
HOG_tell,
HOG_length,
HOG_duplicate,
HOG_flush,
HOG_destroy,
NULL
};
Aug 30, 2010
Aug 30, 2010
191
static int hogEntryCmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
Feb 20, 2008
Feb 20, 2008
193
194
195
if (one != two)
{
const HOGentry *a = (const HOGentry *) _a;
Jan 28, 2010
Jan 28, 2010
196
return __PHYSFS_stricmpASCII(a[one].name, a[two].name);
Feb 20, 2008
Feb 20, 2008
197
198
199
} /* if */
return 0;
Aug 30, 2010
Aug 30, 2010
200
} /* hogEntryCmp */
Aug 30, 2010
Aug 30, 2010
203
static void hogEntrySwap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
Feb 20, 2008
Feb 20, 2008
205
206
207
208
209
210
211
212
213
if (one != two)
{
HOGentry tmp;
HOGentry *first = &(((HOGentry *) _a)[one]);
HOGentry *second = &(((HOGentry *) _a)[two]);
memcpy(&tmp, first, sizeof (HOGentry));
memcpy(first, second, sizeof (HOGentry));
memcpy(second, &tmp, sizeof (HOGentry));
} /* if */
Aug 30, 2010
Aug 30, 2010
214
} /* hogEntrySwap */
Aug 30, 2010
Aug 30, 2010
217
static int hog_load_entries(PHYSFS_Io *io, HOGinfo *info)
Aug 30, 2010
Aug 30, 2010
219
220
221
222
223
224
225
226
const PHYSFS_uint64 iolen = io->length(io);
PHYSFS_uint32 entCount = 0;
void *ptr = NULL;
HOGentry *entry = NULL;
PHYSFS_uint32 size = 0;
PHYSFS_uint32 pos = 3;
while (pos < iolen)
Aug 30, 2010
Aug 30, 2010
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
entCount++;
ptr = allocator.Realloc(ptr, sizeof (HOGentry) * entCount);
BAIL_IF_MACRO(ptr == NULL, ERR_OUT_OF_MEMORY, 0);
info->entries = (HOGentry *) ptr;
entry = &info->entries[entCount-1];
BAIL_IF_MACRO(!readAll(io, &entry->name, 13), NULL, 0);
pos += 13;
BAIL_IF_MACRO(!readAll(io, &size, 4), NULL, 0);
pos += 4;
entry->size = PHYSFS_swapULE32(size);
entry->startPos = pos;
pos += size;
BAIL_IF_MACRO(!io->seek(io, pos), NULL, 0); /* skip over entry */
Aug 30, 2010
Aug 30, 2010
246
info->entryCount = entCount;
Aug 30, 2010
Aug 30, 2010
248
__PHYSFS_sort(info->entries, entCount, hogEntryCmp, hogEntrySwap);
Jan 28, 2010
Jan 28, 2010
249
return 1;
250
251
252
} /* hog_load_entries */
Aug 30, 2010
Aug 30, 2010
253
static void *HOG_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
Aug 30, 2010
Aug 30, 2010
255
256
PHYSFS_uint8 buf[3];
HOGinfo *info = NULL;
Aug 30, 2010
Aug 30, 2010
258
assert(io != NULL); /* shouldn't ever happen. */
Aug 30, 2010
Aug 30, 2010
260
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
Aug 30, 2010
Aug 30, 2010
262
263
264
265
266
267
268
269
270
271
BAIL_IF_MACRO(!readAll(io, buf, 3), NULL, 0);
if (memcmp(buf, "DHF", 3) != 0)
GOTO_MACRO(ERR_NOT_AN_ARCHIVE, HOG_openArchive_failed);
info = (HOGinfo *) allocator.Malloc(sizeof (HOGinfo));
GOTO_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, HOG_openArchive_failed);
memset(info, '\0', sizeof (HOGinfo));
info->io = io;
GOTO_IF_MACRO(!hog_load_entries(io, info), NULL, HOG_openArchive_failed);
Sep 26, 2004
Sep 26, 2004
272
Jan 28, 2010
Jan 28, 2010
273
return info;
274
275
HOG_openArchive_failed:
Sep 26, 2004
Sep 26, 2004
276
if (info != NULL)
Sep 26, 2004
Sep 26, 2004
278
if (info->entries != NULL)
Mar 14, 2005
Mar 14, 2005
279
280
allocator.Free(info->entries);
allocator.Free(info);
Jan 28, 2010
Jan 28, 2010
283
return NULL;
284
285
286
} /* HOG_openArchive */
Sep 29, 2004
Sep 29, 2004
287
static void HOG_enumerateFiles(dvoid *opaque, const char *dname,
Sep 18, 2005
Sep 18, 2005
288
289
int omitSymLinks, PHYSFS_EnumFilesCallback cb,
const char *origdir, void *callbackdata)
290
291
{
/* no directories in HOG files. */
Mar 28, 2007
Mar 28, 2007
292
if (*dname == '\0')
Sep 29, 2004
Sep 29, 2004
293
294
295
296
297
{
HOGinfo *info = (HOGinfo *) opaque;
HOGentry *entry = info->entries;
PHYSFS_uint32 max = info->entryCount;
PHYSFS_uint32 i;
Sep 29, 2004
Sep 29, 2004
299
for (i = 0; i < max; i++, entry++)
Sep 18, 2005
Sep 18, 2005
300
cb(callbackdata, origdir, entry->name);
Sep 29, 2004
Sep 29, 2004
301
} /* if */
302
303
304
} /* HOG_enumerateFiles */
Feb 15, 2010
Feb 15, 2010
305
static HOGentry *hog_find_entry(const HOGinfo *info, const char *name)
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
{
char *ptr = strchr(name, '.');
HOGentry *a = info->entries;
PHYSFS_sint32 lo = 0;
PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
PHYSFS_sint32 middle;
int rc;
/*
* Rule out filenames to avoid unneeded processing...no dirs,
* big filenames, or extensions > 3 chars.
*/
BAIL_IF_MACRO((ptr) && (strlen(ptr) > 4), ERR_NO_SUCH_FILE, NULL);
BAIL_IF_MACRO(strlen(name) > 12, ERR_NO_SUCH_FILE, NULL);
BAIL_IF_MACRO(strchr(name, '/') != NULL, ERR_NO_SUCH_FILE, NULL);
while (lo <= hi)
{
middle = lo + ((hi - lo) / 2);
Mar 15, 2007
Mar 15, 2007
325
rc = __PHYSFS_stricmpASCII(name, a[middle].name);
326
if (rc == 0) /* found it! */
Jan 28, 2010
Jan 28, 2010
327
return &a[middle];
328
329
330
331
332
333
334
335
336
337
else if (rc > 0)
lo = middle + 1;
else
hi = middle - 1;
} /* while */
BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
} /* hog_find_entry */
Sep 26, 2004
Sep 26, 2004
338
static int HOG_exists(dvoid *opaque, const char *name)
Aug 30, 2010
Aug 30, 2010
340
return (hog_find_entry((HOGinfo *) opaque, name) != NULL);
341
342
343
} /* HOG_exists */
Sep 26, 2004
Sep 26, 2004
344
static int HOG_isDirectory(dvoid *opaque, const char *name, int *fileExists)
Sep 26, 2004
Sep 26, 2004
346
*fileExists = HOG_exists(opaque, name);
Jan 28, 2010
Jan 28, 2010
347
return 0; /* never directories in a groupfile. */
348
349
350
} /* HOG_isDirectory */
Sep 26, 2004
Sep 26, 2004
351
static int HOG_isSymLink(dvoid *opaque, const char *name, int *fileExists)
Sep 26, 2004
Sep 26, 2004
353
*fileExists = HOG_exists(opaque, name);
Jan 28, 2010
Jan 28, 2010
354
return 0; /* never symlinks in a groupfile. */
355
356
357
} /* HOG_isSymLink */
Aug 30, 2010
Aug 30, 2010
358
static PHYSFS_Io *HOG_openRead(dvoid *opaque, const char *fnm, int *fileExists)
Aug 30, 2010
Aug 30, 2010
360
361
PHYSFS_Io *retval = NULL;
HOGinfo *info = (HOGinfo *) opaque;
362
363
364
365
366
HOGfileinfo *finfo;
HOGentry *entry;
entry = hog_find_entry(info, fnm);
*fileExists = (entry != NULL);
Aug 30, 2010
Aug 30, 2010
367
368
369
370
GOTO_IF_MACRO(entry == NULL, NULL, HOG_openRead_failed);
retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
GOTO_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, HOG_openRead_failed);
Mar 14, 2005
Mar 14, 2005
372
finfo = (HOGfileinfo *) allocator.Malloc(sizeof (HOGfileinfo));
Aug 30, 2010
Aug 30, 2010
373
374
375
376
GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, HOG_openRead_failed);
finfo->io = info->io->duplicate(info->io);
GOTO_IF_MACRO(finfo->io == NULL, NULL, HOG_openRead_failed);
Aug 30, 2010
Aug 30, 2010
378
379
380
381
382
383
384
385
386
387
388
389
if (!finfo->io->seek(finfo->io, entry->startPos))
GOTO_MACRO(NULL, HOG_openRead_failed);
finfo->curPos = 0;
finfo->entry = entry;
memcpy(retval, &HOG_Io, sizeof (*retval));
retval->opaque = finfo;
return retval;
HOG_openRead_failed:
if (finfo != NULL)
Aug 30, 2010
Aug 30, 2010
391
392
if (finfo->io != NULL)
finfo->io->destroy(finfo->io);
Mar 14, 2005
Mar 14, 2005
393
allocator.Free(finfo);
Aug 30, 2010
Aug 30, 2010
396
397
398
399
if (retval != NULL)
allocator.Free(retval);
return NULL;
400
401
402
} /* HOG_openRead */
Aug 30, 2010
Aug 30, 2010
403
static PHYSFS_Io *HOG_openWrite(dvoid *opaque, const char *name)
404
405
406
407
408
{
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* HOG_openWrite */
Aug 30, 2010
Aug 30, 2010
409
static PHYSFS_Io *HOG_openAppend(dvoid *opaque, const char *name)
410
411
412
413
414
{
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* HOG_openAppend */
Sep 26, 2004
Sep 26, 2004
415
static int HOG_remove(dvoid *opaque, const char *name)
416
417
418
419
420
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* HOG_remove */
Sep 26, 2004
Sep 26, 2004
421
static int HOG_mkdir(dvoid *opaque, const char *name)
422
423
424
425
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* HOG_mkdir */
Sep 29, 2004
Sep 29, 2004
426
Aug 22, 2010
Aug 22, 2010
427
static int HOG_stat(dvoid *opaque, const char *filename, int *exists,
Feb 15, 2010
Feb 15, 2010
428
429
430
431
432
433
434
435
436
437
438
PHYSFS_Stat *stat)
{
const HOGinfo *info = (const HOGinfo *) opaque;
const HOGentry *entry = hog_find_entry(info, filename);
*exists = (entry != 0);
if (!entry)
return 0;
stat->filesize = entry->size;
stat->filetype = PHYSFS_FILETYPE_REGULAR;
Aug 25, 2010
Aug 25, 2010
439
440
stat->modtime = -1;
stat->createtime = -1;
Feb 15, 2010
Feb 15, 2010
441
442
443
stat->accesstime = -1;
stat->readonly = 1;
Aug 21, 2010
Aug 21, 2010
444
return 1;
Feb 15, 2010
Feb 15, 2010
445
446
447
} /* HOG_stat */
Sep 29, 2004
Sep 29, 2004
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_HOG =
{
"HOG",
HOG_ARCHIVE_DESCRIPTION,
"Bradley Bell <btb@icculus.org>",
"http://icculus.org/physfs/",
};
const PHYSFS_Archiver __PHYSFS_Archiver_HOG =
{
&__PHYSFS_ArchiveInfo_HOG,
HOG_openArchive, /* openArchive() method */
HOG_enumerateFiles, /* enumerateFiles() method */
HOG_exists, /* exists() method */
HOG_isDirectory, /* isDirectory() method */
HOG_isSymLink, /* isSymLink() method */
HOG_openRead, /* openRead() method */
HOG_openWrite, /* openWrite() method */
HOG_openAppend, /* openAppend() method */
HOG_remove, /* remove() method */
HOG_mkdir, /* mkdir() method */
HOG_dirClose, /* dirClose() method */
Aug 30, 2010
Aug 30, 2010
471
HOG_stat /* stat() method */
Sep 29, 2004
Sep 29, 2004
472
473
};
474
475
476
#endif /* defined PHYSFS_SUPPORTS_HOG */
/* end of hog.c ... */