1 | /* |
2 | * GRP support routines for PhysicsFS. |
3 | * |
4 | * This driver handles BUILD engine archives ("groupfiles"). This format |
5 | * (but not this driver) was put together by Ken Silverman. |
6 | * |
7 | * The format is simple enough. In Ken's words: |
8 | * |
9 | * What's the .GRP file format? |
10 | * |
11 | * The ".grp" file format is just a collection of a lot of files stored |
12 | * into 1 big one. I tried to make the format as simple as possible: The |
13 | * first 12 bytes contains my name, "KenSilverman". The next 4 bytes is |
14 | * the number of files that were compacted into the group file. Then for |
15 | * each file, there is a 16 byte structure, where the first 12 bytes are |
16 | * the filename, and the last 4 bytes are the file's size. The rest of |
17 | * the group file is just the raw data packed one after the other in the |
18 | * same order as the list of files. |
19 | * |
20 | * (That info is from http://www.advsys.net/ken/build.htm ...) |
21 | * |
22 | * Please see the file LICENSE.txt in the source's root directory. |
23 | * |
24 | * This file written by Ryan C. Gordon. |
25 | */ |
26 | |
27 | #define __PHYSICSFS_INTERNAL__ |
28 | #include "physfs_internal.h" |
29 | |
30 | #if PHYSFS_SUPPORTS_GRP |
31 | |
32 | static int grpLoadEntries(PHYSFS_Io *io, const PHYSFS_uint32 count, void *arc) |
33 | { |
34 | PHYSFS_uint32 pos = 16 + (16 * count); /* past sig+metadata. */ |
35 | PHYSFS_uint32 i; |
36 | |
37 | for (i = 0; i < count; i++) |
38 | { |
39 | char *ptr; |
40 | char name[13]; |
41 | PHYSFS_uint32 size; |
42 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, name, 12), 0); |
43 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &size, 4), 0); |
44 | |
45 | name[12] = '\0'; /* name isn't null-terminated in file. */ |
46 | if ((ptr = strchr(name, ' ')) != NULL) |
47 | *ptr = '\0'; /* trim extra spaces. */ |
48 | |
49 | size = PHYSFS_swapULE32(size); |
50 | BAIL_IF_ERRPASS(!UNPK_addEntry(arc, name, 0, -1, -1, pos, size), 0); |
51 | |
52 | pos += size; |
53 | } /* for */ |
54 | |
55 | return 1; |
56 | } /* grpLoadEntries */ |
57 | |
58 | |
59 | static void *GRP_openArchive(PHYSFS_Io *io, const char *name, |
60 | int forWriting, int *claimed) |
61 | { |
62 | PHYSFS_uint8 buf[12]; |
63 | PHYSFS_uint32 count = 0; |
64 | void *unpkarc = NULL; |
65 | |
66 | assert(io != NULL); /* shouldn't ever happen. */ |
67 | |
68 | BAIL_IF(forWriting, PHYSFS_ERR_READ_ONLY, NULL); |
69 | |
70 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, buf, sizeof (buf)), NULL); |
71 | if (memcmp(buf, "KenSilverman" , sizeof (buf)) != 0) |
72 | BAIL(PHYSFS_ERR_UNSUPPORTED, NULL); |
73 | |
74 | *claimed = 1; |
75 | |
76 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &count, sizeof(count)), NULL); |
77 | count = PHYSFS_swapULE32(count); |
78 | |
79 | unpkarc = UNPK_openArchive(io, 0, 1); |
80 | BAIL_IF_ERRPASS(!unpkarc, NULL); |
81 | |
82 | if (!grpLoadEntries(io, count, unpkarc)) |
83 | { |
84 | UNPK_abandonArchive(unpkarc); |
85 | return NULL; |
86 | } /* if */ |
87 | |
88 | return unpkarc; |
89 | } /* GRP_openArchive */ |
90 | |
91 | |
92 | const PHYSFS_Archiver __PHYSFS_Archiver_GRP = |
93 | { |
94 | CURRENT_PHYSFS_ARCHIVER_API_VERSION, |
95 | { |
96 | "GRP" , |
97 | "Build engine Groupfile format" , |
98 | "Ryan C. Gordon <icculus@icculus.org>" , |
99 | "https://icculus.org/physfs/" , |
100 | 0, /* supportsSymlinks */ |
101 | }, |
102 | GRP_openArchive, |
103 | UNPK_enumerate, |
104 | UNPK_openRead, |
105 | UNPK_openWrite, |
106 | UNPK_openAppend, |
107 | UNPK_remove, |
108 | UNPK_mkdir, |
109 | UNPK_stat, |
110 | UNPK_closeArchive |
111 | }; |
112 | |
113 | #endif /* defined PHYSFS_SUPPORTS_GRP */ |
114 | |
115 | /* end of physfs_archiver_grp.c ... */ |
116 | |
117 | |