/
archiver_lzma.c
701 lines (559 loc) · 20.5 KB
1
2
3
/*
* LZMA support routines for PhysicsFS.
*
4
* Please see the file lzma.txt in the lzma/ directory.
5
*
6
* This file was written by Dennis Schridde, with some peeking at "7zMain.c"
7
8
9
10
11
12
* by Igor Pavlov.
*/
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
13
14
#if PHYSFS_SUPPORTS_7Z
15
16
17
#include "lzma/C/7zCrc.h"
#include "lzma/C/Archive/7z/7zIn.h"
#include "lzma/C/Archive/7z/7zExtract.h"
18
19
20
21
/* 7z internal from 7zIn.c */
extern int TestSignatureCandidate(Byte *testBytes);
22
23
24
25
26
#ifdef _LZMA_IN_CB
# define BUFFER_SIZE (1 << 12)
#endif /* _LZMA_IN_CB */
27
28
29
30
31
32
/*
* Carries filestream metadata through 7z
*/
typedef struct _FileInputStream
33
{
34
35
36
ISzAlloc allocImp; /* Allocation implementation, used by 7z */
ISzAlloc allocTempImp; /* Temporary allocation implementation, used by 7z */
ISzInStream inStream; /* Input stream with read callbacks, used by 7z */
37
PHYSFS_Io *io; /* Filehandle, used by read implementation */
38
39
40
41
#ifdef _LZMA_IN_CB
Byte buffer[BUFFER_SIZE]; /* Buffer, used by read implementation */
#endif /* _LZMA_IN_CB */
} FileInputStream;
42
43
/*
44
* In the 7z format archives are splited into blocks, those are called folders
45
46
47
48
49
50
* Set by LZMA_read()
*/
typedef struct _LZMAfolder
{
PHYSFS_uint32 index; /* Index of folder in archive */
PHYSFS_uint32 references; /* Number of files using this block */
51
52
PHYSFS_uint8 *cache; /* Cached folder */
size_t size; /* Size of folder */
53
54
55
56
57
58
} LZMAfolder;
/*
* Set by LZMA_openArchive(), except folder which gets it's values
* in LZMA_read()
*/
59
typedef struct _LZMAarchive
60
{
61
62
struct _LZMAfile *files; /* Array of files, size == archive->db.Database.NumFiles */
LZMAfolder *folders; /* Array of folders, size == archive->db.Database.NumFolders */
63
CArchiveDatabaseEx db; /* For 7z: Database */
64
FileInputStream stream; /* For 7z: Input file incl. read and seek callbacks */
65
66
} LZMAarchive;
67
68
/* Set by LZMA_openArchive(), except offset which is set by LZMA_read() */
typedef struct _LZMAfile
69
{
70
PHYSFS_uint32 index; /* Index of file in archive */
71
LZMAarchive *archive; /* Link to corresponding archive */
72
73
LZMAfolder *folder; /* Link to corresponding folder */
CFileItem *item; /* For 7z: File info, eg. name, size */
74
size_t offset; /* Offset in folder */
75
76
size_t position; /* Current "virtual" position in file */
} LZMAfile;
77
78
79
80
/* Memory management implementations to be passed to 7z */
81
82
83
84
85
86
87
88
89
90
91
92
93
static void *SzAllocPhysicsFS(size_t size)
{
return ((size == 0) ? NULL : allocator.Malloc(size));
} /* SzAllocPhysicsFS */
static void SzFreePhysicsFS(void *address)
{
if (address != NULL)
allocator.Free(address);
} /* SzFreePhysicsFS */
94
95
96
97
/* Filesystem implementations to be passed to 7z */
#ifdef _LZMA_IN_CB
98
99
100
101
/*
* Read implementation, to be passed to 7z
* WARNING: If the ISzInStream in 'object' is not contained in a valid FileInputStream this _will_ break horribly!
*/
102
103
SZ_RESULT SzFileReadImp(void *object, void **buffer, size_t maxReqSize,
size_t *processedSize)
104
{
105
FileInputStream *s = (FileInputStream *)(object - offsetof(FileInputStream, inStream)); /* HACK! */
106
107
108
109
PHYSFS_sint64 processedSizeLoc = 0;
if (maxReqSize > BUFFER_SIZE)
maxReqSize = BUFFER_SIZE;
110
processedSizeLoc = s->io->read(s->io, s->buffer, maxReqSize);
111
*buffer = s->buffer;
112
113
if (processedSize != NULL)
*processedSize = (size_t) processedSizeLoc;
114
115
116
117
118
return SZ_OK;
} /* SzFileReadImp */
#else
119
120
121
122
123
/*
* Read implementation, to be passed to 7z
* WARNING: If the ISzInStream in 'object' is not contained in a valid FileInputStream this _will_ break horribly!
*/
124
125
126
SZ_RESULT SzFileReadImp(void *object, void *buffer, size_t size,
size_t *processedSize)
{
127
FileInputStream *s = (FileInputStream *)((unsigned long)object - offsetof(FileInputStream, inStream)); /* HACK! */
128
129
const size_t processedSizeLoc = s->io->read(s->io, buffer, size);
if (processedSize != NULL)
130
*processedSize = processedSizeLoc;
131
132
133
return SZ_OK;
} /* SzFileReadImp */
134
#endif
135
136
137
138
139
/*
* Seek implementation, to be passed to 7z
* WARNING: If the ISzInStream in 'object' is not contained in a valid FileInputStream this _will_ break horribly!
*/
140
141
SZ_RESULT SzFileSeekImp(void *object, CFileSize pos)
{
142
FileInputStream *s = (FileInputStream *)((unsigned long)object - offsetof(FileInputStream, inStream)); /* HACK! */
143
if (s->io->seek(s->io, (PHYSFS_uint64) pos))
144
145
146
147
148
return SZ_OK;
return SZE_FAIL;
} /* SzFileSeekImp */
149
/*
150
* Translate Microsoft FILETIME (used by 7zip) into UNIX timestamp
151
*/
152
static PHYSFS_sint64 lzma_filetime_to_unix_timestamp(CArchiveFileTime *ft)
153
{
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/* MS counts in nanoseconds ... */
const PHYSFS_uint64 FILETIME_NANOTICKS_PER_SECOND = __PHYSFS_UI64(10000000);
/* MS likes to count seconds since 01.01.1601 ... */
const PHYSFS_uint64 FILETIME_UNIX_DIFF = __PHYSFS_UI64(11644473600);
PHYSFS_uint64 filetime = ft->Low | ((PHYSFS_uint64)ft->High << 32);
return filetime/FILETIME_NANOTICKS_PER_SECOND - FILETIME_UNIX_DIFF;
} /* lzma_filetime_to_unix_timestamp */
/*
* Compare a file with a given name, C89 stdlib variant
* Used for sorting
*/
static int lzma_file_cmp_stdlib(const void *key, const void *object)
{
const char *name = (const char *) key;
LZMAfile *file = (LZMAfile *) object;
172
return strcmp(name, file->item->Name);
173
} /* lzma_file_cmp_posix */
174
175
176
177
178
179
/*
* Compare two files with each other based on the name
* Used for sorting
*/
180
static int lzma_file_cmp(void *_a, size_t one, size_t two)
181
182
{
LZMAfile *files = (LZMAfile *) _a;
183
return strcmp(files[one].item->Name, files[two].item->Name);
184
185
186
187
188
189
} /* lzma_file_cmp */
/*
* Swap two entries in the file array
*/
190
static void lzma_file_swap(void *_a, size_t one, size_t two)
191
192
193
194
195
196
197
198
199
200
201
202
203
{
LZMAfile tmp;
LZMAfile *first = &(((LZMAfile *) _a)[one]);
LZMAfile *second = &(((LZMAfile *) _a)[two]);
memcpy(&tmp, first, sizeof (LZMAfile));
memcpy(first, second, sizeof (LZMAfile));
memcpy(second, &tmp, sizeof (LZMAfile));
} /* lzma_file_swap */
/*
* Find entry 'name' in 'archive'
*/
204
static LZMAfile * lzma_find_file(const LZMAarchive *archive, const char *name)
205
{
206
LZMAfile *file = bsearch(name, archive->files, archive->db.Database.NumFiles, sizeof(*archive->files), lzma_file_cmp_stdlib); /* FIXME: Should become __PHYSFS_search!!! */
207
208
BAIL_IF_MACRO(file == NULL, PHYSFS_ERR_NOT_FOUND, NULL);
209
210
return file;
211
} /* lzma_find_file */
212
213
214
/*
215
* Load metadata for the file at given index
216
*/
217
static int lzma_file_init(LZMAarchive *archive, PHYSFS_uint32 fileIndex)
218
{
219
220
221
LZMAfile *file = &archive->files[fileIndex];
PHYSFS_uint32 folderIndex = archive->db.FileIndexToFolderIndexMap[fileIndex];
222
file->index = fileIndex; /* Store index into 7z array, since we sort our own. */
223
file->archive = archive;
224
225
file->folder = (folderIndex != (PHYSFS_uint32)-1 ? &archive->folders[folderIndex] : NULL); /* Directories don't have a folder (they contain no own data...) */
file->item = &archive->db.Database.Files[fileIndex]; /* Holds crucial data and is often referenced -> Store link */
226
227
228
file->position = 0;
file->offset = 0; /* Offset will be set by LZMA_read() */
229
return 1;
230
} /* lzma_load_file */
231
232
233
234
235
236
237
238
/*
* Load metadata for all files
*/
static int lzma_files_init(LZMAarchive *archive)
{
PHYSFS_uint32 fileIndex = 0, numFiles = archive->db.Database.NumFiles;
239
240
for (fileIndex = 0; fileIndex < numFiles; fileIndex++ )
241
{
242
if (!lzma_file_init(archive, fileIndex))
243
{
244
return 0; /* FALSE on failure */
245
246
247
}
} /* for */
248
__PHYSFS_sort(archive->files, (size_t) numFiles, lzma_file_cmp, lzma_file_swap);
249
250
return 1;
251
} /* lzma_load_files */
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
/*
* Initialise specified archive
*/
static void lzma_archive_init(LZMAarchive *archive)
{
memset(archive, 0, sizeof(*archive));
/* Prepare callbacks for 7z */
archive->stream.inStream.Read = SzFileReadImp;
archive->stream.inStream.Seek = SzFileSeekImp;
archive->stream.allocImp.Alloc = SzAllocPhysicsFS;
archive->stream.allocImp.Free = SzFreePhysicsFS;
archive->stream.allocTempImp.Alloc = SzAllocPhysicsFS;
archive->stream.allocTempImp.Free = SzFreePhysicsFS;
}
/*
* Deinitialise archive
*/
static void lzma_archive_exit(LZMAarchive *archive)
{
/* Free arrays */
allocator.Free(archive->folders);
allocator.Free(archive->files);
allocator.Free(archive);
}
284
285
286
287
288
289
290
291
292
293
/*
* Wrap all 7z calls in this, so the physfs error state is set appropriately.
*/
static int lzma_err(SZ_RESULT rc)
{
switch (rc)
{
case SZ_OK: /* Same as LZMA_RESULT_OK */
break;
case SZE_DATA_ERROR: /* Same as LZMA_RESULT_DATA_ERROR */
294
PHYSFS_setErrorCode(PHYSFS_ERR_CORRUPT); /*!!!FIXME: was "PHYSFS_ERR_DATA_ERROR" */
295
296
break;
case SZE_OUTOFMEMORY:
297
PHYSFS_setErrorCode(PHYSFS_ERR_OUT_OF_MEMORY);
298
299
break;
case SZE_CRC_ERROR:
300
PHYSFS_setErrorCode(PHYSFS_ERR_CORRUPT);
301
302
break;
case SZE_NOTIMPL:
303
PHYSFS_setErrorCode(PHYSFS_ERR_UNSUPPORTED);
304
305
break;
case SZE_FAIL:
306
PHYSFS_setErrorCode(PHYSFS_ERR_OTHER_ERROR); /* !!! FIXME: right? */
307
308
break;
case SZE_ARCHIVE_ERROR:
309
PHYSFS_setErrorCode(PHYSFS_ERR_CORRUPT); /* !!! FIXME: right? */
310
311
break;
default:
312
PHYSFS_setErrorCode(PHYSFS_ERR_OTHER_ERROR);
313
314
} /* switch */
315
return rc;
316
317
318
} /* lzma_err */
319
static PHYSFS_sint64 LZMA_read(PHYSFS_Io *io, void *outBuf, PHYSFS_uint64 len)
320
{
321
LZMAfile *file = (LZMAfile *) io->opaque;
322
323
size_t wantedSize = (size_t) len;
324
const size_t remainingSize = file->item->Size - file->position;
325
size_t fileSize = 0;
326
327
328
BAIL_IF_MACRO(wantedSize == 0, ERRPASS, 0); /* quick rejection. */
BAIL_IF_MACRO(remainingSize == 0, PHYSFS_ERR_PAST_EOF, 0);
329
330
331
if (wantedSize > remainingSize)
wantedSize = remainingSize;
332
333
/* Only decompress the folder if it is not already cached */
334
if (file->folder->cache == NULL)
335
{
336
const int rc = lzma_err(SzExtract(
337
338
339
&file->archive->stream.inStream, /* compressed data */
&file->archive->db, /* 7z's database, containing everything */
file->index, /* Index into database arrays */
340
/* Index of cached folder, will be changed by SzExtract */
341
&file->folder->index,
342
/* Cache for decompressed folder, allocated/freed by SzExtract */
343
&file->folder->cache,
344
/* Size of cache, will be changed by SzExtract */
345
&file->folder->size,
346
/* Offset of this file inside the cache, set by SzExtract */
347
&file->offset,
348
&fileSize, /* Size of this file */
349
350
&file->archive->stream.allocImp,
&file->archive->stream.allocTempImp));
351
352
if (rc != SZ_OK)
353
return -1;
354
} /* if */
355
356
/* Copy wanted bytes over from cache to outBuf */
357
memcpy(outBuf, (file->folder->cache + file->offset + file->position),
358
359
360
wantedSize);
file->position += wantedSize; /* Increase virtual position */
361
return wantedSize;
362
363
364
} /* LZMA_read */
365
static PHYSFS_sint64 LZMA_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
366
{
367
BAIL_MACRO(PHYSFS_ERR_READ_ONLY, -1);
368
369
370
} /* LZMA_write */
371
static PHYSFS_sint64 LZMA_tell(PHYSFS_Io *io)
372
{
373
374
LZMAfile *file = (LZMAfile *) io->opaque;
return file->position;
375
376
377
} /* LZMA_tell */
378
static int LZMA_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
379
{
380
LZMAfile *file = (LZMAfile *) io->opaque;
381
382
BAIL_IF_MACRO(offset > file->item->Size, PHYSFS_ERR_PAST_EOF, 0);
383
384
file->position = offset; /* We only use a virtual position... */
385
386
return 1;
387
388
389
} /* LZMA_seek */
390
static PHYSFS_sint64 LZMA_length(PHYSFS_Io *io)
391
{
392
const LZMAfile *file = (LZMAfile *) io->opaque;
393
return (file->item->Size);
394
} /* LZMA_length */
395
396
397
static PHYSFS_Io *LZMA_duplicate(PHYSFS_Io *_io)
398
{
399
400
/* !!! FIXME: this archiver needs to be reworked to allow multiple
* !!! FIXME: opens before we worry about duplication. */
401
BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL);
402
} /* LZMA_duplicate */
403
404
405
static int LZMA_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
406
407
408
static void LZMA_destroy(PHYSFS_Io *io)
409
{
410
LZMAfile *file = (LZMAfile *) io->opaque;
411
412
if (file->folder != NULL)
413
{
414
415
416
417
418
419
420
421
422
423
424
425
/* Only decrease refcount if someone actually requested this file... Prevents from overflows and close-on-open... */
if (file->folder->references > 0)
file->folder->references--;
if (file->folder->references == 0)
{
/* Free the cache which might have been allocated by LZMA_read() */
allocator.Free(file->folder->cache);
file->folder->cache = NULL;
}
/* !!! FIXME: we don't free (file) or (file->folder)?! */
} /* if */
} /* LZMA_destroy */
426
427
428
429
static const PHYSFS_Io LZMA_Io =
{
430
CURRENT_PHYSFS_IO_API_VERSION, NULL,
431
432
433
434
435
436
437
LZMA_read,
LZMA_write,
LZMA_seek,
LZMA_tell,
LZMA_length,
LZMA_duplicate,
LZMA_flush,
438
LZMA_destroy
439
};
440
441
442
static void *LZMA_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
443
{
444
PHYSFS_uint8 sig[k7zSignatureSize];
445
size_t len = 0;
446
LZMAarchive *archive = NULL;
447
448
449
assert(io != NULL); /* shouldn't ever happen. */
450
BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
451
452
if (io->read(io, sig, k7zSignatureSize) != k7zSignatureSize)
453
454
455
return 0;
BAIL_IF_MACRO(!TestSignatureCandidate(sig), PHYSFS_ERR_UNSUPPORTED, NULL);
BAIL_IF_MACRO(!io->seek(io, 0), ERRPASS, NULL);
456
457
archive = (LZMAarchive *) allocator.Malloc(sizeof (LZMAarchive));
458
BAIL_IF_MACRO(archive == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
459
460
lzma_archive_init(archive);
461
archive->stream.io = io;
462
463
CrcGenerateTable();
464
SzArDbExInit(&archive->db);
465
466
467
468
if (lzma_err(SzArchiveOpen(&archive->stream.inStream,
&archive->db,
&archive->stream.allocImp,
&archive->stream.allocTempImp)) != SZ_OK)
469
{
470
471
SzArDbExFree(&archive->db, SzFreePhysicsFS);
lzma_archive_exit(archive);
472
return NULL; /* Error is set by lzma_err! */
473
474
} /* if */
475
476
477
478
479
480
len = archive->db.Database.NumFiles * sizeof (LZMAfile);
archive->files = (LZMAfile *) allocator.Malloc(len);
if (archive->files == NULL)
{
SzArDbExFree(&archive->db, SzFreePhysicsFS);
lzma_archive_exit(archive);
481
BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
482
483
484
485
486
487
488
489
}
/*
* Init with 0 so we know when a folder is already cached
* Values will be set by LZMA_openRead()
*/
memset(archive->files, 0, len);
490
len = archive->db.Database.NumFolders * sizeof (LZMAfolder);
491
492
493
494
495
archive->folders = (LZMAfolder *) allocator.Malloc(len);
if (archive->folders == NULL)
{
SzArDbExFree(&archive->db, SzFreePhysicsFS);
lzma_archive_exit(archive);
496
BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
497
}
498
499
500
501
502
/*
* Init with 0 so we know when a folder is already cached
* Values will be set by LZMA_read()
*/
503
504
505
506
507
508
memset(archive->folders, 0, len);
if(!lzma_files_init(archive))
{
SzArDbExFree(&archive->db, SzFreePhysicsFS);
lzma_archive_exit(archive);
509
BAIL_MACRO(PHYSFS_ERR_OTHER_ERROR, NULL);
510
}
511
512
return archive;
513
514
515
516
517
518
519
520
} /* LZMA_openArchive */
/*
* Moved to seperate function so we can use alloca then immediately throw
* away the allocated stack space...
*/
static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata,
521
const char *odir, const char *str, size_t flen)
522
{
523
char *newstr = __PHYSFS_smallAlloc(flen + 1);
524
525
526
if (newstr == NULL)
return;
527
528
memcpy(newstr, str, flen);
newstr[flen] = '\0';
529
cb(callbackdata, odir, newstr);
530
__PHYSFS_smallFree(newstr);
531
532
533
} /* doEnumCallback */
534
static void LZMA_enumerateFiles(void *opaque, const char *dname,
535
PHYSFS_EnumFilesCallback cb,
536
537
const char *origdir, void *callbackdata)
{
538
539
size_t dlen = strlen(dname),
dlen_inc = dlen + ((dlen > 0) ? 1 : 0);
540
LZMAarchive *archive = (LZMAarchive *) opaque;
541
542
543
544
545
LZMAfile *file = NULL,
*lastFile = &archive->files[archive->db.Database.NumFiles];
if (dlen)
{
file = lzma_find_file(archive, dname);
546
if (file != NULL) /* if 'file' is NULL it should stay so, otherwise errors will not be handled */
547
548
549
550
551
552
file += 1;
}
else
{
file = archive->files;
}
553
554
BAIL_IF_MACRO(file == NULL, PHYSFS_ERR_NOT_FOUND, );
555
556
while (file < lastFile)
557
{
558
559
560
561
562
563
564
const char * fname = file->item->Name;
const char * dirNameEnd = fname + dlen_inc;
if (strncmp(dname, fname, dlen) != 0) /* Stop after mismatch, archive->files is sorted */
break;
if (strchr(dirNameEnd, '/')) /* Skip subdirs */
565
{
566
567
568
569
570
571
572
573
574
file++;
continue;
}
/* Do the actual callback... */
doEnumCallback(cb, callbackdata, origdir, dirNameEnd, strlen(dirNameEnd));
file++;
}
575
576
577
} /* LZMA_enumerateFiles */
578
static PHYSFS_Io *LZMA_openRead(void *opaque, const char *name,
579
int *fileExists)
580
581
{
LZMAarchive *archive = (LZMAarchive *) opaque;
582
LZMAfile *file = lzma_find_file(archive, name);
583
PHYSFS_Io *io = NULL;
584
585
*fileExists = (file != NULL);
586
BAIL_IF_MACRO(file == NULL, PHYSFS_ERR_NOT_FOUND, NULL);
587
BAIL_IF_MACRO(file->folder == NULL, PHYSFS_ERR_NOT_A_FILE, NULL);
588
589
file->position = 0;
590
file->folder->references++; /* Increase refcount for automatic cleanup... */
591
592
io = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
593
BAIL_IF_MACRO(io == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
594
595
596
597
memcpy(io, &LZMA_Io, sizeof (*io));
io->opaque = file;
return io;
598
599
600
} /* LZMA_openRead */
601
static PHYSFS_Io *LZMA_openWrite(void *opaque, const char *filename)
602
{
603
BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
604
605
606
} /* LZMA_openWrite */
607
static PHYSFS_Io *LZMA_openAppend(void *opaque, const char *filename)
608
{
609
BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
610
611
612
} /* LZMA_openAppend */
613
static void LZMA_closeArchive(void *opaque)
614
{
615
616
LZMAarchive *archive = (LZMAarchive *) opaque;
617
618
#if 0 /* !!! FIXME: you shouldn't have to do this. */
PHYSFS_uint32 fileIndex = 0, numFiles = archive->db.Database.NumFiles;
619
for (fileIndex = 0; fileIndex < numFiles; fileIndex++)
620
{
621
622
LZMA_fileClose(&archive->files[fileIndex]);
} /* for */
623
#endif
624
625
SzArDbExFree(&archive->db, SzFreePhysicsFS);
626
archive->stream.io->destroy(archive->stream.io);
627
lzma_archive_exit(archive);
628
} /* LZMA_closeArchive */
629
630
631
static int LZMA_remove(void *opaque, const char *name)
632
{
633
BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
634
635
636
} /* LZMA_remove */
637
static int LZMA_mkdir(void *opaque, const char *name)
638
{
639
BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
640
641
} /* LZMA_mkdir */
642
static int LZMA_stat(void *opaque, const char *filename, PHYSFS_Stat *stat)
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
{
const LZMAarchive *archive = (const LZMAarchive *) opaque;
const LZMAfile *file = lzma_find_file(archive, filename);
if (!file)
return 0;
if(file->item->IsDirectory)
{
stat->filesize = 0;
stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
} /* if */
else
{
stat->filesize = (PHYSFS_sint64) file->item->Size;
stat->filetype = PHYSFS_FILETYPE_REGULAR;
} /* else */
/* !!! FIXME: the 0's should be -1's? */
if (file->item->IsLastWriteTimeDefined)
stat->modtime = lzma_filetime_to_unix_timestamp(&file->item->LastWriteTime);
else
stat->modtime = 0;
/* real create and accesstype are currently not in the lzma SDK */
stat->createtime = stat->modtime;
stat->accesstime = 0;
stat->readonly = 1; /* 7zips are always read only */
673
return 1;
674
675
} /* LZMA_stat */
676
677
678
const PHYSFS_Archiver __PHYSFS_Archiver_LZMA =
{
679
CURRENT_PHYSFS_ARCHIVER_API_VERSION,
680
681
682
683
684
{
"7Z",
"LZMA (7zip) format",
"Dennis Schridde <devurandom@gmx.net>",
"http://icculus.org/physfs/",
685
0, /* supportsSymlinks */
686
},
687
688
689
690
691
692
693
LZMA_openArchive, /* openArchive() method */
LZMA_enumerateFiles, /* enumerateFiles() method */
LZMA_openRead, /* openRead() method */
LZMA_openWrite, /* openWrite() method */
LZMA_openAppend, /* openAppend() method */
LZMA_remove, /* remove() method */
LZMA_mkdir, /* mkdir() method */
694
LZMA_closeArchive, /* closeArchive() method */
695
LZMA_stat /* stat() method */
696
697
};
698
#endif /* defined PHYSFS_SUPPORTS_7Z */
699
700
/* end of archiver_lzma.c ... */