Skip to content

Latest commit

 

History

History
471 lines (366 loc) · 12.7 KB

grp.c

File metadata and controls

471 lines (366 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
/*
* 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 ...)
*
* Please see the file LICENSE in the source's root directory.
*
* This file written by Ryan C. Gordon.
*/
May 10, 2002
May 10, 2002
27
28
29
30
31
32
#if HAVE_CONFIG_H
# include <config.h>
#endif
#if (defined PHYSFS_SUPPORTS_GRP)
33
34
35
36
37
38
39
40
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "physfs.h"
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
Jul 23, 2002
Jul 23, 2002
41
42
43
typedef struct
{
char name[13];
Aug 28, 2002
Aug 28, 2002
44
45
PHYSFS_uint32 startPos;
PHYSFS_uint32 size;
Jul 23, 2002
Jul 23, 2002
46
47
} GRPentry;
48
49
typedef struct
{
Mar 25, 2002
Mar 25, 2002
50
char *filename;
Jul 23, 2002
Jul 23, 2002
51
52
53
PHYSFS_sint64 last_mod_time;
PHYSFS_uint32 entryCount;
GRPentry *entries;
54
55
56
57
} GRPinfo;
typedef struct
{
Mar 25, 2002
Mar 25, 2002
58
void *handle;
Jul 23, 2002
Jul 23, 2002
59
GRPentry *entry;
Aug 28, 2002
Aug 28, 2002
60
PHYSFS_uint32 curPos;
61
62
63
} GRPfileinfo;
Sep 26, 2004
Sep 26, 2004
64
static void GRP_dirClose(dvoid *opaque)
Sep 2, 2001
Sep 2, 2001
65
{
Sep 26, 2004
Sep 26, 2004
66
GRPinfo *info = ((GRPinfo *) opaque);
Mar 14, 2005
Mar 14, 2005
67
68
69
allocator.Free(info->filename);
allocator.Free(info->entries);
allocator.Free(info);
Sep 2, 2001
Sep 2, 2001
70
} /* GRP_dirClose */
Sep 26, 2004
Sep 26, 2004
73
static PHYSFS_sint64 GRP_read(fvoid *opaque, void *buffer,
Mar 24, 2002
Mar 24, 2002
74
PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
Sep 26, 2004
Sep 26, 2004
76
GRPfileinfo *finfo = (GRPfileinfo *) opaque;
Jul 23, 2002
Jul 23, 2002
77
GRPentry *entry = finfo->entry;
Aug 28, 2002
Aug 28, 2002
78
79
PHYSFS_uint32 bytesLeft = entry->size - finfo->curPos;
PHYSFS_uint32 objsLeft = (bytesLeft / objSize);
Jul 23, 2002
Jul 23, 2002
80
PHYSFS_sint64 rc;
81
82
if (objsLeft < objCount)
Aug 28, 2002
Aug 28, 2002
83
objCount = objsLeft;
Jul 23, 2002
Jul 23, 2002
85
86
rc = __PHYSFS_platformRead(finfo->handle, buffer, objSize, objCount);
if (rc > 0)
Aug 28, 2002
Aug 28, 2002
87
finfo->curPos += (PHYSFS_uint32) (rc * objSize);
Jul 23, 2002
Jul 23, 2002
88
89
return(rc);
90
91
92
} /* GRP_read */
Sep 26, 2004
Sep 26, 2004
93
static PHYSFS_sint64 GRP_write(fvoid *opaque, const void *buffer,
Aug 21, 2002
Aug 21, 2002
94
95
96
97
98
99
PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
} /* GRP_write */
Sep 26, 2004
Sep 26, 2004
100
static int GRP_eof(fvoid *opaque)
Sep 26, 2004
Sep 26, 2004
102
GRPfileinfo *finfo = (GRPfileinfo *) opaque;
Jul 23, 2002
Jul 23, 2002
103
GRPentry *entry = finfo->entry;
Aug 28, 2002
Aug 28, 2002
104
return(finfo->curPos >= entry->size);
105
106
107
} /* GRP_eof */
Sep 26, 2004
Sep 26, 2004
108
static PHYSFS_sint64 GRP_tell(fvoid *opaque)
Sep 26, 2004
Sep 26, 2004
110
return(((GRPfileinfo *) opaque)->curPos);
111
112
113
} /* GRP_tell */
Sep 26, 2004
Sep 26, 2004
114
static int GRP_seek(fvoid *opaque, PHYSFS_uint64 offset)
Sep 26, 2004
Sep 26, 2004
116
GRPfileinfo *finfo = (GRPfileinfo *) opaque;
Jul 23, 2002
Jul 23, 2002
117
118
GRPentry *entry = finfo->entry;
int rc;
119
120
BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
Aug 28, 2002
Aug 28, 2002
121
122
BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
rc = __PHYSFS_platformSeek(finfo->handle, entry->startPos + offset);
Jul 23, 2002
Jul 23, 2002
123
if (rc)
Aug 28, 2002
Aug 28, 2002
124
finfo->curPos = (PHYSFS_uint32) offset;
Jul 23, 2002
Jul 23, 2002
125
126
return(rc);
127
128
129
} /* GRP_seek */
Sep 26, 2004
Sep 26, 2004
130
static PHYSFS_sint64 GRP_fileLength(fvoid *opaque)
Jul 9, 2001
Jul 9, 2001
131
{
Sep 26, 2004
Sep 26, 2004
132
GRPfileinfo *finfo = (GRPfileinfo *) opaque;
Aug 28, 2002
Aug 28, 2002
133
return((PHYSFS_sint64) finfo->entry->size);
Jul 9, 2001
Jul 9, 2001
134
135
136
} /* GRP_fileLength */
Sep 26, 2004
Sep 26, 2004
137
static int GRP_fileClose(fvoid *opaque)
Sep 26, 2004
Sep 26, 2004
139
GRPfileinfo *finfo = (GRPfileinfo *) opaque;
Jul 23, 2002
Jul 23, 2002
140
BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0);
Mar 14, 2005
Mar 14, 2005
141
allocator.Free(finfo);
142
143
144
145
return(1);
} /* GRP_fileClose */
Jul 23, 2002
Jul 23, 2002
146
147
static int grp_open(const char *filename, int forWriting,
void **fh, PHYSFS_uint32 *count)
Mar 25, 2002
Mar 25, 2002
149
PHYSFS_uint8 buf[12];
150
151
152
153
*fh = NULL;
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
Mar 25, 2002
Mar 25, 2002
154
155
*fh = __PHYSFS_platformOpenRead(filename);
BAIL_IF_MACRO(*fh == NULL, NULL, 0);
Mar 25, 2002
Mar 25, 2002
157
158
159
160
161
162
163
164
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 */
Jul 23, 2002
Jul 23, 2002
166
if (__PHYSFS_platformRead(*fh, count, sizeof (PHYSFS_uint32), 1) != 1)
Mar 25, 2002
Mar 25, 2002
167
goto openGrp_failed;
Jul 23, 2002
Jul 23, 2002
169
*count = PHYSFS_swapULE32(*count);
Apr 5, 2002
Apr 5, 2002
170
171
return(1);
Mar 25, 2002
Mar 25, 2002
172
173
174
175
176
177
178
179
openGrp_failed:
if (*fh != NULL)
__PHYSFS_platformClose(*fh);
*count = -1;
*fh = NULL;
return(0);
Jul 23, 2002
Jul 23, 2002
180
} /* grp_open */
181
182
183
184
static int GRP_isArchive(const char *filename, int forWriting)
{
Mar 25, 2002
Mar 25, 2002
185
void *fh;
Jul 23, 2002
Jul 23, 2002
186
187
PHYSFS_uint32 fileCount;
int retval = grp_open(filename, forWriting, &fh, &fileCount);
188
189
if (fh != NULL)
Mar 25, 2002
Mar 25, 2002
190
__PHYSFS_platformClose(fh);
191
192
193
194
195
return(retval);
} /* GRP_isArchive */
Aug 20, 2002
Aug 20, 2002
196
static int grp_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
Jul 23, 2002
Jul 23, 2002
197
{
Aug 20, 2002
Aug 20, 2002
198
199
200
GRPentry *a = (GRPentry *) _a;
return(strcmp(a[one].name, a[two].name));
} /* grp_entry_cmp */
Jul 23, 2002
Jul 23, 2002
201
202
Aug 20, 2002
Aug 20, 2002
203
static void grp_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
Jul 23, 2002
Jul 23, 2002
204
205
{
GRPentry tmp;
Aug 20, 2002
Aug 20, 2002
206
207
208
209
210
211
GRPentry *first = &(((GRPentry *) _a)[one]);
GRPentry *second = &(((GRPentry *) _a)[two]);
memcpy(&tmp, first, sizeof (GRPentry));
memcpy(first, second, sizeof (GRPentry));
memcpy(second, &tmp, sizeof (GRPentry));
} /* grp_entry_swap */
Jul 23, 2002
Jul 23, 2002
212
213
214
static int grp_load_entries(const char *name, int forWriting, GRPinfo *info)
Mar 25, 2002
Mar 25, 2002
216
void *fh = NULL;
Jul 23, 2002
Jul 23, 2002
217
PHYSFS_uint32 fileCount;
Jul 23, 2002
Jul 23, 2002
218
PHYSFS_uint32 location = 16; /* sizeof sig. */
Jul 23, 2002
Jul 23, 2002
219
220
221
222
223
GRPentry *entry;
char *ptr;
BAIL_IF_MACRO(!grp_open(name, forWriting, &fh, &fileCount), NULL, 0);
info->entryCount = fileCount;
Mar 14, 2005
Mar 14, 2005
224
info->entries = (GRPentry *) allocator.Malloc(sizeof(GRPentry)*fileCount);
Jul 23, 2002
Jul 23, 2002
225
226
227
228
229
230
if (info->entries == NULL)
{
__PHYSFS_platformClose(fh);
BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
} /* if */
Jul 23, 2002
Jul 23, 2002
231
232
location += (16 * fileCount);
Jul 23, 2002
Jul 23, 2002
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
for (entry = info->entries; fileCount > 0; fileCount--, entry++)
{
if (__PHYSFS_platformRead(fh, &entry->name, 12, 1) != 1)
{
__PHYSFS_platformClose(fh);
return(0);
} /* if */
entry->name[12] = '\0'; /* name isn't null-terminated in file. */
if ((ptr = strchr(entry->name, ' ')) != NULL)
*ptr = '\0'; /* trim extra spaces. */
if (__PHYSFS_platformRead(fh, &entry->size, 4, 1) != 1)
{
__PHYSFS_platformClose(fh);
return(0);
} /* if */
entry->size = PHYSFS_swapULE32(entry->size);
entry->startPos = location;
Jul 23, 2002
Jul 23, 2002
253
location += entry->size;
Jul 23, 2002
Jul 23, 2002
254
255
256
257
} /* for */
__PHYSFS_platformClose(fh);
Aug 20, 2002
Aug 20, 2002
258
259
__PHYSFS_sort(info->entries, info->entryCount,
grp_entry_cmp, grp_entry_swap);
Jul 23, 2002
Jul 23, 2002
260
261
262
263
return(1);
} /* grp_load_entries */
Sep 26, 2004
Sep 26, 2004
264
static void *GRP_openArchive(const char *name, int forWriting)
Jul 23, 2002
Jul 23, 2002
265
266
{
PHYSFS_sint64 modtime = __PHYSFS_platformGetLastModTime(name);
Mar 14, 2005
Mar 14, 2005
267
GRPinfo *info = (GRPinfo *) allocator.Malloc(sizeof (GRPinfo));
Sep 26, 2004
Sep 26, 2004
269
BAIL_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, 0);
Jul 23, 2002
Jul 23, 2002
271
memset(info, '\0', sizeof (GRPinfo));
Mar 14, 2005
Mar 14, 2005
272
info->filename = (char *) allocator.Malloc(strlen(name) + 1);
Mar 13, 2005
Mar 13, 2005
273
GOTO_IF_MACRO(!info->filename, ERR_OUT_OF_MEMORY, GRP_openArchive_failed);
Jul 23, 2002
Jul 23, 2002
275
if (!grp_load_entries(name, forWriting, info))
Mar 25, 2002
Mar 25, 2002
276
277
goto GRP_openArchive_failed;
Jul 23, 2002
Jul 23, 2002
278
279
strcpy(info->filename, name);
info->last_mod_time = modtime;
Sep 26, 2004
Sep 26, 2004
280
281
return(info);
Mar 25, 2002
Mar 25, 2002
282
283
GRP_openArchive_failed:
Sep 26, 2004
Sep 26, 2004
284
if (info != NULL)
Mar 25, 2002
Mar 25, 2002
285
{
Sep 26, 2004
Sep 26, 2004
286
if (info->filename != NULL)
Mar 14, 2005
Mar 14, 2005
287
allocator.Free(info->filename);
Sep 26, 2004
Sep 26, 2004
288
if (info->entries != NULL)
Mar 14, 2005
Mar 14, 2005
289
290
allocator.Free(info->entries);
allocator.Free(info);
Mar 25, 2002
Mar 25, 2002
291
292
293
} /* if */
return(NULL);
294
295
296
} /* GRP_openArchive */
Sep 29, 2004
Sep 29, 2004
297
static void GRP_enumerateFiles(dvoid *opaque, const char *dname,
Sep 18, 2005
Sep 18, 2005
298
299
int omitSymLinks, PHYSFS_EnumFilesCallback cb,
const char *origdir, void *callbackdata)
Jul 23, 2002
Jul 23, 2002
301
/* no directories in GRP files. */
Sep 29, 2004
Sep 29, 2004
302
303
304
305
306
307
if (*dname != '\0')
{
GRPinfo *info = (GRPinfo *) opaque;
GRPentry *entry = info->entries;
PHYSFS_uint32 max = info->entryCount;
PHYSFS_uint32 i;
Sep 29, 2004
Sep 29, 2004
309
for (i = 0; i < max; i++, entry++)
Sep 18, 2005
Sep 18, 2005
310
cb(callbackdata, origdir, entry->name);
Sep 29, 2004
Sep 29, 2004
311
} /* if */
312
313
314
} /* GRP_enumerateFiles */
Jul 23, 2002
Jul 23, 2002
315
static GRPentry *grp_find_entry(GRPinfo *info, const char *name)
Jul 23, 2002
Jul 23, 2002
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
char *ptr = strchr(name, '.');
GRPentry *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)
Jul 23, 2002
Jul 23, 2002
334
335
336
337
338
339
340
341
342
middle = lo + ((hi - lo) / 2);
rc = strcmp(name, a[middle].name);
if (rc == 0) /* found it! */
return(&a[middle]);
else if (rc > 0)
lo = middle + 1;
else
hi = middle - 1;
} /* while */
Jul 23, 2002
Jul 23, 2002
344
345
BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
} /* grp_find_entry */
Sep 26, 2004
Sep 26, 2004
348
static int GRP_exists(dvoid *opaque, const char *name)
Sep 26, 2004
Sep 26, 2004
350
return(grp_find_entry((GRPinfo *) opaque, name) != NULL);
351
352
353
} /* GRP_exists */
Sep 26, 2004
Sep 26, 2004
354
static int GRP_isDirectory(dvoid *opaque, const char *name, int *fileExists)
Sep 26, 2004
Sep 26, 2004
356
*fileExists = GRP_exists(opaque, name);
357
358
359
360
return(0); /* never directories in a groupfile. */
} /* GRP_isDirectory */
Sep 26, 2004
Sep 26, 2004
361
static int GRP_isSymLink(dvoid *opaque, const char *name, int *fileExists)
Sep 26, 2004
Sep 26, 2004
363
*fileExists = GRP_exists(opaque, name);
364
365
366
367
return(0); /* never symlinks in a groupfile. */
} /* GRP_isSymLink */
Sep 26, 2004
Sep 26, 2004
368
static PHYSFS_sint64 GRP_getLastModTime(dvoid *opaque,
Aug 21, 2002
Aug 21, 2002
369
370
const char *name,
int *fileExists)
Jun 6, 2002
Jun 6, 2002
371
{
Sep 26, 2004
Sep 26, 2004
372
GRPinfo *info = (GRPinfo *) opaque;
Aug 21, 2002
Aug 21, 2002
373
PHYSFS_sint64 retval = -1;
Jul 25, 2002
Jul 25, 2002
374
Aug 21, 2002
Aug 21, 2002
375
376
*fileExists = (grp_find_entry(info, name) != NULL);
if (*fileExists) /* use time of GRP itself in the physical filesystem. */
Sep 26, 2004
Sep 26, 2004
377
retval = info->last_mod_time;
Aug 21, 2002
Aug 21, 2002
378
379
return(retval);
Jun 6, 2002
Jun 6, 2002
380
381
382
} /* GRP_getLastModTime */
Sep 26, 2004
Sep 26, 2004
383
static fvoid *GRP_openRead(dvoid *opaque, const char *fnm, int *fileExists)
Sep 26, 2004
Sep 26, 2004
385
GRPinfo *info = (GRPinfo *) opaque;
386
GRPfileinfo *finfo;
Jul 23, 2002
Jul 23, 2002
387
GRPentry *entry;
Aug 21, 2002
Aug 21, 2002
389
390
entry = grp_find_entry(info, fnm);
*fileExists = (entry != NULL);
Jul 23, 2002
Jul 23, 2002
391
BAIL_IF_MACRO(entry == NULL, NULL, NULL);
Mar 14, 2005
Mar 14, 2005
393
finfo = (GRPfileinfo *) allocator.Malloc(sizeof (GRPfileinfo));
Sep 26, 2004
Sep 26, 2004
394
BAIL_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, NULL);
Jul 23, 2002
Jul 23, 2002
396
finfo->handle = __PHYSFS_platformOpenRead(info->filename);
Mar 25, 2002
Mar 25, 2002
397
if ( (finfo->handle == NULL) ||
Jul 23, 2002
Jul 23, 2002
398
(!__PHYSFS_platformSeek(finfo->handle, entry->startPos)) )
Mar 25, 2002
Mar 25, 2002
399
{
Mar 14, 2005
Mar 14, 2005
400
allocator.Free(finfo);
Mar 25, 2002
Mar 25, 2002
401
402
403
return(NULL);
} /* if */
Jul 23, 2002
Jul 23, 2002
404
405
finfo->curPos = 0;
finfo->entry = entry;
Sep 26, 2004
Sep 26, 2004
406
return(finfo);
407
408
} /* GRP_openRead */
Aug 21, 2002
Aug 21, 2002
409
Sep 26, 2004
Sep 26, 2004
410
static fvoid *GRP_openWrite(dvoid *opaque, const char *name)
Aug 21, 2002
Aug 21, 2002
411
412
413
414
415
{
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* GRP_openWrite */
Sep 26, 2004
Sep 26, 2004
416
static fvoid *GRP_openAppend(dvoid *opaque, const char *name)
Aug 21, 2002
Aug 21, 2002
417
418
419
420
421
{
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* GRP_openAppend */
Sep 26, 2004
Sep 26, 2004
422
static int GRP_remove(dvoid *opaque, const char *name)
Aug 21, 2002
Aug 21, 2002
423
424
425
426
427
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* GRP_remove */
Sep 26, 2004
Sep 26, 2004
428
static int GRP_mkdir(dvoid *opaque, const char *name)
Aug 21, 2002
Aug 21, 2002
429
430
431
432
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* GRP_mkdir */
Sep 29, 2004
Sep 29, 2004
433
434
435
436
437
const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_GRP =
{
"GRP",
GRP_ARCHIVE_DESCRIPTION,
Jan 1, 2006
Jan 1, 2006
438
"Ryan C. Gordon <icculus@icculus.org>",
Sep 29, 2004
Sep 29, 2004
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
"http://icculus.org/physfs/",
};
const PHYSFS_Archiver __PHYSFS_Archiver_GRP =
{
&__PHYSFS_ArchiveInfo_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_getLastModTime, /* getLastModTime() method */
GRP_openRead, /* openRead() method */
GRP_openWrite, /* openWrite() method */
GRP_openAppend, /* openAppend() method */
GRP_remove, /* remove() method */
GRP_mkdir, /* mkdir() method */
GRP_dirClose, /* dirClose() method */
GRP_read, /* read() method */
GRP_write, /* write() method */
GRP_eof, /* eof() method */
GRP_tell, /* tell() method */
GRP_seek, /* seek() method */
GRP_fileLength, /* fileLength() method */
GRP_fileClose /* fileClose() method */
};
May 10, 2002
May 10, 2002
468
469
#endif /* defined PHYSFS_SUPPORTS_GRP */
470
/* end of grp.c ... */