Skip to content

Latest commit

 

History

History
458 lines (357 loc) · 11.9 KB

archiver_mvl.c

File metadata and controls

458 lines (357 loc) · 11.9 KB
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
* MVL support routines for PhysicsFS.
*
* This driver handles Descent II Movielib archives.
*
* The file format of MVL is quite easy...
*
* //MVL File format - Written by Heiko Herrmann
* char sig[4] = {'D','M', 'V', 'L'}; // "DMVL"=Descent MoVie Library
*
* int num_files; // the number of files in this MVL
*
* struct {
* char file_name[13]; // Filename, padded to 13 bytes with 0s
* int file_size; // filesize in bytes
* }DIR_STRUCT[num_files];
*
* struct {
* char data[file_size]; // The file data
* }FILE_STRUCT[num_files];
*
* (That info is from http://www.descent2.com/ddn/specs/mvl/)
*
Mar 11, 2007
Mar 11, 2007
24
* Please see the file LICENSE.txt in the source's root directory.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
*
* This file written by Bradley Bell.
* Based on grp.c by Ryan C. Gordon.
*/
#if (defined PHYSFS_SUPPORTS_MVL)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "physfs.h"
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
typedef struct
{
char name[13];
PHYSFS_uint32 startPos;
PHYSFS_uint32 size;
} MVLentry;
typedef struct
{
Aug 30, 2010
Aug 30, 2010
49
PHYSFS_Io *io;
50
51
52
53
54
55
PHYSFS_uint32 entryCount;
MVLentry *entries;
} MVLinfo;
typedef struct
{
Aug 30, 2010
Aug 30, 2010
56
PHYSFS_Io *io;
57
58
59
60
61
MVLentry *entry;
PHYSFS_uint32 curPos;
} MVLfileinfo;
Aug 30, 2010
Aug 30, 2010
62
63
64
65
66
67
static inline int readAll(PHYSFS_Io *io, void *buf, const PHYSFS_uint64 len)
{
return (io->read(io, buf, len) == len);
} /* readAll */
Sep 26, 2004
Sep 26, 2004
68
static void MVL_dirClose(dvoid *opaque)
Sep 26, 2004
Sep 26, 2004
70
MVLinfo *info = ((MVLinfo *) opaque);
Aug 30, 2010
Aug 30, 2010
71
info->io->destroy(info->io);
Mar 14, 2005
Mar 14, 2005
72
73
allocator.Free(info->entries);
allocator.Free(info);
74
75
76
} /* MVL_dirClose */
Aug 30, 2010
Aug 30, 2010
77
static PHYSFS_sint64 MVL_read(PHYSFS_Io *io, void *buffer, PHYSFS_uint64 len)
Aug 30, 2010
Aug 30, 2010
79
MVLfileinfo *finfo = (MVLfileinfo *) io->opaque;
Aug 21, 2010
Aug 21, 2010
80
81
const MVLentry *entry = finfo->entry;
const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos);
82
83
PHYSFS_sint64 rc;
Aug 21, 2010
Aug 21, 2010
84
85
if (bytesLeft < len)
len = bytesLeft;
Aug 30, 2010
Aug 30, 2010
87
rc = finfo->io->read(finfo->io, buffer, len);
Aug 21, 2010
Aug 21, 2010
89
finfo->curPos += (PHYSFS_uint32) rc;
Jan 28, 2010
Jan 28, 2010
91
return rc;
92
93
94
} /* MVL_read */
Aug 30, 2010
Aug 30, 2010
95
static PHYSFS_sint64 MVL_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
96
97
98
99
100
{
BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
} /* MVL_write */
Aug 30, 2010
Aug 30, 2010
101
static PHYSFS_sint64 MVL_tell(PHYSFS_Io *io)
Aug 30, 2010
Aug 30, 2010
103
return ((MVLfileinfo *) io->opaque)->curPos;
104
105
106
} /* MVL_tell */
Aug 30, 2010
Aug 30, 2010
107
static int MVL_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
Aug 30, 2010
Aug 30, 2010
109
110
MVLfileinfo *finfo = (MVLfileinfo *) io->opaque;
const MVLentry *entry = finfo->entry;
111
112
113
int rc;
BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
Aug 30, 2010
Aug 30, 2010
114
rc = finfo->io->seek(finfo->io, entry->startPos + offset);
115
116
117
if (rc)
finfo->curPos = (PHYSFS_uint32) offset;
Jan 28, 2010
Jan 28, 2010
118
return rc;
119
120
121
} /* MVL_seek */
Aug 30, 2010
Aug 30, 2010
122
static PHYSFS_sint64 MVL_length(PHYSFS_Io *io)
Aug 30, 2010
Aug 30, 2010
124
const MVLfileinfo *finfo = (MVLfileinfo *) io->opaque;
Jan 28, 2010
Jan 28, 2010
125
return ((PHYSFS_sint64) finfo->entry->size);
Aug 30, 2010
Aug 30, 2010
126
} /* MVL_length */
Aug 30, 2010
Aug 30, 2010
129
static PHYSFS_Io *MVL_duplicate(PHYSFS_Io *_io)
Aug 30, 2010
Aug 30, 2010
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
MVLfileinfo *origfinfo = (MVLfileinfo *) _io->opaque;
PHYSFS_Io *io = NULL;
PHYSFS_Io *retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
MVLfileinfo *finfo = (MVLfileinfo *) allocator.Malloc(sizeof (MVLfileinfo));
GOTO_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, MVL_duplicate_failed);
GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, MVL_duplicate_failed);
io = origfinfo->io->duplicate(origfinfo->io);
GOTO_IF_MACRO(io == NULL, NULL, MVL_duplicate_failed);
finfo->io = io;
finfo->entry = origfinfo->entry;
finfo->curPos = 0;
memcpy(retval, _io, sizeof (PHYSFS_Io));
retval->opaque = finfo;
return retval;
MVL_duplicate_failed:
if (finfo != NULL) allocator.Free(finfo);
if (retval != NULL) allocator.Free(retval);
if (io != NULL) io->destroy(io);
return NULL;
} /* MVL_duplicate */
Aug 30, 2010
Aug 30, 2010
154
static int MVL_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
Aug 30, 2010
Aug 30, 2010
156
static void MVL_destroy(PHYSFS_Io *io)
Aug 30, 2010
Aug 30, 2010
158
159
160
161
162
MVLfileinfo *finfo = (MVLfileinfo *) io->opaque;
finfo->io->destroy(finfo->io);
allocator.Free(finfo);
allocator.Free(io);
} /* MVL_destroy */
Aug 30, 2010
Aug 30, 2010
165
166
167
168
169
170
171
172
173
174
175
176
static const PHYSFS_Io MVL_Io =
{
MVL_read,
MVL_write,
MVL_seek,
MVL_tell,
MVL_length,
MVL_duplicate,
MVL_flush,
MVL_destroy,
NULL
};
Aug 30, 2010
Aug 30, 2010
179
static int mvlEntryCmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
Feb 20, 2008
Feb 20, 2008
181
182
183
if (one != two)
{
const MVLentry *a = (const MVLentry *) _a;
Aug 30, 2010
Aug 30, 2010
184
return __PHYSFS_stricmpASCII(a[one].name, a[two].name);
Feb 20, 2008
Feb 20, 2008
185
186
187
} /* if */
return 0;
Aug 30, 2010
Aug 30, 2010
188
} /* mvlEntryCmp */
Aug 30, 2010
Aug 30, 2010
191
static void mvlEntrySwap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
Feb 20, 2008
Feb 20, 2008
193
194
195
196
197
198
199
200
201
if (one != two)
{
MVLentry tmp;
MVLentry *first = &(((MVLentry *) _a)[one]);
MVLentry *second = &(((MVLentry *) _a)[two]);
memcpy(&tmp, first, sizeof (MVLentry));
memcpy(first, second, sizeof (MVLentry));
memcpy(second, &tmp, sizeof (MVLentry));
} /* if */
Aug 30, 2010
Aug 30, 2010
202
} /* mvlEntrySwap */
Aug 30, 2010
Aug 30, 2010
205
static int mvl_load_entries(PHYSFS_Io *io, MVLinfo *info)
Aug 30, 2010
Aug 30, 2010
207
PHYSFS_uint32 fileCount = info->entryCount;
208
209
210
PHYSFS_uint32 location = 8; /* sizeof sig. */
MVLentry *entry;
Mar 14, 2005
Mar 14, 2005
211
info->entries = (MVLentry *) allocator.Malloc(sizeof(MVLentry)*fileCount);
Aug 30, 2010
Aug 30, 2010
212
BAIL_IF_MACRO(info->entries == NULL, ERR_OUT_OF_MEMORY, 0);
213
214
215
216
217
location += (17 * fileCount);
for (entry = info->entries; fileCount > 0; fileCount--, entry++)
{
Aug 30, 2010
Aug 30, 2010
218
219
BAIL_IF_MACRO(!readAll(io, &entry->name, 13), NULL, 0);
BAIL_IF_MACRO(!readAll(io, &entry->size, 4), NULL, 0);
220
221
222
223
224
entry->size = PHYSFS_swapULE32(entry->size);
entry->startPos = location;
location += entry->size;
} /* for */
Aug 30, 2010
Aug 30, 2010
225
__PHYSFS_sort(info->entries, info->entryCount, mvlEntryCmp, mvlEntrySwap);
Jan 28, 2010
Jan 28, 2010
226
return 1;
227
228
229
} /* mvl_load_entries */
Aug 30, 2010
Aug 30, 2010
230
static void *MVL_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
Aug 30, 2010
Aug 30, 2010
232
233
234
PHYSFS_uint8 buf[4];
MVLinfo *info = NULL;
PHYSFS_uint32 val = 0;
Aug 30, 2010
Aug 30, 2010
236
237
238
239
240
241
242
243
244
245
assert(io != NULL); /* shouldn't ever happen. */
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
BAIL_IF_MACRO(!readAll(io, buf, 4), NULL, NULL);
if (memcmp(buf, "DMVL", 4) != 0)
GOTO_MACRO(ERR_NOT_AN_ARCHIVE, MVL_openArchive_failed);
info = (MVLinfo *) allocator.Malloc(sizeof (MVLinfo));
GOTO_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, MVL_openArchive_failed);
246
memset(info, '\0', sizeof (MVLinfo));
Aug 30, 2010
Aug 30, 2010
247
248
249
250
info->io = io;
GOTO_IF_MACRO(!readAll(io,&val,sizeof(val)), NULL, MVL_openArchive_failed);
info->entryCount = PHYSFS_swapULE32(val);
Aug 30, 2010
Aug 30, 2010
252
GOTO_IF_MACRO(!mvl_load_entries(io, info), NULL, MVL_openArchive_failed);
Jan 28, 2010
Jan 28, 2010
254
return info;
255
256
MVL_openArchive_failed:
Sep 26, 2004
Sep 26, 2004
257
if (info != NULL)
Sep 26, 2004
Sep 26, 2004
259
if (info->entries != NULL)
Mar 14, 2005
Mar 14, 2005
260
261
allocator.Free(info->entries);
allocator.Free(info);
Jan 28, 2010
Jan 28, 2010
264
return NULL;
265
266
267
} /* MVL_openArchive */
Sep 29, 2004
Sep 29, 2004
268
static void MVL_enumerateFiles(dvoid *opaque, const char *dname,
Sep 18, 2005
Sep 18, 2005
269
270
int omitSymLinks, PHYSFS_EnumFilesCallback cb,
const char *origdir, void *callbackdata)
271
272
{
/* no directories in MVL files. */
Mar 28, 2007
Mar 28, 2007
273
if (*dname == '\0')
Sep 29, 2004
Sep 29, 2004
274
275
276
277
278
{
MVLinfo *info = ((MVLinfo *) opaque);
MVLentry *entry = info->entries;
PHYSFS_uint32 max = info->entryCount;
PHYSFS_uint32 i;
Sep 29, 2004
Sep 29, 2004
280
for (i = 0; i < max; i++, entry++)
Sep 18, 2005
Sep 18, 2005
281
cb(callbackdata, origdir, entry->name);
Sep 29, 2004
Sep 29, 2004
282
} /* if */
283
284
285
} /* MVL_enumerateFiles */
Feb 15, 2010
Feb 15, 2010
286
static MVLentry *mvl_find_entry(const MVLinfo *info, const char *name)
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
{
char *ptr = strchr(name, '.');
MVLentry *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
306
rc = __PHYSFS_stricmpASCII(name, a[middle].name);
307
if (rc == 0) /* found it! */
Jan 28, 2010
Jan 28, 2010
308
return &a[middle];
309
310
311
312
313
314
315
316
317
318
else if (rc > 0)
lo = middle + 1;
else
hi = middle - 1;
} /* while */
BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
} /* mvl_find_entry */
Sep 26, 2004
Sep 26, 2004
319
static int MVL_exists(dvoid *opaque, const char *name)
Jan 28, 2010
Jan 28, 2010
321
return (mvl_find_entry((MVLinfo *) opaque, name) != NULL);
322
323
324
} /* MVL_exists */
Sep 26, 2004
Sep 26, 2004
325
static int MVL_isDirectory(dvoid *opaque, const char *name, int *fileExists)
Sep 26, 2004
Sep 26, 2004
327
*fileExists = MVL_exists(opaque, name);
Jan 28, 2010
Jan 28, 2010
328
return 0; /* never directories in a groupfile. */
329
330
331
} /* MVL_isDirectory */
Sep 26, 2004
Sep 26, 2004
332
static int MVL_isSymLink(dvoid *opaque, const char *name, int *fileExists)
Sep 26, 2004
Sep 26, 2004
334
*fileExists = MVL_exists(opaque, name);
Jan 28, 2010
Jan 28, 2010
335
return 0; /* never symlinks in a groupfile. */
336
337
338
} /* MVL_isSymLink */
Aug 30, 2010
Aug 30, 2010
339
static PHYSFS_Io *MVL_openRead(dvoid *opaque, const char *fnm, int *fileExists)
Aug 30, 2010
Aug 30, 2010
341
342
PHYSFS_Io *retval = NULL;
MVLinfo *info = (MVLinfo *) opaque;
343
344
345
346
347
MVLfileinfo *finfo;
MVLentry *entry;
entry = mvl_find_entry(info, fnm);
*fileExists = (entry != NULL);
Aug 30, 2010
Aug 30, 2010
348
349
350
351
GOTO_IF_MACRO(entry == NULL, NULL, MVL_openRead_failed);
retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
GOTO_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, MVL_openRead_failed);
Mar 14, 2005
Mar 14, 2005
353
finfo = (MVLfileinfo *) allocator.Malloc(sizeof (MVLfileinfo));
Aug 30, 2010
Aug 30, 2010
354
355
356
357
358
359
360
361
362
363
364
365
366
367
GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, MVL_openRead_failed);
finfo->io = info->io->duplicate(info->io);
GOTO_IF_MACRO(finfo->io == NULL, NULL, MVL_openRead_failed);
if (!finfo->io->seek(finfo->io, entry->startPos))
GOTO_MACRO(NULL, MVL_openRead_failed);
finfo->curPos = 0;
finfo->entry = entry;
memcpy(retval, &MVL_Io, sizeof (*retval));
retval->opaque = finfo;
return retval;
Aug 30, 2010
Aug 30, 2010
369
370
MVL_openRead_failed:
if (finfo != NULL)
Aug 30, 2010
Aug 30, 2010
372
373
if (finfo->io != NULL)
finfo->io->destroy(finfo->io);
Mar 14, 2005
Mar 14, 2005
374
allocator.Free(finfo);
Aug 30, 2010
Aug 30, 2010
377
378
379
380
if (retval != NULL)
allocator.Free(retval);
return NULL;
381
382
383
} /* MVL_openRead */
Aug 30, 2010
Aug 30, 2010
384
static PHYSFS_Io *MVL_openWrite(dvoid *opaque, const char *name)
385
386
387
388
389
{
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* MVL_openWrite */
Aug 30, 2010
Aug 30, 2010
390
static PHYSFS_Io *MVL_openAppend(dvoid *opaque, const char *name)
391
392
393
394
395
{
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* MVL_openAppend */
Sep 26, 2004
Sep 26, 2004
396
static int MVL_remove(dvoid *opaque, const char *name)
397
398
399
400
401
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* MVL_remove */
Sep 26, 2004
Sep 26, 2004
402
static int MVL_mkdir(dvoid *opaque, const char *name)
403
404
405
406
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* MVL_mkdir */
Sep 29, 2004
Sep 29, 2004
407
Aug 22, 2010
Aug 22, 2010
408
static int MVL_stat(dvoid *opaque, const char *filename, int *exists,
Feb 15, 2010
Feb 15, 2010
409
410
411
412
413
414
415
416
417
418
419
PHYSFS_Stat *stat)
{
const MVLinfo *info = (const MVLinfo *) opaque;
const MVLentry *entry = mvl_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
420
421
422
stat->modtime = -1;
stat->createtime = -1;
stat->accesstime = -1;
Feb 15, 2010
Feb 15, 2010
423
424
stat->readonly = 1;
Aug 21, 2010
Aug 21, 2010
425
return 1;
Feb 15, 2010
Feb 15, 2010
426
427
428
} /* MVL_stat */
Sep 29, 2004
Sep 29, 2004
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_MVL =
{
"MVL",
MVL_ARCHIVE_DESCRIPTION,
"Bradley Bell <btb@icculus.org>",
"http://icculus.org/physfs/",
};
const PHYSFS_Archiver __PHYSFS_Archiver_MVL =
{
&__PHYSFS_ArchiveInfo_MVL,
MVL_openArchive, /* openArchive() method */
MVL_enumerateFiles, /* enumerateFiles() method */
MVL_exists, /* exists() method */
MVL_isDirectory, /* isDirectory() method */
MVL_isSymLink, /* isSymLink() method */
MVL_openRead, /* openRead() method */
MVL_openWrite, /* openWrite() method */
MVL_openAppend, /* openAppend() method */
MVL_remove, /* remove() method */
MVL_mkdir, /* mkdir() method */
MVL_dirClose, /* dirClose() method */
Aug 30, 2010
Aug 30, 2010
452
MVL_stat /* stat() method */
Sep 29, 2004
Sep 29, 2004
453
454
};
455
456
457
#endif /* defined PHYSFS_SUPPORTS_MVL */
/* end of mvl.c ... */