From fd137cba4208ed2d87aef6c63d13dcd5df8f3e68 Mon Sep 17 00:00:00 2001 From: Aleksi Nurmi Date: Mon, 12 Nov 2012 23:40:29 +0200 Subject: [PATCH] SLB archiver --- CMakeLists.txt | 7 +++ docs/CREDITS.txt | 3 + src/archiver_slb.c | 121 ++++++++++++++++++++++++++++++++++++++++ src/archiver_unpacked.c | 2 +- src/physfs.c | 4 ++ src/physfs_internal.h | 5 +- 6 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 src/archiver_slb.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 132468b9..e9b8532e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -133,6 +133,7 @@ set(PHYSFS_SRCS src/archiver_qpak.c src/archiver_wad.c src/archiver_zip.c + src/archiver_slb.c src/archiver_iso9660.c ${PHYSFS_BEOS_SRCS} ) @@ -248,6 +249,11 @@ if(PHYSFS_ARCHIVE_QPAK) add_definitions(-DPHYSFS_SUPPORTS_QPAK=1) endif() +option(PHYSFS_ARCHIVE_SLB "Enable I-War / Independence War SLB support" TRUE) +if(PHYSFS_ARCHIVE_SLB) + add_definitions(-DPHYSFS_SUPPORTS_SLB=1) +endif() + option(PHYSFS_ARCHIVE_ISO9660 "Enable ISO9660 support" TRUE) if(PHYSFS_ARCHIVE_ISO9660) add_definitions(-DPHYSFS_SUPPORTS_ISO9660=1) @@ -364,6 +370,7 @@ message_bool_option("WAD support" PHYSFS_ARCHIVE_WAD) message_bool_option("HOG support" PHYSFS_ARCHIVE_HOG) message_bool_option("MVL support" PHYSFS_ARCHIVE_MVL) message_bool_option("QPAK support" PHYSFS_ARCHIVE_QPAK) +message_bool_option("SLB support" PHYSFS_ARCHIVE_SLB) message_bool_option("CD-ROM drive support" PHYSFS_HAVE_CDROM_SUPPORT) message_bool_option("Thread safety" PHYSFS_HAVE_THREAD_SUPPORT) message_bool_option("Build static library" PHYSFS_BUILD_STATIC) diff --git a/docs/CREDITS.txt b/docs/CREDITS.txt index 24ef612f..796f74f2 100644 --- a/docs/CREDITS.txt +++ b/docs/CREDITS.txt @@ -130,6 +130,9 @@ Bug fixes: Haiku fixes: Chris Roberts +SLB archiver: + Aleksi Nurmi + Other stuff: Your name here! Patches go to icculus@icculus.org ... diff --git a/src/archiver_slb.c b/src/archiver_slb.c new file mode 100644 index 00000000..4a1a78e2 --- /dev/null +++ b/src/archiver_slb.c @@ -0,0 +1,121 @@ +/* + * SLB support routines for PhysicsFS. + * + * This driver handles SLB archives ("slab files"). This uncompressed format + * is used in I-War / Independence War and Independence War: Defiance. + * + * The format begins with four zero bytes (version?), the file count and the + * location of the table of contents. Each ToC entry contains a 64-byte buffer + * containing a zero-terminated filename, the offset of the data, and its size. + * All the filenames begin with the separator character '\'. + * + * Please see the file LICENSE.txt in the source's root directory. + * + * This file written by Aleksi Nurmi, based on the GRP archiver by + * Ryan C. Gordon. + */ + +#define __PHYSICSFS_INTERNAL__ +#include "physfs_internal.h" + +#if PHYSFS_SUPPORTS_SLB + +static UNPKentry *slbLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 fileCount) +{ + UNPKentry *entries = NULL; + UNPKentry *entry = NULL; + + entries = (UNPKentry *) allocator.Malloc(sizeof (UNPKentry) * fileCount); + BAIL_IF_MACRO(entries == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + + for (entry = entries; fileCount > 0; fileCount--, entry++) + { + char *ptr; + + /* don't include the '\' in the beginning */ + char backslash; + GOTO_IF_MACRO(!__PHYSFS_readAll(io, &backslash, 1), ERRPASS, failed); + GOTO_IF_MACRO(backslash != '\\', ERRPASS, failed); + + /* read the rest of the buffer, 63 bytes */ + GOTO_IF_MACRO(!__PHYSFS_readAll(io, &entry->name, 63), ERRPASS, failed); + entry->name[63] = '\0'; /* in case the name lacks the null terminator */ + + /* convert backslashes */ + for (ptr = entry->name; *ptr; ptr++) + { + if (*ptr == '\\') + *ptr = '/'; + } /* for */ + + GOTO_IF_MACRO(!__PHYSFS_readAll(io, &entry->startPos, 4), + ERRPASS, failed); + entry->startPos = PHYSFS_swapULE32(entry->startPos); + + GOTO_IF_MACRO(!__PHYSFS_readAll(io, &entry->size, 4), ERRPASS, failed); + entry->size = PHYSFS_swapULE32(entry->size); + } /* for */ + + return entries; + +failed: + allocator.Free(entries); + return NULL; + +} /* slbLoadEntries */ + + +static void *SLB_openArchive(PHYSFS_Io *io, const char *name, int forWriting) +{ + PHYSFS_uint32 version; + PHYSFS_uint32 count = 0; + PHYSFS_uint32 tocPos = 0; + UNPKentry *entries = NULL; + + assert(io != NULL); /* shouldn't ever happen. */ + + BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL); + + BAIL_IF_MACRO(!__PHYSFS_readAll(io, &version, sizeof(version)), + ERRPASS, NULL); + version = PHYSFS_swapULE32(version); + BAIL_IF_MACRO(version != 0, ERRPASS, NULL); + + BAIL_IF_MACRO(!__PHYSFS_readAll(io, &count, sizeof(count)), ERRPASS, NULL); + count = PHYSFS_swapULE32(count); + + /* offset of the table of contents */ + BAIL_IF_MACRO(!__PHYSFS_readAll(io, &tocPos, sizeof(tocPos)), + ERRPASS, NULL); + tocPos = PHYSFS_swapULE32(tocPos); + + /* seek to the table of contents */ + BAIL_IF_MACRO(!io->seek(io, tocPos), ERRPASS, NULL); + + entries = slbLoadEntries(io, count); + BAIL_IF_MACRO(!entries, ERRPASS, NULL); + + return UNPK_openArchive(io, entries, count); +} /* SLB_openArchive */ + + +const PHYSFS_Archiver __PHYSFS_Archiver_SLB = +{ + { + "SLB", + "I-War / Independence War Slab file", + "Aleksi Nurmi ", + "http://bitbucket.org/ahnurmi/", + }, + SLB_openArchive, /* openArchive() method */ + UNPK_enumerateFiles, /* enumerateFiles() method */ + UNPK_openRead, /* openRead() method */ + UNPK_openWrite, /* openWrite() method */ + UNPK_openAppend, /* openAppend() method */ + UNPK_remove, /* remove() method */ + UNPK_mkdir, /* mkdir() method */ + UNPK_closeArchive, /* closeArchive() method */ + UNPK_stat /* stat() method */ +}; + +#endif /* defined PHYSFS_SUPPORTS_SLB */ diff --git a/src/archiver_unpacked.c b/src/archiver_unpacked.c index 1a7c104b..496766e2 100644 --- a/src/archiver_unpacked.c +++ b/src/archiver_unpacked.c @@ -7,7 +7,7 @@ * * RULES: Archive entries must be uncompressed, must not have separate subdir * entries (but can have subdirs), must be case insensitive LOW ASCII - * filenames <= 56 bytes. No symlinks, etc. We can relax some of these rules + * filenames <= 64 bytes. No symlinks, etc. We can relax some of these rules * as necessary. * * Please see the file LICENSE.txt in the source's root directory. diff --git a/src/physfs.c b/src/physfs.c index f57837e9..ef8ede6f 100644 --- a/src/physfs.c +++ b/src/physfs.c @@ -54,6 +54,7 @@ extern const PHYSFS_Archiver __PHYSFS_Archiver_QPAK; extern const PHYSFS_Archiver __PHYSFS_Archiver_HOG; extern const PHYSFS_Archiver __PHYSFS_Archiver_MVL; extern const PHYSFS_Archiver __PHYSFS_Archiver_WAD; +extern const PHYSFS_Archiver __PHYSFS_Archiver_SLB; extern const PHYSFS_Archiver __PHYSFS_Archiver_DIR; extern const PHYSFS_Archiver __PHYSFS_Archiver_ISO9660; @@ -80,6 +81,9 @@ static const PHYSFS_Archiver *staticArchivers[] = #if PHYSFS_SUPPORTS_WAD &__PHYSFS_Archiver_WAD, #endif +#if PHYSFS_SUPPORTS_SLB + &__PHYSFS_Archiver_SLB, +#endif #if PHYSFS_SUPPORTS_ISO9660 &__PHYSFS_Archiver_ISO9660, #endif diff --git a/src/physfs_internal.h b/src/physfs_internal.h index 1dec63fa..8836aa3b 100644 --- a/src/physfs_internal.h +++ b/src/physfs_internal.h @@ -114,6 +114,9 @@ void __PHYSFS_smallFree(void *ptr); #ifndef PHYSFS_SUPPORTS_WAD #define PHYSFS_SUPPORTS_WAD 0 #endif +#ifndef PHYSFS_SUPPORTS_SLB +#define PHYSFS_SUPPORTS_SLB 0 +#endif #ifndef PHYSFS_SUPPORTS_ISO9660 #define PHYSFS_SUPPORTS_ISO9660 0 #endif @@ -417,7 +420,7 @@ int __PHYSFS_readAll(PHYSFS_Io *io, void *buf, const PHYSFS_uint64 len); typedef struct { - char name[56]; + char name[64]; PHYSFS_uint32 startPos; PHYSFS_uint32 size; } UNPKentry;