Skip to content

Latest commit

 

History

History
447 lines (353 loc) · 12.7 KB

grp.c

File metadata and controls

447 lines (353 loc) · 12.7 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
/*
* 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.
*/
May 10, 2002
May 10, 2002
31
32
33
34
35
36
#if HAVE_CONFIG_H
# include <config.h>
#endif
#if (defined PHYSFS_SUPPORTS_GRP)
37
38
39
40
41
42
43
44
45
46
47
48
49
#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"
typedef struct
{
Mar 25, 2002
Mar 25, 2002
50
51
void *handle;
char *filename;
Mar 24, 2002
Mar 24, 2002
52
PHYSFS_uint32 totalEntries;
53
54
55
56
} GRPinfo;
typedef struct
{
Mar 25, 2002
Mar 25, 2002
57
58
59
void *handle;
PHYSFS_uint64 startPos;
PHYSFS_uint64 size;
60
61
62
} GRPfileinfo;
Sep 2, 2001
Sep 2, 2001
63
static void GRP_dirClose(DirHandle *h);
Mar 24, 2002
Mar 24, 2002
64
65
static PHYSFS_sint64 GRP_read(FileHandle *handle, void *buffer,
PHYSFS_uint32 objSize, PHYSFS_uint32 objCount);
Sep 2, 2001
Sep 2, 2001
66
static int GRP_eof(FileHandle *handle);
Mar 24, 2002
Mar 24, 2002
67
68
69
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
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
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 */
May 25, 2002
May 25, 2002
101
NULL, /* getLastModTime() method */
Sep 2, 2001
Sep 2, 2001
102
103
104
105
106
107
108
109
110
111
112
113
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
114
"Ryan C. Gordon <icculus@clutteredmind.org>",
Sep 2, 2001
Sep 2, 2001
115
116
117
118
119
120
121
"http://www.icculus.org/physfs/",
};
static void GRP_dirClose(DirHandle *h)
{
Mar 25, 2002
Mar 25, 2002
122
123
__PHYSFS_platformClose( ((GRPinfo *) h->opaque)->handle );
free(((GRPinfo *) h->opaque)->filename);
Sep 2, 2001
Sep 2, 2001
124
125
126
free(h->opaque);
free(h);
} /* GRP_dirClose */
Mar 24, 2002
Mar 24, 2002
129
130
static PHYSFS_sint64 GRP_read(FileHandle *handle, void *buffer,
PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
131
132
{
GRPfileinfo *finfo = (GRPfileinfo *) (handle->opaque);
Mar 25, 2002
Mar 25, 2002
133
134
135
void *fh = finfo->handle;
PHYSFS_sint64 curPos = __PHYSFS_platformTell(fh);
PHYSFS_uint64 bytesLeft = (finfo->startPos + finfo->size) - curPos;
Apr 3, 2002
Apr 3, 2002
136
PHYSFS_uint64 objsLeft = (bytesLeft / objSize);
137
138
if (objsLeft < objCount)
Apr 12, 2002
Apr 12, 2002
139
objCount = (PHYSFS_uint32) objsLeft;
Mar 25, 2002
Mar 25, 2002
141
return(__PHYSFS_platformRead(fh, buffer, objSize, objCount));
142
143
144
145
146
147
} /* GRP_read */
static int GRP_eof(FileHandle *handle)
{
GRPfileinfo *finfo = (GRPfileinfo *) (handle->opaque);
Mar 25, 2002
Mar 25, 2002
148
void *fh = finfo->handle;
Apr 12, 2002
Apr 12, 2002
149
150
151
PHYSFS_sint64 pos = __PHYSFS_platformTell(fh);
BAIL_IF_MACRO(pos < 0, NULL, 1); /* (*shrug*) */
return(pos >= (PHYSFS_sint64) (finfo->startPos + finfo->size));
152
153
154
} /* GRP_eof */
Mar 24, 2002
Mar 24, 2002
155
static PHYSFS_sint64 GRP_tell(FileHandle *handle)
156
157
{
GRPfileinfo *finfo = (GRPfileinfo *) (handle->opaque);
Mar 25, 2002
Mar 25, 2002
158
return(__PHYSFS_platformTell(finfo->handle) - finfo->startPos);
159
160
161
} /* GRP_tell */
Mar 24, 2002
Mar 24, 2002
162
static int GRP_seek(FileHandle *handle, PHYSFS_uint64 offset)
163
164
{
GRPfileinfo *finfo = (GRPfileinfo *) (handle->opaque);
Apr 3, 2002
Apr 3, 2002
165
PHYSFS_uint64 newPos = (finfo->startPos + offset);
166
167
168
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
169
return(__PHYSFS_platformSeek(finfo->handle, newPos));
170
171
172
} /* GRP_seek */
Mar 24, 2002
Mar 24, 2002
173
static PHYSFS_sint64 GRP_fileLength(FileHandle *handle)
Jul 9, 2001
Jul 9, 2001
174
175
176
177
178
179
{
GRPfileinfo *finfo = (GRPfileinfo *) (handle->opaque);
return(finfo->size);
} /* GRP_fileLength */
180
181
static int GRP_fileClose(FileHandle *handle)
{
Mar 25, 2002
Mar 25, 2002
182
183
184
GRPfileinfo *finfo = (GRPfileinfo *) (handle->opaque);
BAIL_IF_MACRO(__PHYSFS_platformClose(finfo->handle), NULL, 0);
185
186
187
188
189
190
free(handle->opaque);
free(handle);
return(1);
} /* GRP_fileClose */
Mar 25, 2002
Mar 25, 2002
191
192
static int openGrp(const char *filename, int forWriting,
void **fh, PHYSFS_sint32 *count)
Mar 25, 2002
Mar 25, 2002
194
PHYSFS_uint8 buf[12];
195
196
197
198
*fh = NULL;
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
Mar 25, 2002
Mar 25, 2002
199
200
*fh = __PHYSFS_platformOpenRead(filename);
BAIL_IF_MACRO(*fh == NULL, NULL, 0);
Mar 25, 2002
Mar 25, 2002
202
203
204
205
206
207
208
209
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
211
212
if (__PHYSFS_platformRead(*fh, count, sizeof (PHYSFS_sint32), 1) != 1)
goto openGrp_failed;
Apr 5, 2002
Apr 5, 2002
214
215
*count = PHYSFS_swapSLE32(*count);
216
return(1);
Mar 25, 2002
Mar 25, 2002
217
218
219
220
221
222
223
224
openGrp_failed:
if (*fh != NULL)
__PHYSFS_platformClose(*fh);
*count = -1;
*fh = NULL;
return(0);
225
226
227
228
229
} /* openGrp */
static int GRP_isArchive(const char *filename, int forWriting)
{
Mar 25, 2002
Mar 25, 2002
230
void *fh;
231
232
233
234
int fileCount;
int retval = openGrp(filename, forWriting, &fh, &fileCount);
if (fh != NULL)
Mar 25, 2002
Mar 25, 2002
235
__PHYSFS_platformClose(fh);
236
237
238
239
240
241
242
return(retval);
} /* GRP_isArchive */
static DirHandle *GRP_openArchive(const char *name, int forWriting)
{
Mar 25, 2002
Mar 25, 2002
243
void *fh = NULL;
244
245
246
247
248
249
250
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
251
252
__PHYSFS_setError(ERR_OUT_OF_MEMORY);
goto GRP_openArchive_failed;
253
254
} /* if */
Mar 25, 2002
Mar 25, 2002
255
256
((GRPinfo *) retval->opaque)->filename = (char *) malloc(strlen(name) + 1);
if (((GRPinfo *) retval->opaque)->filename == NULL)
Mar 25, 2002
Mar 25, 2002
258
259
__PHYSFS_setError(ERR_OUT_OF_MEMORY);
goto GRP_openArchive_failed;
260
261
} /* if */
Mar 25, 2002
Mar 25, 2002
262
263
264
265
if (!openGrp(name, forWriting, &fh, &fileCount))
goto GRP_openArchive_failed;
strcpy(((GRPinfo *) retval->opaque)->filename, name);
266
267
268
269
((GRPinfo *) retval->opaque)->handle = fh;
((GRPinfo *) retval->opaque)->totalEntries = fileCount;
retval->funcs = &__PHYSFS_DirFunctions_GRP;
return(retval);
Mar 25, 2002
Mar 25, 2002
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
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);
287
288
289
} /* GRP_openArchive */
Jul 16, 2001
Jul 16, 2001
290
291
292
static LinkedStringList *GRP_enumerateFiles(DirHandle *h,
const char *dirname,
int omitSymLinks)
Mar 25, 2002
Mar 25, 2002
294
PHYSFS_uint8 buf[16];
295
GRPinfo *g = (GRPinfo *) (h->opaque);
Mar 25, 2002
Mar 25, 2002
296
void *fh = g->handle;
Apr 3, 2002
Apr 3, 2002
297
PHYSFS_uint32 i;
298
299
300
301
LinkedStringList *retval = NULL;
LinkedStringList *l = NULL;
LinkedStringList *prev = NULL;
Mar 25, 2002
Mar 25, 2002
302
/* !!! FIXME: Does this consider "/" ? */
Jul 15, 2001
Jul 15, 2001
303
304
305
if (*dirname != '\0') /* no directories in GRP files. */
return(NULL);
306
/* jump to first file entry... */
Mar 25, 2002
Mar 25, 2002
307
BAIL_IF_MACRO(!__PHYSFS_platformSeek(fh, 16), NULL, NULL);
308
309
310
for (i = 0; i < g->totalEntries; i++)
{
Mar 25, 2002
Mar 25, 2002
311
BAIL_IF_MACRO(__PHYSFS_platformRead(fh, buf, 16, 1) != 1, NULL, retval);
312
313
314
315
buf[12] = '\0'; /* FILENAME.EXT is all you get. */
l = (LinkedStringList *) malloc(sizeof (LinkedStringList));
Jul 16, 2001
Jul 16, 2001
316
if (l == NULL)
317
318
break;
Apr 1, 2002
Apr 1, 2002
319
l->str = (char *) malloc(strlen((const char *) buf) + 1);
320
321
322
323
324
325
if (l->str == NULL)
{
free(l);
break;
} /* if */
Apr 1, 2002
Apr 1, 2002
326
strcpy(l->str, (const char *) buf);
Jul 16, 2001
Jul 16, 2001
327
328
329
330
331
332
333
334
335
336
337
338
339
340
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
341
static PHYSFS_sint32 getFileEntry(DirHandle *h, const char *name,
Apr 1, 2002
Apr 1, 2002
342
PHYSFS_uint32 *size)
Mar 25, 2002
Mar 25, 2002
344
PHYSFS_uint8 buf[16];
345
GRPinfo *g = (GRPinfo *) (h->opaque);
Mar 25, 2002
Mar 25, 2002
346
void *fh = g->handle;
Apr 3, 2002
Apr 3, 2002
347
PHYSFS_uint32 i;
348
char *ptr;
Jul 9, 2001
Jul 9, 2001
349
int retval = (g->totalEntries + 1) * 16; /* offset of raw file data */
350
351
352
353
354
355
356
357
358
359
360
361
/* 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
362
363
/* jump to first file entry... */
BAIL_IF_MACRO(!__PHYSFS_platformSeek(fh, 16), NULL, -1);
364
365
366
for (i = 0; i < g->totalEntries; i++)
{
Mar 24, 2002
Mar 24, 2002
367
PHYSFS_sint32 l = 0;
Mar 25, 2002
Mar 25, 2002
369
370
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
371
l = PHYSFS_swapSLE32(l);
372
373
374
buf[12] = '\0'; /* FILENAME.EXT is all you get. */
Apr 1, 2002
Apr 1, 2002
375
if (__PHYSFS_platformStricmp((const char *) buf, name) == 0)
376
377
{
if (size != NULL)
Mar 24, 2002
Mar 24, 2002
378
*size = l;
379
380
381
return(retval);
} /* if */
Mar 24, 2002
Mar 24, 2002
382
retval += l;
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
} /* 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
409
const char *filename = ((GRPinfo *) h->opaque)->filename;
410
411
FileHandle *retval;
GRPfileinfo *finfo;
Mar 25, 2002
Mar 25, 2002
412
PHYSFS_uint32 size;
Mar 24, 2002
Mar 24, 2002
413
PHYSFS_sint32 offset;
414
415
416
417
418
419
420
421
422
423
424
425
426
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
427
428
429
430
431
432
433
434
435
finfo->handle = __PHYSFS_platformOpenRead(filename);
if ( (finfo->handle == NULL) ||
(!__PHYSFS_platformSeek(finfo->handle, offset)) )
{
free(finfo);
free(retval);
return(NULL);
} /* if */
436
437
438
439
440
441
442
443
finfo->startPos = offset;
finfo->size = size;
retval->opaque = (void *) finfo;
retval->funcs = &__PHYSFS_FileFunctions_GRP;
retval->dirHandle = h;
return(retval);
} /* GRP_openRead */
May 10, 2002
May 10, 2002
444
445
#endif /* defined PHYSFS_SUPPORTS_GRP */
446
/* end of grp.c ... */