Skip to content

Latest commit

 

History

History
442 lines (350 loc) · 12.6 KB

grp.c

File metadata and controls

442 lines (350 loc) · 12.6 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
/*
* GRP support routines for PhysicsFS.
*
* This driver handles BUILD engine archives ("groupfiles"). This format
* (but not this driver) was put together by Ken Silverman.
*
* The format is simple enough. In Ken's words:
*
* What's the .GRP file format?
*
* The ".grp" file format is just a collection of a lot of files stored
* into 1 big one. I tried to make the format as simple as possible: The
* first 12 bytes contains my name, "KenSilverman". The next 4 bytes is
* the number of files that were compacted into the group file. Then for
* each file, there is a 16 byte structure, where the first 12 bytes are
* the filename, and the last 4 bytes are the file's size. The rest of
* the group file is just the raw data packed one after the other in the
* same order as the list of files.
*
* (That info is from http://www.advsys.net/ken/build.htm ...)
*
* As it was never a concern in the DOS-based Duke Nukem days, I treat these
* archives as CASE-INSENSITIVE. Opening "myfile.txt" and "MYFILE.TXT" both
* work, and get the same file.
*
* Please see the file LICENSE in the source's root directory.
*
* This file written by Ryan C. Gordon.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <assert.h>
#include "physfs.h"
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
#if (!defined PHYSFS_SUPPORTS_GRP)
#error PHYSFS_SUPPORTS_GRP must be defined.
#endif
typedef struct
{
Mar 25, 2002
Mar 25, 2002
48
49
void *handle;
char *filename;
Mar 24, 2002
Mar 24, 2002
50
PHYSFS_uint32 totalEntries;
51
52
53
54
} GRPinfo;
typedef struct
{
Mar 25, 2002
Mar 25, 2002
55
56
57
void *handle;
PHYSFS_uint64 startPos;
PHYSFS_uint64 size;
58
59
60
} GRPfileinfo;
Sep 2, 2001
Sep 2, 2001
61
static void GRP_dirClose(DirHandle *h);
Mar 24, 2002
Mar 24, 2002
62
63
static PHYSFS_sint64 GRP_read(FileHandle *handle, void *buffer,
PHYSFS_uint32 objSize, PHYSFS_uint32 objCount);
Sep 2, 2001
Sep 2, 2001
64
static int GRP_eof(FileHandle *handle);
Mar 24, 2002
Mar 24, 2002
65
66
67
static PHYSFS_sint64 GRP_tell(FileHandle *handle);
static int GRP_seek(FileHandle *handle, PHYSFS_uint64 offset);
static PHYSFS_sint64 GRP_fileLength(FileHandle *handle);
Sep 2, 2001
Sep 2, 2001
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
static int GRP_fileClose(FileHandle *handle);
static int GRP_isArchive(const char *filename, int forWriting);
static DirHandle *GRP_openArchive(const char *name, int forWriting);
static LinkedStringList *GRP_enumerateFiles(DirHandle *h,
const char *dirname,
int omitSymLinks);
static int GRP_exists(DirHandle *h, const char *name);
static int GRP_isDirectory(DirHandle *h, const char *name);
static int GRP_isSymLink(DirHandle *h, const char *name);
static FileHandle *GRP_openRead(DirHandle *h, const char *name);
static const FileFunctions __PHYSFS_FileFunctions_GRP =
{
GRP_read, /* read() method */
NULL, /* write() method */
GRP_eof, /* eof() method */
GRP_tell, /* tell() method */
GRP_seek, /* seek() method */
GRP_fileLength, /* fileLength() method */
GRP_fileClose /* fileClose() method */
};
const DirFunctions __PHYSFS_DirFunctions_GRP =
{
GRP_isArchive, /* isArchive() method */
GRP_openArchive, /* openArchive() method */
GRP_enumerateFiles, /* enumerateFiles() method */
GRP_exists, /* exists() method */
GRP_isDirectory, /* isDirectory() method */
GRP_isSymLink, /* isSymLink() method */
GRP_openRead, /* openRead() method */
NULL, /* openWrite() method */
NULL, /* openAppend() method */
NULL, /* remove() method */
NULL, /* mkdir() method */
GRP_dirClose /* dirClose() method */
};
const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_GRP =
{
"GRP",
"Build engine Groupfile format",
Sep 14, 2001
Sep 14, 2001
111
"Ryan C. Gordon <icculus@clutteredmind.org>",
Sep 2, 2001
Sep 2, 2001
112
113
114
115
116
117
118
"http://www.icculus.org/physfs/",
};
static void GRP_dirClose(DirHandle *h)
{
Mar 25, 2002
Mar 25, 2002
119
120
__PHYSFS_platformClose( ((GRPinfo *) h->opaque)->handle );
free(((GRPinfo *) h->opaque)->filename);
Sep 2, 2001
Sep 2, 2001
121
122
123
free(h->opaque);
free(h);
} /* GRP_dirClose */
Mar 24, 2002
Mar 24, 2002
126
127
static PHYSFS_sint64 GRP_read(FileHandle *handle, void *buffer,
PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
128
129
{
GRPfileinfo *finfo = (GRPfileinfo *) (handle->opaque);
Mar 25, 2002
Mar 25, 2002
130
131
132
void *fh = finfo->handle;
PHYSFS_sint64 curPos = __PHYSFS_platformTell(fh);
PHYSFS_uint64 bytesLeft = (finfo->startPos + finfo->size) - curPos;
Apr 3, 2002
Apr 3, 2002
133
PHYSFS_uint64 objsLeft = (bytesLeft / objSize);
134
135
if (objsLeft < objCount)
Apr 12, 2002
Apr 12, 2002
136
objCount = (PHYSFS_uint32) objsLeft;
Mar 25, 2002
Mar 25, 2002
138
return(__PHYSFS_platformRead(fh, buffer, objSize, objCount));
139
140
141
142
143
144
} /* GRP_read */
static int GRP_eof(FileHandle *handle)
{
GRPfileinfo *finfo = (GRPfileinfo *) (handle->opaque);
Mar 25, 2002
Mar 25, 2002
145
void *fh = finfo->handle;
Apr 12, 2002
Apr 12, 2002
146
147
148
PHYSFS_sint64 pos = __PHYSFS_platformTell(fh);
BAIL_IF_MACRO(pos < 0, NULL, 1); /* (*shrug*) */
return(pos >= (PHYSFS_sint64) (finfo->startPos + finfo->size));
149
150
151
} /* GRP_eof */
Mar 24, 2002
Mar 24, 2002
152
static PHYSFS_sint64 GRP_tell(FileHandle *handle)
153
154
{
GRPfileinfo *finfo = (GRPfileinfo *) (handle->opaque);
Mar 25, 2002
Mar 25, 2002
155
return(__PHYSFS_platformTell(finfo->handle) - finfo->startPos);
156
157
158
} /* GRP_tell */
Mar 24, 2002
Mar 24, 2002
159
static int GRP_seek(FileHandle *handle, PHYSFS_uint64 offset)
160
161
{
GRPfileinfo *finfo = (GRPfileinfo *) (handle->opaque);
Apr 3, 2002
Apr 3, 2002
162
PHYSFS_uint64 newPos = (finfo->startPos + offset);
163
164
165
BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
BAIL_IF_MACRO(newPos > finfo->startPos + finfo->size, ERR_PAST_EOF, 0);
Mar 25, 2002
Mar 25, 2002
166
return(__PHYSFS_platformSeek(finfo->handle, newPos));
167
168
169
} /* GRP_seek */
Mar 24, 2002
Mar 24, 2002
170
static PHYSFS_sint64 GRP_fileLength(FileHandle *handle)
Jul 9, 2001
Jul 9, 2001
171
172
173
174
175
176
{
GRPfileinfo *finfo = (GRPfileinfo *) (handle->opaque);
return(finfo->size);
} /* GRP_fileLength */
177
178
static int GRP_fileClose(FileHandle *handle)
{
Mar 25, 2002
Mar 25, 2002
179
180
181
GRPfileinfo *finfo = (GRPfileinfo *) (handle->opaque);
BAIL_IF_MACRO(__PHYSFS_platformClose(finfo->handle), NULL, 0);
182
183
184
185
186
187
free(handle->opaque);
free(handle);
return(1);
} /* GRP_fileClose */
Mar 25, 2002
Mar 25, 2002
188
189
static int openGrp(const char *filename, int forWriting,
void **fh, PHYSFS_sint32 *count)
Mar 25, 2002
Mar 25, 2002
191
PHYSFS_uint8 buf[12];
192
193
194
195
*fh = NULL;
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
Mar 25, 2002
Mar 25, 2002
196
197
*fh = __PHYSFS_platformOpenRead(filename);
BAIL_IF_MACRO(*fh == NULL, NULL, 0);
Mar 25, 2002
Mar 25, 2002
199
200
201
202
203
204
205
206
if (__PHYSFS_platformRead(*fh, buf, 12, 1) != 1)
goto openGrp_failed;
if (memcmp(buf, "KenSilverman", 12) != 0)
{
__PHYSFS_setError(ERR_UNSUPPORTED_ARCHIVE);
goto openGrp_failed;
} /* if */
Mar 25, 2002
Mar 25, 2002
208
209
if (__PHYSFS_platformRead(*fh, count, sizeof (PHYSFS_sint32), 1) != 1)
goto openGrp_failed;
Apr 5, 2002
Apr 5, 2002
211
212
*count = PHYSFS_swapSLE32(*count);
213
return(1);
Mar 25, 2002
Mar 25, 2002
214
215
216
217
218
219
220
221
openGrp_failed:
if (*fh != NULL)
__PHYSFS_platformClose(*fh);
*count = -1;
*fh = NULL;
return(0);
222
223
224
225
226
} /* openGrp */
static int GRP_isArchive(const char *filename, int forWriting)
{
Mar 25, 2002
Mar 25, 2002
227
void *fh;
228
229
230
231
int fileCount;
int retval = openGrp(filename, forWriting, &fh, &fileCount);
if (fh != NULL)
Mar 25, 2002
Mar 25, 2002
232
__PHYSFS_platformClose(fh);
233
234
235
236
237
238
239
return(retval);
} /* GRP_isArchive */
static DirHandle *GRP_openArchive(const char *name, int forWriting)
{
Mar 25, 2002
Mar 25, 2002
240
void *fh = NULL;
241
242
243
244
245
246
247
int fileCount;
DirHandle *retval = malloc(sizeof (DirHandle));
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
retval->opaque = malloc(sizeof (GRPinfo));
if (retval->opaque == NULL)
{
Mar 25, 2002
Mar 25, 2002
248
249
__PHYSFS_setError(ERR_OUT_OF_MEMORY);
goto GRP_openArchive_failed;
250
251
} /* if */
Mar 25, 2002
Mar 25, 2002
252
253
((GRPinfo *) retval->opaque)->filename = (char *) malloc(strlen(name) + 1);
if (((GRPinfo *) retval->opaque)->filename == NULL)
Mar 25, 2002
Mar 25, 2002
255
256
__PHYSFS_setError(ERR_OUT_OF_MEMORY);
goto GRP_openArchive_failed;
257
258
} /* if */
Mar 25, 2002
Mar 25, 2002
259
260
261
262
if (!openGrp(name, forWriting, &fh, &fileCount))
goto GRP_openArchive_failed;
strcpy(((GRPinfo *) retval->opaque)->filename, name);
263
264
265
266
((GRPinfo *) retval->opaque)->handle = fh;
((GRPinfo *) retval->opaque)->totalEntries = fileCount;
retval->funcs = &__PHYSFS_DirFunctions_GRP;
return(retval);
Mar 25, 2002
Mar 25, 2002
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
GRP_openArchive_failed:
if (retval != NULL)
{
if (retval->opaque != NULL)
{
if ( ((GRPinfo *) retval->opaque)->filename != NULL )
free( ((GRPinfo *) retval->opaque)->filename );
free(retval->opaque);
} /* if */
free(retval);
} /* if */
if (fh != NULL)
__PHYSFS_platformClose(fh);
return(NULL);
284
285
286
} /* GRP_openArchive */
Jul 16, 2001
Jul 16, 2001
287
288
289
static LinkedStringList *GRP_enumerateFiles(DirHandle *h,
const char *dirname,
int omitSymLinks)
Mar 25, 2002
Mar 25, 2002
291
PHYSFS_uint8 buf[16];
292
GRPinfo *g = (GRPinfo *) (h->opaque);
Mar 25, 2002
Mar 25, 2002
293
void *fh = g->handle;
Apr 3, 2002
Apr 3, 2002
294
PHYSFS_uint32 i;
295
296
297
298
LinkedStringList *retval = NULL;
LinkedStringList *l = NULL;
LinkedStringList *prev = NULL;
Mar 25, 2002
Mar 25, 2002
299
/* !!! FIXME: Does this consider "/" ? */
Jul 15, 2001
Jul 15, 2001
300
301
302
if (*dirname != '\0') /* no directories in GRP files. */
return(NULL);
303
/* jump to first file entry... */
Mar 25, 2002
Mar 25, 2002
304
BAIL_IF_MACRO(!__PHYSFS_platformSeek(fh, 16), NULL, NULL);
305
306
307
for (i = 0; i < g->totalEntries; i++)
{
Mar 25, 2002
Mar 25, 2002
308
BAIL_IF_MACRO(__PHYSFS_platformRead(fh, buf, 16, 1) != 1, NULL, retval);
309
310
311
312
buf[12] = '\0'; /* FILENAME.EXT is all you get. */
l = (LinkedStringList *) malloc(sizeof (LinkedStringList));
Jul 16, 2001
Jul 16, 2001
313
if (l == NULL)
314
315
break;
Apr 1, 2002
Apr 1, 2002
316
l->str = (char *) malloc(strlen((const char *) buf) + 1);
317
318
319
320
321
322
if (l->str == NULL)
{
free(l);
break;
} /* if */
Apr 1, 2002
Apr 1, 2002
323
strcpy(l->str, (const char *) buf);
Jul 16, 2001
Jul 16, 2001
324
325
326
327
328
329
330
331
332
333
334
335
336
337
if (retval == NULL)
retval = l;
else
prev->next = l;
prev = l;
l->next = NULL;
} /* for */
return(retval);
} /* GRP_enumerateFiles */
Mar 24, 2002
Mar 24, 2002
338
static PHYSFS_sint32 getFileEntry(DirHandle *h, const char *name,
Apr 1, 2002
Apr 1, 2002
339
PHYSFS_uint32 *size)
Mar 25, 2002
Mar 25, 2002
341
PHYSFS_uint8 buf[16];
342
GRPinfo *g = (GRPinfo *) (h->opaque);
Mar 25, 2002
Mar 25, 2002
343
void *fh = g->handle;
Apr 3, 2002
Apr 3, 2002
344
PHYSFS_uint32 i;
345
char *ptr;
Jul 9, 2001
Jul 9, 2001
346
int retval = (g->totalEntries + 1) * 16; /* offset of raw file data */
347
348
349
350
351
352
353
354
355
356
357
358
/* Rule out filenames to avoid unneeded file i/o... */
if (strchr(name, '/') != NULL) /* no directories in groupfiles. */
return(-1);
ptr = strchr(name, '.');
if ((ptr) && (strlen(ptr) > 4)) /* 3 char extension at most. */
return(-1);
if (strlen(name) > 12)
return(-1);
Mar 25, 2002
Mar 25, 2002
359
360
/* jump to first file entry... */
BAIL_IF_MACRO(!__PHYSFS_platformSeek(fh, 16), NULL, -1);
361
362
363
for (i = 0; i < g->totalEntries; i++)
{
Mar 24, 2002
Mar 24, 2002
364
PHYSFS_sint32 l = 0;
Mar 25, 2002
Mar 25, 2002
366
367
BAIL_IF_MACRO(__PHYSFS_platformRead(fh, buf, 12, 1) != 1, NULL, -1);
BAIL_IF_MACRO(__PHYSFS_platformRead(fh, &l, sizeof (l), 1) != 1, NULL, -1);
Apr 5, 2002
Apr 5, 2002
368
l = PHYSFS_swapSLE32(l);
369
370
371
buf[12] = '\0'; /* FILENAME.EXT is all you get. */
Apr 1, 2002
Apr 1, 2002
372
if (__PHYSFS_platformStricmp((const char *) buf, name) == 0)
373
374
{
if (size != NULL)
Mar 24, 2002
Mar 24, 2002
375
*size = l;
376
377
378
return(retval);
} /* if */
Mar 24, 2002
Mar 24, 2002
379
retval += l;
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
} /* for */
return(-1); /* not found. */
} /* getFileEntry */
static int GRP_exists(DirHandle *h, const char *name)
{
return(getFileEntry(h, name, NULL) != -1);
} /* GRP_exists */
static int GRP_isDirectory(DirHandle *h, const char *name)
{
return(0); /* never directories in a groupfile. */
} /* GRP_isDirectory */
static int GRP_isSymLink(DirHandle *h, const char *name)
{
return(0); /* never symlinks in a groupfile. */
} /* GRP_isSymLink */
static FileHandle *GRP_openRead(DirHandle *h, const char *name)
{
Mar 25, 2002
Mar 25, 2002
406
const char *filename = ((GRPinfo *) h->opaque)->filename;
407
408
FileHandle *retval;
GRPfileinfo *finfo;
Mar 25, 2002
Mar 25, 2002
409
PHYSFS_uint32 size;
Mar 24, 2002
Mar 24, 2002
410
PHYSFS_sint32 offset;
411
412
413
414
415
416
417
418
419
420
421
422
423
offset = getFileEntry(h, name, &size);
BAIL_IF_MACRO(offset == -1, ERR_NO_SUCH_FILE, NULL);
retval = (FileHandle *) malloc(sizeof (FileHandle));
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
finfo = (GRPfileinfo *) malloc(sizeof (GRPfileinfo));
if (finfo == NULL)
{
free(retval);
BAIL_IF_MACRO(1, ERR_OUT_OF_MEMORY, NULL);
} /* if */
Mar 25, 2002
Mar 25, 2002
424
425
426
427
428
429
430
431
432
finfo->handle = __PHYSFS_platformOpenRead(filename);
if ( (finfo->handle == NULL) ||
(!__PHYSFS_platformSeek(finfo->handle, offset)) )
{
free(finfo);
free(retval);
return(NULL);
} /* if */
433
434
435
436
437
438
439
440
441
finfo->startPos = offset;
finfo->size = size;
retval->opaque = (void *) finfo;
retval->funcs = &__PHYSFS_FileFunctions_GRP;
retval->dirHandle = h;
return(retval);
} /* GRP_openRead */
/* end of grp.c ... */