Skip to content

Latest commit

 

History

History
1730 lines (1398 loc) · 53 KB

archiver_zip.c

File metadata and controls

1730 lines (1398 loc) · 53 KB
 
Jul 7, 2001
Jul 7, 2001
1
2
3
/*
* ZIP support routines for PhysicsFS.
*
Mar 11, 2007
Mar 11, 2007
4
* Please see the file LICENSE.txt in the source's root directory.
Jul 7, 2001
Jul 7, 2001
5
*
Jul 13, 2002
Jul 13, 2002
6
7
* This file written by Ryan C. Gordon, with some peeking at "unzip.c"
* by Gilles Vollant.
Jul 7, 2001
Jul 7, 2001
8
9
*/
Mar 23, 2012
Mar 23, 2012
10
11
12
13
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
#if PHYSFS_SUPPORTS_ZIP
May 10, 2002
May 10, 2002
14
Jul 13, 2002
Jul 13, 2002
15
#include <errno.h>
Nov 22, 2002
Nov 22, 2002
16
#include <time.h>
Sep 6, 2010
Sep 6, 2010
17
Mar 10, 2012
Mar 10, 2012
18
19
#include "physfs_miniz.h"
Jul 13, 2002
Jul 13, 2002
20
/*
Mar 14, 2005
Mar 14, 2005
21
22
* A buffer of ZIP_READBUFSIZE is allocated for each compressed file opened,
* and is freed when you close the file; compressed data is read into
Jul 13, 2002
Jul 13, 2002
23
24
25
26
27
28
29
30
31
32
33
* this buffer, and then is decompressed into the buffer passed to
* PHYSFS_read().
*
* Uncompressed entries in a zipfile do not allocate this buffer; they just
* read data directly into the buffer passed to PHYSFS_read().
*
* Depending on your speed and memory requirements, you should tweak this
* value.
*/
#define ZIP_READBUFSIZE (16 * 1024)
Jul 23, 2002
Jul 23, 2002
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/*
* Entries are "unresolved" until they are first opened. At that time,
* local file headers parsed/validated, data offsets will be updated to look
* at the actual file data instead of the header, and symlinks will be
* followed and optimized. This means that we don't seek and read around the
* archive until forced to do so, and after the first time, we had to do
* less reading and parsing, which is very CD-ROM friendly.
*/
typedef enum
{
ZIP_UNRESOLVED_FILE,
ZIP_UNRESOLVED_SYMLINK,
ZIP_RESOLVING,
ZIP_RESOLVED,
Feb 25, 2016
Feb 25, 2016
49
ZIP_DIRECTORY,
Jul 23, 2002
Jul 23, 2002
50
ZIP_BROKEN_FILE,
Jan 31, 2003
Jan 31, 2003
51
ZIP_BROKEN_SYMLINK
Jul 23, 2002
Jul 23, 2002
52
53
54
} ZipResolveType;
Jul 13, 2002
Jul 13, 2002
55
56
57
/*
* One ZIPentry is kept for each file in an open ZIP archive.
*/
Jul 23, 2002
Jul 23, 2002
58
typedef struct _ZIPentry
Jul 15, 2001
Jul 15, 2001
59
{
Jul 23, 2002
Jul 23, 2002
60
61
62
char *name; /* Name of file in archive */
struct _ZIPentry *symlink; /* NULL or file we symlink to */
ZipResolveType resolved; /* Have we resolved file/symlink? */
Jun 1, 2012
Jun 1, 2012
63
PHYSFS_uint64 offset; /* offset of data in archive */
Jul 23, 2002
Jul 23, 2002
64
65
66
67
PHYSFS_uint16 version; /* version made by */
PHYSFS_uint16 version_needed; /* version needed to extract */
PHYSFS_uint16 compression_method; /* compression method */
PHYSFS_uint32 crc; /* crc-32 */
Jun 1, 2012
Jun 1, 2012
68
69
PHYSFS_uint64 compressed_size; /* compressed size */
PHYSFS_uint64 uncompressed_size; /* uncompressed size */
Jul 23, 2002
Jul 23, 2002
70
PHYSFS_sint64 last_mod_time; /* last file mod time */
Feb 25, 2016
Feb 25, 2016
71
72
73
struct _ZIPentry *hashnext; /* next item in this hash bucket */
struct _ZIPentry *children; /* linked list of kids, if dir */
struct _ZIPentry *sibling; /* next item in same dir */
Jul 28, 2001
Jul 28, 2001
74
75
} ZIPentry;
Jul 13, 2002
Jul 13, 2002
76
77
78
/*
* One ZIPinfo is kept for each open ZIP archive.
*/
Jul 28, 2001
Jul 28, 2001
79
80
typedef struct
{
Feb 24, 2016
Feb 24, 2016
81
PHYSFS_Io *io; /* the i/o interface for this archive. */
Feb 25, 2016
Feb 25, 2016
82
83
84
ZIPentry root; /* root of directory tree. */
ZIPentry **hash; /* all entries hashed for fast lookup. */
size_t hashBuckets; /* number of buckets in hash. */
Jun 1, 2012
Jun 1, 2012
85
int zip64; /* non-zero if this is a Zip64 archive. */
Jul 15, 2001
Jul 15, 2001
86
87
} ZIPinfo;
Jul 13, 2002
Jul 13, 2002
88
89
90
/*
* One ZIPfileinfo is kept for each open file in a ZIP archive.
*/
Jul 15, 2001
Jul 15, 2001
91
92
typedef struct
{
Jul 13, 2002
Jul 13, 2002
93
ZIPentry *entry; /* Info on file. */
Aug 30, 2010
Aug 30, 2010
94
PHYSFS_Io *io; /* physical file handle. */
Jul 13, 2002
Jul 13, 2002
95
96
97
98
PHYSFS_uint32 compressed_position; /* offset in compressed data. */
PHYSFS_uint32 uncompressed_position; /* tell() position. */
PHYSFS_uint8 *buffer; /* decompression buffer. */
z_stream stream; /* zlib stream state. */
Jul 15, 2001
Jul 15, 2001
99
100
101
} ZIPfileinfo;
Jul 13, 2002
Jul 13, 2002
102
/* Magic numbers... */
Jun 1, 2012
Jun 1, 2012
103
104
105
106
107
108
#define ZIP_LOCAL_FILE_SIG 0x04034b50
#define ZIP_CENTRAL_DIR_SIG 0x02014b50
#define ZIP_END_OF_CENTRAL_DIR_SIG 0x06054b50
#define ZIP64_END_OF_CENTRAL_DIR_SIG 0x06064b50
#define ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIG 0x07064b50
#define ZIP64_EXTENDED_INFO_EXTRA_FIELD_SIG 0x0001
Jul 13, 2002
Jul 13, 2002
109
110
111
112
113
114
/* compression methods... */
#define COMPMETH_NONE 0
/* ...and others... */
Jul 15, 2002
Jul 15, 2002
115
116
117
118
#define UNIX_FILETYPE_MASK 0170000
#define UNIX_FILETYPE_SYMLINK 0120000
Sep 23, 2004
Sep 23, 2004
119
120
121
122
123
/*
* Bridge physfs allocation functions to zlib's format...
*/
static voidpf zlibPhysfsAlloc(voidpf opaque, uInt items, uInt size)
{
Jan 28, 2010
Jan 28, 2010
124
return ((PHYSFS_Allocator *) opaque)->Malloc(items * size);
Sep 23, 2004
Sep 23, 2004
125
126
127
128
129
130
131
} /* zlibPhysfsAlloc */
/*
* Bridge physfs allocation functions to zlib's format...
*/
static void zlibPhysfsFree(voidpf opaque, voidpf address)
{
Mar 14, 2005
Mar 14, 2005
132
((PHYSFS_Allocator *) opaque)->Free(address);
Sep 23, 2004
Sep 23, 2004
133
134
135
136
137
138
139
140
141
142
143
} /* zlibPhysfsFree */
/*
* Construct a new z_stream to a sane state.
*/
static void initializeZStream(z_stream *pstr)
{
memset(pstr, '\0', sizeof (z_stream));
pstr->zalloc = zlibPhysfsAlloc;
pstr->zfree = zlibPhysfsFree;
Mar 14, 2005
Mar 14, 2005
144
pstr->opaque = &allocator;
Sep 23, 2004
Sep 23, 2004
145
146
147
} /* initializeZStream */
Mar 20, 2012
Mar 20, 2012
148
static PHYSFS_ErrorCode zlib_error_code(int rc)
Jul 13, 2002
Jul 13, 2002
149
150
151
{
switch (rc)
{
Mar 20, 2012
Mar 20, 2012
152
153
154
155
156
case Z_OK: return PHYSFS_ERR_OK; /* not an error. */
case Z_STREAM_END: return PHYSFS_ERR_OK; /* not an error. */
case Z_ERRNO: return PHYSFS_ERR_IO;
case Z_MEM_ERROR: return PHYSFS_ERR_OUT_OF_MEMORY;
default: return PHYSFS_ERR_CORRUPT;
Jul 13, 2002
Jul 13, 2002
157
} /* switch */
Jul 28, 2002
Jul 28, 2002
158
159
} /* zlib_error_string */
Jul 13, 2002
Jul 13, 2002
160
Jul 28, 2002
Jul 28, 2002
161
162
163
/*
* Wrap all zlib calls in this, so the physfs error state is set appropriately.
*/
Mar 20, 2012
Mar 20, 2012
164
static int zlib_err(const int rc)
Jul 28, 2002
Jul 28, 2002
165
{
Nov 30, 2012
Nov 30, 2012
166
PHYSFS_setErrorCode(zlib_error_code(rc));
Jan 28, 2010
Jan 28, 2010
167
return rc;
Jul 13, 2002
Jul 13, 2002
168
169
} /* zlib_err */
Feb 25, 2016
Feb 25, 2016
170
171
172
173
174
175
176
/*
* Hash a string for lookup an a ZIPinfo hashtable.
*/
static inline PHYSFS_uint32 zip_hash_string(const ZIPinfo *info, const char *s)
{
return __PHYSFS_hashString(s, strlen(s)) % info->hashBuckets;
} /* zip_hash_string */
Jul 13, 2002
Jul 13, 2002
177
Jun 1, 2012
Jun 1, 2012
178
179
180
181
182
183
184
185
186
187
188
/*
* Read an unsigned 64-bit int and swap to native byte order.
*/
static int readui64(PHYSFS_Io *io, PHYSFS_uint64 *val)
{
PHYSFS_uint64 v;
BAIL_IF_MACRO(!__PHYSFS_readAll(io, &v, sizeof (v)), ERRPASS, 0);
*val = PHYSFS_swapULE64(v);
return 1;
} /* readui64 */
Jul 13, 2002
Jul 13, 2002
189
190
191
/*
* Read an unsigned 32-bit int and swap to native byte order.
*/
Aug 30, 2010
Aug 30, 2010
192
static int readui32(PHYSFS_Io *io, PHYSFS_uint32 *val)
Jul 13, 2002
Jul 13, 2002
193
194
{
PHYSFS_uint32 v;
Mar 20, 2012
Mar 20, 2012
195
BAIL_IF_MACRO(!__PHYSFS_readAll(io, &v, sizeof (v)), ERRPASS, 0);
Jul 13, 2002
Jul 13, 2002
196
*val = PHYSFS_swapULE32(v);
Jan 28, 2010
Jan 28, 2010
197
return 1;
Jul 13, 2002
Jul 13, 2002
198
199
200
201
202
203
} /* readui32 */
/*
* Read an unsigned 16-bit int and swap to native byte order.
*/
Aug 30, 2010
Aug 30, 2010
204
static int readui16(PHYSFS_Io *io, PHYSFS_uint16 *val)
Jul 13, 2002
Jul 13, 2002
205
206
{
PHYSFS_uint16 v;
Mar 20, 2012
Mar 20, 2012
207
BAIL_IF_MACRO(!__PHYSFS_readAll(io, &v, sizeof (v)), ERRPASS, 0);
Jul 13, 2002
Jul 13, 2002
208
*val = PHYSFS_swapULE16(v);
Jan 28, 2010
Jan 28, 2010
209
return 1;
Jul 13, 2002
Jul 13, 2002
210
211
212
} /* readui16 */
Aug 30, 2010
Aug 30, 2010
213
static PHYSFS_sint64 ZIP_read(PHYSFS_Io *_io, void *buf, PHYSFS_uint64 len)
Jul 8, 2001
Jul 8, 2001
214
{
Aug 30, 2010
Aug 30, 2010
215
216
ZIPfileinfo *finfo = (ZIPfileinfo *) _io->opaque;
PHYSFS_Io *io = finfo->io;
Jul 13, 2002
Jul 13, 2002
217
218
ZIPentry *entry = finfo->entry;
PHYSFS_sint64 retval = 0;
Aug 21, 2010
Aug 21, 2010
219
PHYSFS_sint64 maxread = (PHYSFS_sint64) len;
Jul 13, 2002
Jul 13, 2002
220
221
222
223
PHYSFS_sint64 avail = entry->uncompressed_size -
finfo->uncompressed_position;
if (avail < maxread)
Aug 21, 2010
Aug 21, 2010
224
maxread = avail;
Jul 13, 2002
Jul 13, 2002
225
Mar 20, 2012
Mar 20, 2012
226
BAIL_IF_MACRO(maxread == 0, ERRPASS, 0); /* quick rejection. */
Jul 13, 2002
Jul 13, 2002
227
Aug 21, 2010
Aug 21, 2010
228
if (entry->compression_method == COMPMETH_NONE)
Aug 30, 2010
Aug 30, 2010
229
retval = io->read(io, buf, maxread);
Jul 13, 2002
Jul 13, 2002
230
231
232
else
{
finfo->stream.next_out = buf;
Mar 10, 2012
Mar 10, 2012
233
finfo->stream.avail_out = (uInt) maxread;
Jul 13, 2002
Jul 13, 2002
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
while (retval < maxread)
{
PHYSFS_uint32 before = finfo->stream.total_out;
int rc;
if (finfo->stream.avail_in == 0)
{
PHYSFS_sint64 br;
br = entry->compressed_size - finfo->compressed_position;
if (br > 0)
{
if (br > ZIP_READBUFSIZE)
br = ZIP_READBUFSIZE;
Aug 30, 2010
Aug 30, 2010
250
br = io->read(io, finfo->buffer, (PHYSFS_uint64) br);
Jul 13, 2002
Jul 13, 2002
251
252
253
if (br <= 0)
break;
Mar 12, 2003
Mar 12, 2003
254
finfo->compressed_position += (PHYSFS_uint32) br;
Jul 13, 2002
Jul 13, 2002
255
finfo->stream.next_in = finfo->buffer;
Mar 12, 2003
Mar 12, 2003
256
finfo->stream.avail_in = (PHYSFS_uint32) br;
Jul 13, 2002
Jul 13, 2002
257
258
} /* if */
} /* if */
Jul 23, 2001
Jul 23, 2001
259
Jul 13, 2002
Jul 13, 2002
260
261
rc = zlib_err(inflate(&finfo->stream, Z_SYNC_FLUSH));
retval += (finfo->stream.total_out - before);
Jul 23, 2001
Jul 23, 2001
262
Jul 13, 2002
Jul 13, 2002
263
264
265
266
267
268
if (rc != Z_OK)
break;
} /* while */
} /* else */
if (retval > 0)
Aug 21, 2010
Aug 21, 2010
269
finfo->uncompressed_position += (PHYSFS_uint32) retval;
Jul 13, 2002
Jul 13, 2002
270
Jan 28, 2010
Jan 28, 2010
271
return retval;
Jul 8, 2001
Jul 8, 2001
272
273
274
} /* ZIP_read */
Aug 30, 2010
Aug 30, 2010
275
static PHYSFS_sint64 ZIP_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
Aug 21, 2002
Aug 21, 2002
276
{
Mar 22, 2012
Mar 22, 2012
277
BAIL_MACRO(PHYSFS_ERR_READ_ONLY, -1);
Aug 21, 2002
Aug 21, 2002
278
279
280
} /* ZIP_write */
Aug 30, 2010
Aug 30, 2010
281
static PHYSFS_sint64 ZIP_tell(PHYSFS_Io *io)
Jul 8, 2001
Jul 8, 2001
282
{
Aug 30, 2010
Aug 30, 2010
283
return ((ZIPfileinfo *) io->opaque)->uncompressed_position;
Jul 8, 2001
Jul 8, 2001
284
285
286
} /* ZIP_tell */
Aug 30, 2010
Aug 30, 2010
287
static int ZIP_seek(PHYSFS_Io *_io, PHYSFS_uint64 offset)
Jul 8, 2001
Jul 8, 2001
288
{
Aug 30, 2010
Aug 30, 2010
289
ZIPfileinfo *finfo = (ZIPfileinfo *) _io->opaque;
Jul 13, 2002
Jul 13, 2002
290
ZIPentry *entry = finfo->entry;
Aug 30, 2010
Aug 30, 2010
291
PHYSFS_Io *io = finfo->io;
Jul 23, 2001
Jul 23, 2001
292
Mar 20, 2012
Mar 20, 2012
293
BAIL_IF_MACRO(offset > entry->uncompressed_size, PHYSFS_ERR_PAST_EOF, 0);
Jul 23, 2001
Jul 23, 2001
294
Jul 13, 2002
Jul 13, 2002
295
if (entry->compression_method == COMPMETH_NONE)
Jul 23, 2001
Jul 23, 2001
296
{
Aug 30, 2010
Aug 30, 2010
297
const PHYSFS_sint64 newpos = offset + entry->offset;
Mar 20, 2012
Mar 20, 2012
298
BAIL_IF_MACRO(!io->seek(io, newpos), ERRPASS, 0);
Mar 30, 2003
Mar 30, 2003
299
finfo->uncompressed_position = (PHYSFS_uint32) offset;
Jul 13, 2002
Jul 13, 2002
300
} /* if */
Jul 23, 2001
Jul 23, 2001
301
Jul 13, 2002
Jul 13, 2002
302
else
Jul 23, 2001
Jul 23, 2001
303
{
Jul 13, 2002
Jul 13, 2002
304
305
306
307
/*
* If seeking backwards, we need to redecode the file
* from the start and throw away the compressed bits until we hit
* the offset we need. If seeking forward, we still need to
Jul 23, 2002
Jul 23, 2002
308
* decode, but we don't rewind first.
Jul 13, 2002
Jul 13, 2002
309
310
311
312
313
*/
if (offset < finfo->uncompressed_position)
{
/* we do a copy so state is sane if inflateInit2() fails. */
z_stream str;
Sep 23, 2004
Sep 23, 2004
314
initializeZStream(&str);
Jul 13, 2002
Jul 13, 2002
315
if (zlib_err(inflateInit2(&str, -MAX_WBITS)) != Z_OK)
Jan 28, 2010
Jan 28, 2010
316
return 0;
Jul 13, 2002
Jul 13, 2002
317
Aug 30, 2010
Aug 30, 2010
318
if (!io->seek(io, entry->offset))
Jan 28, 2010
Jan 28, 2010
319
return 0;
Jul 17, 2002
Jul 17, 2002
320
Jul 13, 2002
Jul 13, 2002
321
322
323
324
325
326
327
328
inflateEnd(&finfo->stream);
memcpy(&finfo->stream, &str, sizeof (z_stream));
finfo->uncompressed_position = finfo->compressed_position = 0;
} /* if */
while (finfo->uncompressed_position != offset)
{
PHYSFS_uint8 buf[512];
Mar 12, 2003
Mar 12, 2003
329
330
331
PHYSFS_uint32 maxread;
maxread = (PHYSFS_uint32) (offset - finfo->uncompressed_position);
Jul 13, 2002
Jul 13, 2002
332
333
334
if (maxread > sizeof (buf))
maxread = sizeof (buf);
Aug 30, 2010
Aug 30, 2010
335
if (ZIP_read(_io, buf, maxread) != maxread)
Jan 28, 2010
Jan 28, 2010
336
return 0;
Jul 13, 2002
Jul 13, 2002
337
338
339
} /* while */
} /* else */
Jan 28, 2010
Jan 28, 2010
340
return 1;
Jul 8, 2001
Jul 8, 2001
341
342
343
} /* ZIP_seek */
Aug 30, 2010
Aug 30, 2010
344
static PHYSFS_sint64 ZIP_length(PHYSFS_Io *io)
Jul 9, 2001
Jul 9, 2001
345
{
Aug 30, 2010
Aug 30, 2010
346
const ZIPfileinfo *finfo = (ZIPfileinfo *) io->opaque;
Jun 1, 2012
Jun 1, 2012
347
return (PHYSFS_sint64) finfo->entry->uncompressed_size;
Aug 30, 2010
Aug 30, 2010
348
} /* ZIP_length */
Jul 9, 2001
Jul 9, 2001
349
350
Aug 30, 2010
Aug 30, 2010
351
352
353
static PHYSFS_Io *zip_get_io(PHYSFS_Io *io, ZIPinfo *inf, ZIPentry *entry);
static PHYSFS_Io *ZIP_duplicate(PHYSFS_Io *io)
Jul 8, 2001
Jul 8, 2001
354
{
Aug 30, 2010
Aug 30, 2010
355
356
357
ZIPfileinfo *origfinfo = (ZIPfileinfo *) io->opaque;
PHYSFS_Io *retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
ZIPfileinfo *finfo = (ZIPfileinfo *) allocator.Malloc(sizeof (ZIPfileinfo));
Mar 24, 2012
Mar 24, 2012
358
359
GOTO_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, failed);
GOTO_IF_MACRO(!finfo, PHYSFS_ERR_OUT_OF_MEMORY, failed);
Aug 30, 2010
Aug 30, 2010
360
361
362
363
memset(finfo, '\0', sizeof (*finfo));
finfo->entry = origfinfo->entry;
finfo->io = zip_get_io(origfinfo->io, NULL, finfo->entry);
Mar 24, 2012
Mar 24, 2012
364
GOTO_IF_MACRO(!finfo->io, ERRPASS, failed);
Aug 30, 2010
Aug 30, 2010
365
366
367
368
if (finfo->entry->compression_method != COMPMETH_NONE)
{
finfo->buffer = (PHYSFS_uint8 *) allocator.Malloc(ZIP_READBUFSIZE);
Mar 24, 2012
Mar 24, 2012
369
370
371
GOTO_IF_MACRO(!finfo->buffer, PHYSFS_ERR_OUT_OF_MEMORY, failed);
if (zlib_err(inflateInit2(&finfo->stream, -MAX_WBITS)) != Z_OK)
goto failed;
Aug 30, 2010
Aug 30, 2010
372
373
374
375
376
377
} /* if */
memcpy(retval, io, sizeof (PHYSFS_Io));
retval->opaque = finfo;
return retval;
Mar 24, 2012
Mar 24, 2012
378
failed:
Aug 30, 2010
Aug 30, 2010
379
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
if (finfo != NULL)
{
if (finfo->io != NULL)
finfo->io->destroy(finfo->io);
if (finfo->buffer != NULL)
{
allocator.Free(finfo->buffer);
inflateEnd(&finfo->stream);
} /* if */
allocator.Free(finfo);
} /* if */
if (retval != NULL)
allocator.Free(retval);
return NULL;
} /* ZIP_duplicate */
static int ZIP_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
static void ZIP_destroy(PHYSFS_Io *io)
{
ZIPfileinfo *finfo = (ZIPfileinfo *) io->opaque;
finfo->io->destroy(finfo->io);
Jul 13, 2002
Jul 13, 2002
405
406
407
408
409
if (finfo->entry->compression_method != COMPMETH_NONE)
inflateEnd(&finfo->stream);
if (finfo->buffer != NULL)
Mar 14, 2005
Mar 14, 2005
410
allocator.Free(finfo->buffer);
Jul 13, 2002
Jul 13, 2002
411
Mar 14, 2005
Mar 14, 2005
412
allocator.Free(finfo);
Aug 30, 2010
Aug 30, 2010
413
414
415
416
417
418
allocator.Free(io);
} /* ZIP_destroy */
static const PHYSFS_Io ZIP_Io =
{
Mar 25, 2012
Mar 25, 2012
419
CURRENT_PHYSFS_IO_API_VERSION, NULL,
Aug 30, 2010
Aug 30, 2010
420
421
422
423
424
425
426
ZIP_read,
ZIP_write,
ZIP_seek,
ZIP_tell,
ZIP_length,
ZIP_duplicate,
ZIP_flush,
Mar 25, 2012
Mar 25, 2012
427
ZIP_destroy
Aug 30, 2010
Aug 30, 2010
428
429
};
Jul 8, 2001
Jul 8, 2001
430
431
Aug 30, 2010
Aug 30, 2010
432
static PHYSFS_sint64 zip_find_end_of_central_dir(PHYSFS_Io *io, PHYSFS_sint64 *len)
Jul 13, 2002
Jul 13, 2002
433
{
Jul 23, 2002
Jul 23, 2002
434
PHYSFS_uint8 buf[256];
Mar 25, 2010
Mar 25, 2010
435
PHYSFS_uint8 extra[4] = { 0, 0, 0, 0 };
Jul 27, 2002
Jul 27, 2002
436
PHYSFS_sint32 i = 0;
Jul 13, 2002
Jul 13, 2002
437
438
439
PHYSFS_sint64 filelen;
PHYSFS_sint64 filepos;
PHYSFS_sint32 maxread;
Jul 23, 2002
Jul 23, 2002
440
441
PHYSFS_sint32 totalread = 0;
int found = 0;
Jul 13, 2002
Jul 13, 2002
442
Aug 30, 2010
Aug 30, 2010
443
filelen = io->length(io);
Feb 7, 2014
Feb 7, 2014
444
BAIL_IF_MACRO(filelen == -1, ERRPASS, -1);
Jul 13, 2002
Jul 13, 2002
445
446
447
448
449
450
451
452
453
/*
* Jump to the end of the file and start reading backwards.
* The last thing in the file is the zipfile comment, which is variable
* length, and the field that specifies its size is before it in the
* file (argh!)...this means that we need to scan backwards until we
* hit the end-of-central-dir signature. We can then sanity check that
* the comment was as big as it should be to make sure we're in the
* right place. The comment length field is 16 bits, so we can stop
Jul 23, 2002
Jul 23, 2002
454
455
* searching for that signature after a little more than 64k at most,
* and call it a corrupted zipfile.
Jul 13, 2002
Jul 13, 2002
456
457
458
459
460
461
462
463
464
465
*/
if (sizeof (buf) < filelen)
{
filepos = filelen - sizeof (buf);
maxread = sizeof (buf);
} /* if */
else
{
filepos = 0;
Mar 12, 2003
Mar 12, 2003
466
maxread = (PHYSFS_uint32) filelen;
Jul 13, 2002
Jul 13, 2002
467
468
} /* else */
Jul 23, 2002
Jul 23, 2002
469
while ((totalread < filelen) && (totalread < 65557))
Jul 13, 2002
Jul 13, 2002
470
{
Mar 20, 2012
Mar 20, 2012
471
BAIL_IF_MACRO(!io->seek(io, filepos), ERRPASS, -1);
Jul 23, 2002
Jul 23, 2002
472
473
474
/* make sure we catch a signature between buffers. */
if (totalread != 0)
Jul 13, 2002
Jul 13, 2002
475
{
Mar 9, 2012
Mar 9, 2012
476
if (!__PHYSFS_readAll(io, buf, maxread - 4))
Jan 28, 2010
Jan 28, 2010
477
return -1;
May 3, 2009
May 3, 2009
478
memcpy(&buf[maxread - 4], &extra, sizeof (extra));
Jul 23, 2002
Jul 23, 2002
479
totalread += maxread - 4;
Jul 13, 2002
Jul 13, 2002
480
} /* if */
Jul 23, 2002
Jul 23, 2002
481
482
else
{
Mar 9, 2012
Mar 9, 2012
483
if (!__PHYSFS_readAll(io, buf, maxread))
Jan 28, 2010
Jan 28, 2010
484
return -1;
Jul 23, 2002
Jul 23, 2002
485
486
487
totalread += maxread;
} /* else */
May 3, 2009
May 3, 2009
488
memcpy(&extra, buf, sizeof (extra));
Jul 13, 2002
Jul 13, 2002
489
Jul 23, 2002
Jul 23, 2002
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
for (i = maxread - 4; i > 0; i--)
{
if ((buf[i + 0] == 0x50) &&
(buf[i + 1] == 0x4B) &&
(buf[i + 2] == 0x05) &&
(buf[i + 3] == 0x06) )
{
found = 1; /* that's the signature! */
break;
} /* if */
} /* for */
if (found)
break;
filepos -= (maxread - 4);
May 5, 2007
May 5, 2007
506
507
if (filepos < 0)
filepos = 0;
Jul 23, 2002
Jul 23, 2002
508
509
} /* while */
Mar 20, 2012
Mar 20, 2012
510
BAIL_IF_MACRO(!found, PHYSFS_ERR_UNSUPPORTED, -1);
Jul 13, 2002
Jul 13, 2002
511
512
513
514
if (len != NULL)
*len = filelen;
Jan 28, 2010
Jan 28, 2010
515
return (filepos + i);
Jul 23, 2002
Jul 23, 2002
516
} /* zip_find_end_of_central_dir */
Jul 13, 2002
Jul 13, 2002
517
518
Aug 30, 2010
Aug 30, 2010
519
static int isZip(PHYSFS_Io *io)
Jul 8, 2001
Jul 8, 2001
520
{
Aug 30, 2010
Aug 30, 2010
521
PHYSFS_uint32 sig = 0;
Jul 31, 2002
Jul 31, 2002
522
int retval = 0;
Jul 13, 2002
Jul 13, 2002
523
524
525
526
527
/*
* The first thing in a zip file might be the signature of the
* first local file record, so it makes for a quick determination.
*/
Aug 30, 2010
Aug 30, 2010
528
if (readui32(io, &sig))
Jul 15, 2001
Jul 15, 2001
529
{
Jul 31, 2002
Jul 31, 2002
530
531
532
533
534
535
536
537
retval = (sig == ZIP_LOCAL_FILE_SIG);
if (!retval)
{
/*
* No sig...might be a ZIP with data at the start
* (a self-extracting executable, etc), so we'll have to do
* it the hard way...
*/
Aug 30, 2010
Aug 30, 2010
538
retval = (zip_find_end_of_central_dir(io, NULL) != -1);
Jul 31, 2002
Jul 31, 2002
539
} /* if */
Jul 15, 2001
Jul 15, 2001
540
541
} /* if */
Jan 28, 2010
Jan 28, 2010
542
return retval;
Aug 24, 2010
Aug 24, 2010
543
} /* isZip */
Jul 8, 2001
Jul 8, 2001
544
545
Feb 25, 2016
Feb 25, 2016
546
547
/* Find the ZIPentry for a path in platform-independent notation. */
static ZIPentry *zip_find_entry(ZIPinfo *info, const char *path)
Jul 13, 2002
Jul 13, 2002
548
{
Feb 25, 2016
Feb 25, 2016
549
550
551
PHYSFS_uint32 hashval;
ZIPentry *prev = NULL;
ZIPentry *retval;
Jul 23, 2002
Jul 23, 2002
552
Feb 25, 2016
Feb 25, 2016
553
554
if (*path == '\0')
return &info->root;
Jul 23, 2002
Jul 23, 2002
555
Feb 25, 2016
Feb 25, 2016
556
557
hashval = zip_hash_string(info, path);
for (retval = info->hash[hashval]; retval; retval = retval->hashnext)
Jul 23, 2002
Jul 23, 2002
558
{
Feb 25, 2016
Feb 25, 2016
559
if (strcmp(retval->name, path) == 0)
Aug 30, 2002
Aug 30, 2002
560
{
Feb 25, 2016
Feb 25, 2016
561
if (prev != NULL) /* move this to the front of the list */
Aug 28, 2002
Aug 28, 2002
562
{
Feb 25, 2016
Feb 25, 2016
563
564
565
prev->hashnext = retval->hashnext;
retval->hashnext = info->hash[hashval];
info->hash[hashval] = retval;
Aug 28, 2002
Aug 28, 2002
566
567
} /* if */
Feb 25, 2016
Feb 25, 2016
568
return retval;
Aug 30, 2002
Aug 30, 2002
569
} /* if */
Aug 28, 2002
Aug 28, 2002
570
Feb 25, 2016
Feb 25, 2016
571
572
prev = retval;
} /* for */
Jul 23, 2002
Jul 23, 2002
573
Nov 28, 2012
Nov 28, 2012
574
BAIL_MACRO(PHYSFS_ERR_NOT_FOUND, NULL);
Jul 23, 2002
Jul 23, 2002
575
} /* zip_find_entry */
Jul 13, 2002
Jul 13, 2002
576
577
Jul 23, 2002
Jul 23, 2002
578
579
580
581
582
583
584
585
586
587
588
589
590
591
/* Convert paths from old, buggy DOS zippers... */
static void zip_convert_dos_path(ZIPentry *entry, char *path)
{
PHYSFS_uint8 hosttype = (PHYSFS_uint8) ((entry->version >> 8) & 0xFF);
if (hosttype == 0) /* FS_FAT_ */
{
while (*path)
{
if (*path == '\\')
*path = '/';
path++;
} /* while */
} /* if */
} /* zip_convert_dos_path */
Jul 13, 2002
Jul 13, 2002
592
593
Jul 23, 2002
Jul 23, 2002
594
static void zip_expand_symlink_path(char *path)
Jul 8, 2001
Jul 8, 2001
595
{
Jul 23, 2002
Jul 23, 2002
596
597
char *ptr = path;
char *prevptr = path;
Jul 15, 2001
Jul 15, 2001
598
Jul 23, 2002
Jul 23, 2002
599
while (1)
Jul 28, 2001
Jul 28, 2001
600
{
Jul 23, 2002
Jul 23, 2002
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
ptr = strchr(ptr, '/');
if (ptr == NULL)
break;
if (*(ptr + 1) == '.')
{
if (*(ptr + 2) == '/')
{
/* current dir in middle of string: ditch it. */
memmove(ptr, ptr + 2, strlen(ptr + 2) + 1);
} /* else if */
else if (*(ptr + 2) == '\0')
{
/* current dir at end of string: ditch it. */
*ptr = '\0';
} /* else if */
else if (*(ptr + 2) == '.')
{
if (*(ptr + 3) == '/')
{
/* parent dir in middle: move back one, if possible. */
memmove(prevptr, ptr + 4, strlen(ptr + 4) + 1);
ptr = prevptr;
while (prevptr != path)
{
prevptr--;
if (*prevptr == '/')
{
prevptr++;
break;
} /* if */
} /* while */
} /* if */
Jul 15, 2001
Jul 15, 2001
636
Jul 23, 2002
Jul 23, 2002
637
638
639
640
641
642
643
644
645
646
if (*(ptr + 3) == '\0')
{
/* parent dir at end: move back one, if possible. */
*prevptr = '\0';
} /* if */
} /* if */
} /* if */
else
{
prevptr = ptr;
Jun 1, 2011
Jun 1, 2011
647
ptr++;
Jul 23, 2002
Jul 23, 2002
648
649
650
} /* else */
} /* while */
} /* zip_expand_symlink_path */
Jul 15, 2001
Jul 15, 2001
651
Sep 29, 2004
Sep 29, 2004
652
/* (forward reference: zip_follow_symlink and zip_resolve call each other.) */
Aug 30, 2010
Aug 30, 2010
653
static int zip_resolve(PHYSFS_Io *io, ZIPinfo *info, ZIPentry *entry);
Jul 15, 2001
Jul 15, 2001
654
Mar 29, 2002
Mar 29, 2002
655
/*
Jul 23, 2002
Jul 23, 2002
656
657
658
* Look for the entry named by (path). If it exists, resolve it, and return
* a pointer to that entry. If it's another symlink, keep resolving until you
* hit a real file and then return a pointer to the final non-symlink entry.
Mar 24, 2012
Mar 24, 2012
659
* If there's a problem, return NULL.
Mar 29, 2002
Mar 29, 2002
660
*/
Aug 30, 2010
Aug 30, 2010
661
static ZIPentry *zip_follow_symlink(PHYSFS_Io *io, ZIPinfo *info, char *path)
Jul 28, 2001
Jul 28, 2001
662
{
Jul 23, 2002
Jul 23, 2002
663
664
665
ZIPentry *entry;
zip_expand_symlink_path(path);
Feb 25, 2016
Feb 25, 2016
666
entry = zip_find_entry(info, path);
Jul 23, 2002
Jul 23, 2002
667
668
if (entry != NULL)
{
Aug 30, 2010
Aug 30, 2010
669
if (!zip_resolve(io, info, entry)) /* recursive! */
Jul 23, 2002
Jul 23, 2002
670
671
672
673
674
675
676
677
entry = NULL;
else
{
if (entry->symlink != NULL)
entry = entry->symlink;
} /* else */
} /* if */
Jan 28, 2010
Jan 28, 2010
678
return entry;
Jul 23, 2002
Jul 23, 2002
679
} /* zip_follow_symlink */
Jul 8, 2001
Jul 8, 2001
680
681
Aug 30, 2010
Aug 30, 2010
682
static int zip_resolve_symlink(PHYSFS_Io *io, ZIPinfo *info, ZIPentry *entry)
Jul 23, 2001
Jul 23, 2001
683
{
Jun 1, 2012
Jun 1, 2012
684
const PHYSFS_uint64 size = entry->uncompressed_size;
Mar 24, 2012
Mar 24, 2012
685
char *path = NULL;
Jul 13, 2002
Jul 13, 2002
686
687
int rc = 0;
Jul 23, 2002
Jul 23, 2002
688
689
690
691
692
693
/*
* We've already parsed the local file header of the symlink at this
* point. Now we need to read the actual link from the file data and
* follow it.
*/
Mar 20, 2012
Mar 20, 2012
694
BAIL_IF_MACRO(!io->seek(io, entry->offset), ERRPASS, 0);
Jul 23, 2002
Jul 23, 2002
695
Mar 24, 2012
Mar 24, 2012
696
697
path = (char *) __PHYSFS_smallAlloc(size + 1);
BAIL_IF_MACRO(!path, PHYSFS_ERR_OUT_OF_MEMORY, 0);
Jul 13, 2002
Jul 13, 2002
698
699
if (entry->compression_method == COMPMETH_NONE)
Mar 9, 2012
Mar 9, 2012
700
rc = __PHYSFS_readAll(io, path, size);
Jul 13, 2002
Jul 13, 2002
701
702
703
704
else /* symlink target path is compressed... */
{
z_stream stream;
Jun 1, 2012
Jun 1, 2012
705
const PHYSFS_uint64 complen = entry->compressed_size;
Mar 24, 2007
Mar 24, 2007
706
PHYSFS_uint8 *compressed = (PHYSFS_uint8*) __PHYSFS_smallAlloc(complen);
Jul 13, 2002
Jul 13, 2002
707
708
if (compressed != NULL)
{
Mar 9, 2012
Mar 9, 2012
709
if (__PHYSFS_readAll(io, compressed, complen))
Jul 13, 2002
Jul 13, 2002
710
{
Sep 23, 2004
Sep 23, 2004
711
initializeZStream(&stream);
Jul 13, 2002
Jul 13, 2002
712
stream.next_in = compressed;
Mar 24, 2007
Mar 24, 2007
713
stream.avail_in = complen;
Jan 31, 2003
Jan 31, 2003
714
stream.next_out = (unsigned char *) path;
Jul 13, 2002
Jul 13, 2002
715
716
717
stream.avail_out = size;
if (zlib_err(inflateInit2(&stream, -MAX_WBITS)) == Z_OK)
{
Jul 15, 2002
Jul 15, 2002
718
rc = zlib_err(inflate(&stream, Z_FINISH));
Jul 13, 2002
Jul 13, 2002
719
inflateEnd(&stream);
Jul 15, 2002
Jul 15, 2002
720
721
722
/* both are acceptable outcomes... */
rc = ((rc == Z_OK) || (rc == Z_STREAM_END));
Jul 13, 2002
Jul 13, 2002
723
724
} /* if */
} /* if */
Mar 24, 2007
Mar 24, 2007
725
__PHYSFS_smallFree(compressed);
Jul 13, 2002
Jul 13, 2002
726
727
} /* if */
} /* else */
Mar 29, 2002
Mar 29, 2002
728
Mar 24, 2012
Mar 24, 2012
729
if (rc)
Jul 23, 2002
Jul 23, 2002
730
731
732
{
path[entry->uncompressed_size] = '\0'; /* null-terminate it. */
zip_convert_dos_path(entry, path);
Aug 30, 2010
Aug 30, 2010
733
entry->symlink = zip_follow_symlink(io, info, path);
Jul 23, 2002
Jul 23, 2002
734
735
} /* else */
Mar 24, 2012
Mar 24, 2012
736
737
__PHYSFS_smallFree(path);
Jan 28, 2010
Jan 28, 2010
738
return (entry->symlink != NULL);
Jul 23, 2002
Jul 23, 2002
739
740
741
742
743
744
} /* zip_resolve_symlink */
/*
* Parse the local file header of an entry, and update entry->offset.
*/
Aug 30, 2010
Aug 30, 2010
745
static int zip_parse_local(PHYSFS_Io *io, ZIPentry *entry)
Jul 23, 2002
Jul 23, 2002
746
747
748
749
750
751
{
PHYSFS_uint32 ui32;
PHYSFS_uint16 ui16;
PHYSFS_uint16 fnamelen;
PHYSFS_uint16 extralen;
Mar 30, 2003
Mar 30, 2003
752
753
754
755
756
/*
* crc and (un)compressed_size are always zero if this is a "JAR"
* archive created with Sun's Java tools, apparently. We only
* consider this archive corrupted if those entries don't match and
* aren't zero. That seems to work well.
Jun 1, 2012
Jun 1, 2012
757
758
* We also ignore a mismatch if the value is 0xFFFFFFFF here, since it's
* possible that's a Zip64 thing.
Mar 30, 2003
Mar 30, 2003
759
760
*/
Mar 20, 2012
Mar 20, 2012
761
762
763
764
765
766
767
768
769
770
771
BAIL_IF_MACRO(!io->seek(io, entry->offset), ERRPASS, 0);
BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
BAIL_IF_MACRO(ui32 != ZIP_LOCAL_FILE_SIG, PHYSFS_ERR_CORRUPT, 0);
BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
BAIL_IF_MACRO(ui16 != entry->version_needed, PHYSFS_ERR_CORRUPT, 0);
BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0); /* general bits. */
BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
BAIL_IF_MACRO(ui16 != entry->compression_method, PHYSFS_ERR_CORRUPT, 0);
BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0); /* date/time */
BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
BAIL_IF_MACRO(ui32 && (ui32 != entry->crc), PHYSFS_ERR_CORRUPT, 0);
Jun 1, 2012
Jun 1, 2012
772
Mar 20, 2012
Mar 20, 2012
773
BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
Jun 1, 2012
Jun 1, 2012
774
775
776
BAIL_IF_MACRO(ui32 && (ui32 != 0xFFFFFFFF) &&
(ui32 != entry->compressed_size), PHYSFS_ERR_CORRUPT, 0);
Mar 20, 2012
Mar 20, 2012
777
BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
Jun 1, 2012
Jun 1, 2012
778
779
780
BAIL_IF_MACRO(ui32 && (ui32 != 0xFFFFFFFF) &&
(ui32 != entry->uncompressed_size), PHYSFS_ERR_CORRUPT, 0);
Mar 20, 2012
Mar 20, 2012
781
782
BAIL_IF_MACRO(!readui16(io, &fnamelen), ERRPASS, 0);
BAIL_IF_MACRO(!readui16(io, &extralen), ERRPASS, 0);
Jul 23, 2002
Jul 23, 2002
783
784
entry->offset += fnamelen + extralen + 30;
Jan 28, 2010
Jan 28, 2010
785
return 1;
Jul 23, 2002
Jul 23, 2002
786
787
788
} /* zip_parse_local */
Aug 30, 2010
Aug 30, 2010
789
static int zip_resolve(PHYSFS_Io *io, ZIPinfo *info, ZIPentry *entry)
Jul 23, 2002
Jul 23, 2002
790
791
{
int retval = 1;
Feb 25, 2016
Feb 25, 2016
792
793
794
795
const ZipResolveType resolve_type = entry->resolved;
if (resolve_type == ZIP_DIRECTORY)
return 1; /* we're good. */
Jul 23, 2002
Jul 23, 2002
796
797
/* Don't bother if we've failed to resolve this entry before. */
Mar 20, 2012
Mar 20, 2012
798
799
BAIL_IF_MACRO(resolve_type == ZIP_BROKEN_FILE, PHYSFS_ERR_CORRUPT, 0);
BAIL_IF_MACRO(resolve_type == ZIP_BROKEN_SYMLINK, PHYSFS_ERR_CORRUPT, 0);
Jul 23, 2002
Jul 23, 2002
800
801
/* uhoh...infinite symlink loop! */
Mar 20, 2012
Mar 20, 2012
802
BAIL_IF_MACRO(resolve_type == ZIP_RESOLVING, PHYSFS_ERR_SYMLINK_LOOP, 0);
Jul 23, 2002
Jul 23, 2002
803
804
805
806
807
808
809
810
811
812
813
814
/*
* We fix up the offset to point to the actual data on the
* first open, since we don't want to seek across the whole file on
* archive open (can be SLOW on large, CD-stored files), but we
* need to check the local file header...not just for corruption,
* but since it stores offset info the central directory does not.
*/
if (resolve_type != ZIP_RESOLVED)
{
entry->resolved = ZIP_RESOLVING;
Aug 30, 2010
Aug 30, 2010
815
retval = zip_parse_local(io, entry);
Jul 23, 2002
Jul 23, 2002
816
817
818
819
820
821
822
823
if (retval)
{
/*
* If it's a symlink, find the original file. This will cause
* resolution of other entries (other symlinks and, eventually,
* the real file) if all goes well.
*/
if (resolve_type == ZIP_UNRESOLVED_SYMLINK)
Aug 30, 2010
Aug 30, 2010
824
retval = zip_resolve_symlink(io, info, entry);
Jul 23, 2002
Jul 23, 2002
825
826
827
828
829
830
} /* if */
if (resolve_type == ZIP_UNRESOLVED_SYMLINK)
entry->resolved = ((retval) ? ZIP_RESOLVED : ZIP_BROKEN_SYMLINK);
else if (resolve_type == ZIP_UNRESOLVED_FILE)
entry->resolved = ((retval) ? ZIP_RESOLVED : ZIP_BROKEN_FILE);
Jul 13, 2002
Jul 13, 2002
831
} /* if */
Mar 29, 2002
Mar 29, 2002
832
Jan 28, 2010
Jan 28, 2010
833
return retval;
Jul 23, 2002
Jul 23, 2002
834
} /* zip_resolve */
Jul 23, 2001
Jul 23, 2001
835
836
Feb 25, 2016
Feb 25, 2016
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
static int zip_hash_entry(ZIPinfo *info, ZIPentry *entry);
/* Fill in missing parent directories. */
static ZIPentry *zip_hash_ancestors(ZIPinfo *info, char *name)
{
ZIPentry *retval = &info->root;
char *sep = strrchr(name, '/');
if (sep)
{
const size_t namelen = (sep - name) + 1;
ZIPentry *parent;
*sep = '\0'; /* chop off last piece. */
retval = zip_find_entry(info, name);
*sep = '/';
if (retval != NULL)
{
if (retval->resolved != ZIP_DIRECTORY)
BAIL_MACRO(PHYSFS_ERR_CORRUPT, NULL);
return retval; /* already hashed. */
} /* if */
/* okay, this is a new dir. Build and hash us. */
retval = (ZIPentry *) allocator.Malloc(sizeof (ZIPentry) + namelen);
BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
memset(retval, '\0', sizeof (*retval));
retval->name = ((char *) retval) + sizeof (ZIPentry);
memcpy(retval->name, name, namelen);
retval->name[namelen] = '\0';
retval->resolved = ZIP_DIRECTORY;
if (!zip_hash_entry(info, retval))
{
allocator.Free(retval);
return NULL;
} /* if */
} /* else */
return retval;
} /* zip_hash_ancestors */
static int zip_hash_entry(ZIPinfo *info, ZIPentry *entry)
{
PHYSFS_uint32 hashval;
ZIPentry *parent;
assert(!zip_find_entry(info, entry->name)); /* checked elsewhere */
parent = zip_hash_ancestors(info, entry->name);
if (!parent)
return 0;
hashval = zip_hash_string(info, entry->name);
entry->hashnext = info->hash[hashval];
info->hash[hashval] = entry;
entry->sibling = parent->children;
parent->children = entry;
return 1;
} /* zip_hash_entry */
static int zip_entry_is_symlink(const ZIPentry *entry)
{
return ((entry->resolved == ZIP_UNRESOLVED_SYMLINK) ||
(entry->resolved == ZIP_BROKEN_SYMLINK) ||
(entry->symlink));
} /* zip_entry_is_symlink */
Jul 23, 2002
Jul 23, 2002
909
static int zip_version_does_symlinks(PHYSFS_uint32 version)
Jul 23, 2001
Jul 23, 2001
910
911
{
int retval = 0;
Apr 3, 2002
Apr 3, 2002
912
PHYSFS_uint8 hosttype = (PHYSFS_uint8) ((version >> 8) & 0xFF);
Jul 23, 2001
Jul 23, 2001
913
914
915
switch (hosttype)
{
Jul 15, 2002
Jul 15, 2002
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
/*
* These are the platforms that can NOT build an archive with
* symlinks, according to the Info-ZIP project.
*/
case 0: /* FS_FAT_ */
case 1: /* AMIGA_ */
case 2: /* VMS_ */
case 4: /* VM_CSM_ */
case 6: /* FS_HPFS_ */
case 11: /* FS_NTFS_ */
case 14: /* FS_VFAT_ */
case 13: /* ACORN_ */
case 15: /* MVS_ */
case 18: /* THEOS_ */
break; /* do nothing. */
default: /* assume the rest to be unix-like. */
Jul 23, 2001
Jul 23, 2001
933
934
935
936
retval = 1;
break;
} /* switch */
Jan 28, 2010
Jan 28, 2010
937
return retval;
Jul 23, 2002
Jul 23, 2002
938
939
940
941
} /* zip_version_does_symlinks */
static int zip_has_symlink_attr(ZIPentry *entry, PHYSFS_uint32 extern_attr)
Jul 23, 2001
Jul 23, 2001
942
{
Jul 15, 2002
Jul 15, 2002
943
PHYSFS_uint16 xattr = ((extern_attr >> 16) & 0xFFFF);
Jan 28, 2010
Jan 28, 2010
944
945
946
return ( (zip_version_does_symlinks(entry->version)) &&
(entry->uncompressed_size > 0) &&
((xattr & UNIX_FILETYPE_MASK) == UNIX_FILETYPE_SYMLINK) );
Jul 23, 2002
Jul 23, 2002
947
} /* zip_has_symlink_attr */
Jul 23, 2001
Jul 23, 2001
948
949
Jan 31, 2003
Jan 31, 2003
950
static PHYSFS_sint64 zip_dos_time_to_physfs_time(PHYSFS_uint32 dostime)
Jul 23, 2001
Jul 23, 2001
951
{
Jul 23, 2002
Jul 23, 2002
952
PHYSFS_uint32 dosdate;
Jul 13, 2002
Jul 13, 2002
953
954
struct tm unixtime;
memset(&unixtime, '\0', sizeof (unixtime));
Jul 28, 2001
Jul 28, 2001
955
Jul 23, 2002
Jul 23, 2002
956
957
dosdate = (PHYSFS_uint32) ((dostime >> 16) & 0xFFFF);
dostime &= 0xFFFF;
Jul 23, 2001
Jul 23, 2001
958
Jul 23, 2002
Jul 23, 2002
959
960
961
962
963
964
965
966
967
968
969
970
/* dissect date */
unixtime.tm_year = ((dosdate >> 9) & 0x7F) + 80;
unixtime.tm_mon = ((dosdate >> 5) & 0x0F) - 1;
unixtime.tm_mday = ((dosdate ) & 0x1F);
/* dissect time */
unixtime.tm_hour = ((dostime >> 11) & 0x1F);
unixtime.tm_min = ((dostime >> 5) & 0x3F);
unixtime.tm_sec = ((dostime << 1) & 0x3E);
/* let mktime calculate daylight savings time. */
unixtime.tm_isdst = -1;
Jul 28, 2001
Jul 28, 2001
971
Jan 28, 2010
Jan 28, 2010
972
return ((PHYSFS_sint64) mktime(&unixtime));
Jul 23, 2002
Jul 23, 2002
973
} /* zip_dos_time_to_physfs_time */
Jul 13, 2002
Jul 13, 2002
974
975
Feb 25, 2016
Feb 25, 2016
976
977
static ZIPentry *zip_load_entry(PHYSFS_Io *io, const int zip64,
const PHYSFS_uint64 ofs_fixup)
Jul 13, 2002
Jul 13, 2002
978
{
Feb 25, 2016
Feb 25, 2016
979
980
ZIPentry entry;
ZIPentry *retval = NULL;
Jul 13, 2002
Jul 13, 2002
981
982
PHYSFS_uint16 fnamelen, extralen, commentlen;
PHYSFS_uint32 external_attr;
Jun 1, 2012
Jun 1, 2012
983
984
PHYSFS_uint32 starting_disk;
PHYSFS_uint64 offset;
Jul 13, 2002
Jul 13, 2002
985
986
987
988
PHYSFS_uint16 ui16;
PHYSFS_uint32 ui32;
PHYSFS_sint64 si64;
Feb 25, 2016
Feb 25, 2016
989
990
memset(&entry, '\0', sizeof (entry));
Jul 13, 2002
Jul 13, 2002
991
/* sanity check with central directory signature... */
Feb 25, 2016
Feb 25, 2016
992
993
if (!readui32(io, &ui32)) return NULL;
BAIL_IF_MACRO(ui32 != ZIP_CENTRAL_DIR_SIG, PHYSFS_ERR_CORRUPT, NULL);
Jul 13, 2002
Jul 13, 2002
994
995
/* Get the pertinent parts of the record... */
Feb 25, 2016
Feb 25, 2016
996
997
998
999
1000
if (!readui16(io, &entry.version)) return NULL;
if (!readui16(io, &entry.version_needed)) return NULL;
if (!readui16(io, &ui16)) return NULL; /* general bits */
if (!readui16(io, &entry.compression_method)) return NULL;
if (!readui32(io, &ui32)) return NULL;