1f526205839fa1e8ac47d6f5f540d0450dfae4da
[supertux.git] / src / unison / physfs-1.1.1 / archivers / lzma.c
1 /*
2  * LZMA support routines for PhysicsFS.
3  *
4  * Please see the file LICENSE.txt in the source's root directory.
5  *
6  *  This file is written by Dennis Schridde, with some peeking at "7zMain.c"
7  *   by Igor Pavlov.
8  */
9
10 #if (defined PHYSFS_SUPPORTS_7Z)
11
12 #include <stdlib.h>
13 #include <string.h>
14
15 #include "physfs.h"
16
17 #define __PHYSICSFS_INTERNAL__
18 #include "physfs_internal.h"
19
20 #ifndef _LZMA_IN_CB
21 #define _LZMA_IN_CB
22 /* Use callback for input data */
23 #endif
24
25 /* #define _LZMA_OUT_READ */
26 /* Use read function for output data */
27
28 #ifndef _LZMA_PROB32
29 #define _LZMA_PROB32
30 /* It can increase speed on some 32-bit CPUs,
31    but memory usage will be doubled in that case */
32 #endif
33
34 #ifndef _LZMA_SYSTEM_SIZE_T
35 #define _LZMA_SYSTEM_SIZE_T
36 /* Use system's size_t. You can use it to enable 64-bit sizes supporting */
37 #endif
38
39 #include "7zIn.h"
40 #include "7zCrc.h"
41 #include "7zExtract.h"
42
43
44 /* 7z internal from 7zIn.c */
45 int TestSignatureCandidate(Byte *testBytes);
46
47
48 typedef struct _CFileInStream
49 {
50     ISzInStream InStream;
51     void *File;
52 } CFileInStream;
53
54 /*
55  * In LZMA the archive is splited in blocks, those are called folders
56  * Set by LZMA_read()
57 */
58 typedef struct _LZMAfolder
59 {
60     PHYSFS_uint8 *cache; /* Cached folder */
61     PHYSFS_uint32 size; /* Size of folder */
62     PHYSFS_uint32 index; /* Index of folder in archive */
63     PHYSFS_uint32 references; /* Number of files using this block */
64 } LZMAfolder;
65
66 /*
67  * Set by LZMA_openArchive(), except folder which gets it's values
68  *  in LZMA_read()
69  */
70 typedef struct _LZMAarchive
71 {
72     struct _LZMAentry *firstEntry; /* Used for cleanup on shutdown */
73     struct _LZMAentry *lastEntry;
74     LZMAfolder *folder; /* Array of folders */
75     CArchiveDatabaseEx db; /* For 7z: Database */
76     CFileInStream stream; /* For 7z: Input file incl. read and seek callbacks */
77 } LZMAarchive;
78
79 /* Set by LZMA_openRead(), except offset which is set by LZMA_read() */
80 typedef struct _LZMAentry
81 {
82     struct _LZMAentry *next; /* Used for cleanup on shutdown */
83     struct _LZMAentry *previous;
84     LZMAarchive *archive; /* Link to corresponding archive */
85     CFileItem *file; /* For 7z: File info, eg. name, size */
86     PHYSFS_uint32 fileIndex; /* Index of file in archive */
87     PHYSFS_uint32 folderIndex; /* Index of folder in archive */
88     size_t offset; /* Offset in folder */
89     PHYSFS_uint64 position; /* Current "virtual" position in file */
90 } LZMAentry;
91
92
93 /* Memory management implementations to be passed to 7z */
94
95 static void *SzAllocPhysicsFS(size_t size)
96 {
97     return ((size == 0) ? NULL : allocator.Malloc(size));
98 } /* SzAllocPhysicsFS */
99
100
101 static void SzFreePhysicsFS(void *address)
102 {
103     if (address != NULL)
104         allocator.Free(address);
105 } /* SzFreePhysicsFS */
106
107
108 /* Filesystem implementations to be passed to 7z */
109
110 #ifdef _LZMA_IN_CB
111
112 #define kBufferSize (1 << 12)
113 static Byte g_Buffer[kBufferSize];  /* !!! FIXME: not thread safe! */
114
115 SZ_RESULT SzFileReadImp(void *object, void **buffer, size_t maxReqSize,
116                         size_t *processedSize)
117 {
118     CFileInStream *s = (CFileInStream *)object;
119     PHYSFS_sint64 processedSizeLoc;
120     if (maxReqSize > kBufferSize)
121         maxReqSize = kBufferSize;
122     processedSizeLoc = __PHYSFS_platformRead(s->File, g_Buffer, 1, maxReqSize);
123     *buffer = g_Buffer;
124     if (processedSize != NULL)
125         *processedSize = (size_t) processedSizeLoc;
126     return SZ_OK;
127 } /* SzFileReadImp */
128
129 #else
130
131 SZ_RESULT SzFileReadImp(void *object, void *buffer, size_t size,
132                         size_t *processedSize)
133 {
134     CFileInStream *s = (CFileInStream *)object;
135     size_t processedSizeLoc = __PHYSFS_platformRead(s->File, buffer, 1, size);
136     if (processedSize != 0)
137         *processedSize = processedSizeLoc;
138     return SZ_OK;
139 } /* SzFileReadImp */
140
141 #endif
142
143 SZ_RESULT SzFileSeekImp(void *object, CFileSize pos)
144 {
145     CFileInStream *s = (CFileInStream *) object;
146     if (__PHYSFS_platformSeek(s->File, (PHYSFS_uint64) pos))
147         return SZ_OK;
148     return SZE_FAIL;
149 } /* SzFileSeekImp */
150
151
152 /*
153  * Find entry 'name' in 'archive' and report the 'index' back
154  */
155 static int lzma_find_entry(LZMAarchive *archive, const char *name,
156                            PHYSFS_uint32 *index)
157 {
158     for (*index = 0; *index < archive->db.Database.NumFiles; (*index)++)
159     {
160         if (strcmp(archive->db.Database.Files[*index].Name, name) == 0)
161             return 1;
162     } /* for */
163
164     BAIL_MACRO(ERR_NO_SUCH_FILE, 0);
165 } /* lzma_find_entry */
166
167
168 /*
169  * Report the first file index of a directory
170  */
171 static PHYSFS_sint32 lzma_find_start_of_dir(LZMAarchive *archive,
172                                             const char *path,
173                                             int stop_on_first_find)
174 {
175     PHYSFS_sint32 lo = 0;
176     PHYSFS_sint32 hi = (PHYSFS_sint32) (archive->db.Database.NumFiles - 1);
177     PHYSFS_sint32 middle;
178     PHYSFS_uint32 dlen = strlen(path);
179     PHYSFS_sint32 retval = -1;
180     const char *name;
181     int rc;
182
183     if (*path == '\0')  /* root dir? */
184         return(0);
185
186     if ((dlen > 0) && (path[dlen - 1] == '/')) /* ignore trailing slash. */
187         dlen--;
188
189     while (lo <= hi)
190     {
191         middle = lo + ((hi - lo) / 2);
192         name = archive->db.Database.Files[middle].Name;
193         rc = strncmp(path, name, dlen);
194         if (rc == 0)
195         {
196             char ch = name[dlen];
197             if ('/' < ch) /* make sure this isn't just a substr match. */
198                 rc = -1;
199             else if ('/' > ch)
200                 rc = 1;
201             else
202             {
203                 if (stop_on_first_find) /* Just checking dir's existance? */
204                     return(middle);
205
206                 if (name[dlen + 1] == '\0') /* Skip initial dir entry. */
207                     return(middle + 1);
208
209                 /* there might be more entries earlier in the list. */
210                 retval = middle;
211                 hi = middle - 1;
212             } /* else */
213         } /* if */
214
215         if (rc > 0)
216             lo = middle + 1;
217         else
218             hi = middle - 1;
219     } /* while */
220
221     return(retval);
222 } /* lzma_find_start_of_dir */
223
224
225 /*
226  * Wrap all 7z calls in this, so the physfs error state is set appropriately.
227  */
228 static int lzma_err(SZ_RESULT rc)
229 {
230     switch (rc)
231     {
232         case SZ_OK: /* Same as LZMA_RESULT_OK */
233             break;
234         case SZE_DATA_ERROR: /* Same as LZMA_RESULT_DATA_ERROR */
235             __PHYSFS_setError(ERR_DATA_ERROR);
236             break;
237         case SZE_OUTOFMEMORY:
238             __PHYSFS_setError(ERR_OUT_OF_MEMORY);
239             break;
240         case SZE_CRC_ERROR:
241             __PHYSFS_setError(ERR_CORRUPTED);
242             break;
243         case SZE_NOTIMPL:
244             __PHYSFS_setError(ERR_NOT_IMPLEMENTED);
245             break;
246         case SZE_FAIL:
247             __PHYSFS_setError(ERR_UNKNOWN_ERROR);  /* !!! FIXME: right? */
248             break;
249         case SZE_ARCHIVE_ERROR:
250             __PHYSFS_setError(ERR_CORRUPTED);  /* !!! FIXME: right? */
251             break;
252         default:
253             __PHYSFS_setError(ERR_UNKNOWN_ERROR);
254     } /* switch */
255
256     return(rc);
257 } /* lzma_err */
258
259
260 static PHYSFS_sint64 LZMA_read(fvoid *opaque, void *outBuffer,
261                                PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
262 {
263     LZMAentry *entry = (LZMAentry *) opaque;
264
265     PHYSFS_sint64 wantedSize = objSize*objCount;
266     PHYSFS_sint64 remainingSize = entry->file->Size - entry->position;
267
268     size_t fileSize;
269     ISzAlloc allocImp;
270     ISzAlloc allocTempImp;
271
272     BAIL_IF_MACRO(wantedSize == 0, NULL, 0); /* quick rejection. */
273     BAIL_IF_MACRO(remainingSize == 0, ERR_PAST_EOF, 0);
274
275     if (remainingSize < wantedSize)
276     {
277         wantedSize = remainingSize - (remainingSize % objSize);
278         objCount = (PHYSFS_uint32) (remainingSize / objSize);
279         BAIL_IF_MACRO(objCount == 0, ERR_PAST_EOF, 0); /* quick rejection. */
280         __PHYSFS_setError(ERR_PAST_EOF); /* this is always true here. */
281     } /* if */
282
283     /* Prepare callbacks for 7z */
284     allocImp.Alloc = SzAllocPhysicsFS;
285     allocImp.Free = SzFreePhysicsFS;
286
287     allocTempImp.Alloc = SzAllocPhysicsFS;
288     allocTempImp.Free = SzFreePhysicsFS;
289
290     /* Only decompress the folder if it is not allready cached */
291     if (entry->archive->folder[entry->folderIndex].cache == NULL)
292     {
293         size_t tmpsize = entry->archive->folder[entry->folderIndex].size;
294         int rc = lzma_err(SzExtract(
295             &entry->archive->stream.InStream, /* compressed data */
296             &entry->archive->db,
297             entry->fileIndex,
298             /* Index of cached folder, will be changed by SzExtract */
299             &entry->archive->folder[entry->folderIndex].index,
300             /* Cache for decompressed folder, allocated/freed by SzExtract */
301             &entry->archive->folder[entry->folderIndex].cache,
302             /* Size of cache, will be changed by SzExtract */
303             &tmpsize,
304             /* Offset of this file inside the cache, set by SzExtract */
305             &entry->offset,
306             &fileSize, /* Size of this file */
307             &allocImp,
308             &allocTempImp));
309
310         entry->archive->folder[entry->folderIndex].size = tmpsize;
311         if (rc != SZ_OK)
312             return -1;
313     } /* if */
314
315     /* Copy wanted bytes over from cache to outBuffer */
316 /* !!! FIXME: strncpy for non-string data? */
317         strncpy(outBuffer,
318             (void*) (entry->archive->folder[entry->folderIndex].cache +
319                      entry->offset + entry->position),
320             (size_t) wantedSize);
321     entry->position += wantedSize;
322     return objCount;
323 } /* LZMA_read */
324
325
326 static PHYSFS_sint64 LZMA_write(fvoid *opaque, const void *buf,
327                                PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
328 {
329     BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
330 } /* LZMA_write */
331
332
333 static int LZMA_eof(fvoid *opaque)
334 {
335     LZMAentry *entry = (LZMAentry *) opaque;
336     return (entry->position >= entry->file->Size);
337 } /* LZMA_eof */
338
339
340 static PHYSFS_sint64 LZMA_tell(fvoid *opaque)
341 {
342     LZMAentry *entry = (LZMAentry *) opaque;
343     return (entry->position);
344 } /* LZMA_tell */
345
346
347 static int LZMA_seek(fvoid *opaque, PHYSFS_uint64 offset)
348 {
349     LZMAentry *entry = (LZMAentry *) opaque;
350
351     BAIL_IF_MACRO(offset < 0, ERR_SEEK_OUT_OF_RANGE, 0);
352     BAIL_IF_MACRO(offset > entry->file->Size, ERR_PAST_EOF, 0);
353
354     entry->position = offset;
355     return 1;
356 } /* LZMA_seek */
357
358
359 static PHYSFS_sint64 LZMA_fileLength(fvoid *opaque)
360 {
361     LZMAentry *entry = (LZMAentry *) opaque;
362     return (entry->file->Size);
363 } /* LZMA_fileLength */
364
365
366 static int LZMA_fileClose(fvoid *opaque)
367 {
368     LZMAentry *entry = (LZMAentry *) opaque;
369
370     /* Fix archive */
371     if (entry == entry->archive->firstEntry)
372         entry->archive->firstEntry = entry->next;
373     if (entry == entry->archive->lastEntry)
374         entry->archive->lastEntry = entry->previous;
375
376     /* Fix neighbours */
377     if (entry->previous != NULL)
378         entry->previous->next = entry->next;
379     if (entry->next != NULL)
380         entry->next->previous = entry->previous;
381
382     entry->archive->folder[entry->folderIndex].references--;
383     if (entry->archive->folder[entry->folderIndex].references == 0)
384     {
385         allocator.Free(entry->archive->folder[entry->folderIndex].cache);
386         entry->archive->folder[entry->folderIndex].cache = NULL;
387     }
388
389     allocator.Free(entry);
390     entry = NULL;
391
392     return(1);
393 } /* LZMA_fileClose */
394
395
396 static int LZMA_isArchive(const char *filename, int forWriting)
397 {
398     PHYSFS_uint8 sig[k7zSignatureSize];
399     PHYSFS_uint8 res;
400     void *in;
401
402     BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
403
404     in = __PHYSFS_platformOpenRead(filename);
405     BAIL_IF_MACRO(in == NULL, NULL, 0);
406
407     if (__PHYSFS_platformRead(in, sig, k7zSignatureSize, 1) != 1)
408         BAIL_MACRO(NULL, 0);
409
410     /* Test whether sig is the 7z signature */
411     res = TestSignatureCandidate(sig);
412
413     __PHYSFS_platformClose(in);
414
415     return res;
416 } /* LZMA_isArchive */
417
418
419 static void *LZMA_openArchive(const char *name, int forWriting)
420 {
421     PHYSFS_uint64 len;
422     LZMAarchive *archive = NULL;
423     ISzAlloc allocImp;
424     ISzAlloc allocTempImp;
425
426     BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, NULL);
427     BAIL_IF_MACRO(!LZMA_isArchive(name,forWriting), ERR_UNSUPPORTED_ARCHIVE, 0);
428
429     archive = (LZMAarchive *) allocator.Malloc(sizeof (LZMAarchive));
430     BAIL_IF_MACRO(archive == NULL, ERR_OUT_OF_MEMORY, NULL);
431
432     archive->firstEntry = NULL;
433     archive->lastEntry = NULL;
434
435     if ((archive->stream.File = __PHYSFS_platformOpenRead(name)) == NULL)
436     {
437         allocator.Free(archive);
438         return NULL;
439     } /* if */
440
441     /* Prepare structs for 7z */
442     archive->stream.InStream.Read = SzFileReadImp;
443     archive->stream.InStream.Seek = SzFileSeekImp;
444
445     allocImp.Alloc = SzAllocPhysicsFS;
446     allocImp.Free = SzFreePhysicsFS;
447
448     allocTempImp.Alloc = SzAllocPhysicsFS;
449     allocTempImp.Free = SzFreePhysicsFS;
450
451     InitCrcTable();
452     SzArDbExInit(&archive->db);
453     if (lzma_err(SzArchiveOpen(&archive->stream.InStream, &archive->db,
454                                &allocImp, &allocTempImp)) != SZ_OK)
455     {
456         __PHYSFS_platformClose(archive->stream.File);
457         allocator.Free(archive);
458         return NULL;
459     } /* if */
460
461     len = archive->db.Database.NumFolders * sizeof (LZMAfolder);
462     archive->folder = (LZMAfolder *) allocator.Malloc(len);
463     BAIL_IF_MACRO(archive->folder == NULL, ERR_OUT_OF_MEMORY, NULL);
464
465     /*
466      * Init with 0 so we know when a folder is already cached
467      * Values will be set by LZMA_read()
468      */
469     memset(archive->folder, 0, (size_t) len);
470
471     return(archive);
472 } /* LZMA_openArchive */
473
474
475 /*
476  * Moved to seperate function so we can use alloca then immediately throw
477  *  away the allocated stack space...
478  */
479 static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata,
480                            const char *odir, const char *str, PHYSFS_sint32 ln)
481 {
482     char *newstr = __PHYSFS_smallAlloc(ln + 1);
483     if (newstr == NULL)
484         return;
485
486     memcpy(newstr, str, ln);
487     newstr[ln] = '\0';
488     cb(callbackdata, odir, newstr);
489     __PHYSFS_smallFree(newstr);
490 } /* doEnumCallback */
491
492
493 static void LZMA_enumerateFiles(dvoid *opaque, const char *dname,
494                                 int omitSymLinks, PHYSFS_EnumFilesCallback cb,
495                                 const char *origdir, void *callbackdata)
496 {
497     LZMAarchive *archive = (LZMAarchive *) opaque;
498     PHYSFS_sint32 dlen;
499     PHYSFS_sint32 dlen_inc;
500     PHYSFS_sint32 max;
501     PHYSFS_sint32 i;
502
503     i = lzma_find_start_of_dir(archive, dname, 0);
504     if (i == -1)  /* no such directory. */
505         return;
506
507     dlen = strlen(dname);
508     if ((dlen > 0) && (dname[dlen - 1] == '/')) /* ignore trailing slash. */
509         dlen--;
510
511     dlen_inc = ((dlen > 0) ? 1 : 0) + dlen;
512     max = (PHYSFS_sint32) archive->db.Database.NumFiles;
513     while (i < max)
514     {
515         char *add;
516         char *ptr;
517         PHYSFS_sint32 ln;
518         char *e = archive->db.Database.Files[i].Name;
519         if ((dlen) && ((strncmp(e, dname, dlen)) || (e[dlen] != '/')))
520             break;  /* past end of this dir; we're done. */
521
522         add = e + dlen_inc;
523         ptr = strchr(add, '/');
524         ln = (PHYSFS_sint32) ((ptr) ? ptr-add : strlen(add));
525         doEnumCallback(cb, callbackdata, origdir, add, ln);
526         ln += dlen_inc;  /* point past entry to children... */
527
528         /* increment counter and skip children of subdirs... */
529         while ((++i < max) && (ptr != NULL))
530         {
531             char *e_new = archive->db.Database.Files[i].Name;
532             if ((strncmp(e, e_new, ln) != 0) || (e_new[ln] != '/'))
533                 break;
534         } /* while */
535     } /* while */
536 } /* LZMA_enumerateFiles */
537
538
539 static int LZMA_exists(dvoid *opaque, const char *name)
540 {
541     LZMAarchive *archive = (LZMAarchive *) opaque;
542     PHYSFS_uint32 index = 0;
543     return(lzma_find_entry(archive, name, &index));
544 } /* LZMA_exists */
545
546
547 static PHYSFS_sint64 LZMA_getLastModTime(dvoid *opaque,
548                                          const char *name,
549                                          int *fileExists)
550 {
551     /* !!! FIXME: Lacking support in the LZMA C SDK. */
552     BAIL_MACRO(ERR_NOT_IMPLEMENTED, -1);
553 } /* LZMA_getLastModTime */
554
555
556 static int LZMA_isDirectory(dvoid *opaque, const char *name, int *fileExists)
557 {
558     LZMAarchive *archive = (LZMAarchive *) opaque;
559     PHYSFS_uint32 index = 0;
560
561     *fileExists = lzma_find_entry(archive, name, &index);
562
563     return(archive->db.Database.Files[index].IsDirectory);
564 } /* LZMA_isDirectory */
565
566
567 static int LZMA_isSymLink(dvoid *opaque, const char *name, int *fileExists)
568 {
569     BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
570 } /* LZMA_isSymLink */
571
572
573 static fvoid *LZMA_openRead(dvoid *opaque, const char *name, int *fileExists)
574 {
575     LZMAarchive *archive = (LZMAarchive *) opaque;
576     LZMAentry *entry = NULL;
577     PHYSFS_uint32 fileIndex = 0;
578     PHYSFS_uint32 folderIndex = 0;
579
580     *fileExists = lzma_find_entry(archive, name, &fileIndex);
581     BAIL_IF_MACRO(!*fileExists, ERR_NO_SUCH_FILE, NULL);
582
583     folderIndex = archive->db.FileIndexToFolderIndexMap[fileIndex];
584     BAIL_IF_MACRO(folderIndex == (PHYSFS_uint32)-1, ERR_UNKNOWN_ERROR, NULL);
585
586     entry = (LZMAentry *) allocator.Malloc(sizeof (LZMAentry));
587     BAIL_IF_MACRO(entry == NULL, ERR_OUT_OF_MEMORY, NULL);
588
589     entry->fileIndex = fileIndex;
590     entry->folderIndex = folderIndex;
591     entry->archive = archive;
592     entry->file = archive->db.Database.Files + entry->fileIndex;
593     entry->offset = 0; /* Offset will be set by LZMA_read() */
594     entry->position = 0;
595
596     archive->folder[folderIndex].references++;
597
598     entry->next = NULL;
599     entry->previous = entry->archive->lastEntry;
600     if (entry->previous != NULL)
601         entry->previous->next = entry;
602     entry->archive->lastEntry = entry;
603     if (entry->archive->firstEntry == NULL)
604         entry->archive->firstEntry = entry;
605
606     return(entry);
607 } /* LZMA_openRead */
608
609
610 static fvoid *LZMA_openWrite(dvoid *opaque, const char *filename)
611 {
612     BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
613 } /* LZMA_openWrite */
614
615
616 static fvoid *LZMA_openAppend(dvoid *opaque, const char *filename)
617 {
618     BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
619 } /* LZMA_openAppend */
620
621
622 static void LZMA_dirClose(dvoid *opaque)
623 {
624     LZMAarchive *archive = (LZMAarchive *) opaque;
625     LZMAentry *entry = archive->firstEntry;
626     LZMAentry *tmpEntry = entry;
627
628     while (entry != NULL)
629     {
630         tmpEntry = entry->next;
631         LZMA_fileClose(entry);
632         entry = tmpEntry;
633     } /* while */
634
635     SzArDbExFree(&archive->db, SzFreePhysicsFS);
636     __PHYSFS_platformClose(archive->stream.File);
637
638     /* Free the cache which might have been allocated by LZMA_read() */
639     allocator.Free(archive->folder);
640     allocator.Free(archive);
641 } /* LZMA_dirClose */
642
643
644 static int LZMA_remove(dvoid *opaque, const char *name)
645 {
646     BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
647 } /* LZMA_remove */
648
649
650 static int LZMA_mkdir(dvoid *opaque, const char *name)
651 {
652     BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
653 } /* LZMA_mkdir */
654
655
656 const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_LZMA =
657 {
658     "7Z",
659     LZMA_ARCHIVE_DESCRIPTION,
660     "Dennis Schridde <devurandom@gmx.net>",
661     "http://icculus.org/physfs/",
662 };
663
664
665 const PHYSFS_Archiver __PHYSFS_Archiver_LZMA =
666 {
667     &__PHYSFS_ArchiveInfo_LZMA,
668     LZMA_isArchive,          /* isArchive() method      */
669     LZMA_openArchive,        /* openArchive() method    */
670     LZMA_enumerateFiles,     /* enumerateFiles() method */
671     LZMA_exists,             /* exists() method         */
672     LZMA_isDirectory,        /* isDirectory() method    */
673     LZMA_isSymLink,          /* isSymLink() method      */
674     LZMA_getLastModTime,     /* getLastModTime() method */
675     LZMA_openRead,           /* openRead() method       */
676     LZMA_openWrite,          /* openWrite() method      */
677     LZMA_openAppend,         /* openAppend() method     */
678     LZMA_remove,             /* remove() method         */
679     LZMA_mkdir,              /* mkdir() method          */
680     LZMA_dirClose,           /* dirClose() method       */
681     LZMA_read,               /* read() method           */
682     LZMA_write,              /* write() method          */
683     LZMA_eof,                /* eof() method            */
684     LZMA_tell,               /* tell() method           */
685     LZMA_seek,               /* seek() method           */
686     LZMA_fileLength,         /* fileLength() method     */
687     LZMA_fileClose           /* fileClose() method      */
688 };
689
690 #endif  /* defined PHYSFS_SUPPORTS_7Z */
691
692 /* end of lzma.c ... */
693