From a9d65e6d595fb62668c1c7dfb3c1f9c5d6904d5f Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sun, 5 Nov 2006 10:06:02 +0000 Subject: [PATCH] More 7zip work (thanks, Dennis!) --- CHANGELOG | 1 + archivers/lzma.c | 99 +++++++++++++++++++++++++++++++------------ lzma/LZMA-LICENSE.txt | 1 - 3 files changed, 73 insertions(+), 28 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9a1cc925..02ca4caa 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,7 @@ * CHANGELOG. */ +11052006 - More 7zip archiver work (thanks, Dennis!). 09272006 - Reworked 7zip archiver (thanks, Dennis!). 09232006 - Fixed typo in doxygen comment. 04112006 - Added LZMA archiver...7zip support (thanks, Dennis!). diff --git a/archivers/lzma.c b/archivers/lzma.c index b8b1253d..4e31621f 100644 --- a/archivers/lzma.c +++ b/archivers/lzma.c @@ -51,16 +51,29 @@ typedef struct _CFileInStream void *File; } CFileInStream; -/* Set by LZMA_openArchive, except blockXXX which is handled by LZMA_read() */ +/* + * In LZMA the archive is splited in blocks, those are called folders + * Set by LZMA_read() +*/ +typedef struct _LZMAfolder +{ + PHYSFS_uint8 *cache; /* Cached folder */ + PHYSFS_uint32 size; /* Size of folder */ + PHYSFS_uint32 index; /* Index of folder in archive */ + PHYSFS_uint32 references; /* Number of files using this block */ +} LZMAfolder; + +/* + * Set by LZMA_openArchive(), except folder which gets it's values + * in LZMA_read() + */ typedef struct _LZMAarchive { struct _LZMAentry *firstEntry; /* Used for cleanup on shutdown */ struct _LZMAentry *lastEntry; + LZMAfolder *folder; /* Array of folders */ CArchiveDatabaseEx db; /* For 7z: Database */ CFileInStream stream; /* For 7z: Input file incl. read and seek callbacks */ - unsigned char *block; /* Currently cached block */ - size_t blockSize; /* Size of current block */ - PHYSFS_uint32 blockIndex; /* Index of current block */ } LZMAarchive; /* Set by LZMA_openRead(), except offset which is set by LZMA_read() */ @@ -70,8 +83,9 @@ typedef struct _LZMAentry struct _LZMAentry *previous; LZMAarchive *archive; /* Link to corresponding archive */ CFileItem *file; /* For 7z: File info, eg. name, size */ - PHYSFS_uint32 index; /* Index inside the archive */ - size_t offset; /* Offset inside archive block */ + PHYSFS_uint32 fileIndex; /* Index of file in archive */ + PHYSFS_uint32 folderIndex; /* Index of folder in archive */ + size_t offset; /* Offset in folder */ PHYSFS_uint32 position; /* Current "virtual" position in file */ } LZMAentry; @@ -273,23 +287,30 @@ static PHYSFS_sint64 LZMA_read(fvoid *opaque, void *outBuffer, allocTempImp.Alloc = SzAllocPhysicsFS; allocTempImp.Free = SzFreePhysicsFS; - if (lzma_err(SzExtract( - &entry->archive->stream.InStream, /* compressed data */ - &entry->archive->db, - entry->index, - &entry->archive->blockIndex, /* Index of currently cached block, may be changed by SzExtract */ - &entry->archive->block, /* Cache of current decompressed block, may be allocated/freed by SzExtract */ - &entry->archive->blockSize, /* Size of current cache, may be changed by SzExtract */ - &entry->offset, /* Offset of this file inside the cache block, set by SzExtract */ - &fileSize, /* Size of this file */ - &allocImp, - &allocTempImp - )) != SZ_OK) - return -1; + /* Only decompress the folder if it is not allready cached */ + if (entry->archive->folder[entry->folderIndex].cache == NULL) + if (lzma_err(SzExtract( + &entry->archive->stream.InStream, /* compressed data */ + &entry->archive->db, + entry->fileIndex, + /* Index of cached folder, will be changed by SzExtract */ + &entry->archive->folder[entry->folderIndex].index, + /* Cache for decompressed folder, allocated/freed by SzExtract */ + &entry->archive->folder[entry->folderIndex].cache, + /* Size of cache, will be changed by SzExtract */ + &entry->archive->folder[entry->folderIndex].size, + /* Offset of this file inside the cache, set by SzExtract */ + &entry->offset, + &fileSize, /* Size of this file */ + &allocImp, + &allocTempImp + )) != SZ_OK) + return -1; /* Copy wanted bytes over from cache to outBuffer */ strncpy(outBuffer, - (void*)(entry->archive->block + entry->offset + entry->position), + (void*) (entry->archive->folder[entry->folderIndex].cache + + entry->offset + entry->position), wantedSize); entry->position += wantedSize; return objCount; @@ -352,6 +373,13 @@ static int LZMA_fileClose(fvoid *opaque) if (entry->next != NULL) entry->next->previous = entry->previous; + entry->archive->folder[entry->folderIndex].references--; + if (entry->archive->folder[entry->folderIndex].references == 0) + { + allocator.Free(entry->archive->folder[entry->folderIndex].cache); + entry->archive->folder[entry->folderIndex].cache = NULL; + } + allocator.Free(entry); entry = NULL; @@ -384,17 +412,17 @@ static int LZMA_isArchive(const char *filename, int forWriting) static void *LZMA_openArchive(const char *name, int forWriting) { + PHYSFS_uint64 len; LZMAarchive *archive = NULL; ISzAlloc allocImp; ISzAlloc allocTempImp; BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, NULL); - BAIL_IF_MACRO(!LZMA_isArchive(name, forWriting), ERR_UNSUPPORTED_ARCHIVE, 0); + BAIL_IF_MACRO(!LZMA_isArchive(name,forWriting), ERR_UNSUPPORTED_ARCHIVE, 0); archive = (LZMAarchive *) allocator.Malloc(sizeof (LZMAarchive)); BAIL_IF_MACRO(archive == NULL, ERR_OUT_OF_MEMORY, NULL); - archive->block = NULL; archive->firstEntry = NULL; archive->lastEntry = NULL; @@ -424,6 +452,16 @@ static void *LZMA_openArchive(const char *name, int forWriting) return NULL; } /* if */ + len = archive->db.Database.NumFolders * sizeof (LZMAfolder); + archive->folder = (LZMAfolder *) allocator.Malloc(len); + BAIL_IF_MACRO(archive->folder == NULL, ERR_OUT_OF_MEMORY, NULL); + + /* + * Init with 0 so we know when a folder is already cached + * Values will be set by LZMA_read() + */ + memset(archive->folder, 0, len); + return(archive); } /* LZMA_openArchive */ @@ -529,20 +567,27 @@ static fvoid *LZMA_openRead(dvoid *opaque, const char *name, int *fileExists) { LZMAarchive *archive = (LZMAarchive *) opaque; LZMAentry *entry = NULL; - PHYSFS_uint32 index = 0; + PHYSFS_uint32 fileIndex = 0; + PHYSFS_uint32 folderIndex = 0; - *fileExists = lzma_find_entry(archive, name, &index); + *fileExists = lzma_find_entry(archive, name, &fileIndex); BAIL_IF_MACRO(!*fileExists, ERR_NO_SUCH_FILE, NULL); + folderIndex = archive->db.FileIndexToFolderIndexMap[fileIndex]; + BAIL_IF_MACRO(folderIndex == (PHYSFS_uint32)-1, ERR_UNKNOWN_ERROR, NULL); + entry = (LZMAentry *) allocator.Malloc(sizeof (LZMAentry)); BAIL_IF_MACRO(entry == NULL, ERR_OUT_OF_MEMORY, NULL); - entry->index = index; + entry->fileIndex = fileIndex; + entry->folderIndex = folderIndex; entry->archive = archive; - entry->file = archive->db.Database.Files + entry->index; + entry->file = archive->db.Database.Files + entry->fileIndex; entry->offset = 0; /* Offset will be set by LZMA_read() */ entry->position = 0; + archive->folder[folderIndex].references++; + entry->next = NULL; entry->previous = entry->archive->lastEntry; if (entry->previous != NULL) @@ -584,7 +629,7 @@ static void LZMA_dirClose(dvoid *opaque) __PHYSFS_platformClose(archive->stream.File); /* Free the cache which might have been allocated by LZMA_read() */ - allocator.Free(archive->block); + allocator.Free(archive->folder); allocator.Free(archive); } /* LZMA_dirClose */ diff --git a/lzma/LZMA-LICENSE.txt b/lzma/LZMA-LICENSE.txt index 1645390f..d4e0f9f2 100644 --- a/lzma/LZMA-LICENSE.txt +++ b/lzma/LZMA-LICENSE.txt @@ -92,4 +92,3 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA You should have received a copy of the Common Public License along with this library. -k