physfs/src/archiver_slb.c

124 lines
3.4 KiB
C

/*
* 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 int slbLoadEntries(PHYSFS_Io *io, const PHYSFS_uint32 count, void *arc)
{
PHYSFS_uint32 i;
for (i = 0; i < count; i++)
{
PHYSFS_uint32 location;
PHYSFS_uint32 size;
char name[64];
char backslash;
char *ptr;
/* don't include the '\' in the beginning */
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &backslash, 1), 0);
BAIL_IF(backslash != '\\', PHYSFS_ERR_CORRUPT, 0);
/* read the rest of the buffer, 63 bytes */
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &name, 63), 0);
name[63] = '\0'; /* in case the name lacks the null terminator */
/* convert backslashes */
for (ptr = name; *ptr; ptr++)
{
if (*ptr == '\\')
*ptr = '/';
} /* for */
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &location, 4), 0);
location = PHYSFS_swapULE32(location);
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &size, 4), 0);
size = PHYSFS_swapULE32(size);
BAIL_IF_ERRPASS(!UNPK_addEntry(arc, name, 0, location, size), 0);
} /* for */
return 1;
} /* slbLoadEntries */
static void *SLB_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
{
PHYSFS_uint32 version;
PHYSFS_uint32 count;
PHYSFS_uint32 tocPos;
void *unpkarc;
assert(io != NULL); /* shouldn't ever happen. */
BAIL_IF(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &version, sizeof (version)), NULL);
version = PHYSFS_swapULE32(version);
BAIL_IF(version != 0, PHYSFS_ERR_UNSUPPORTED, NULL);
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &count, sizeof (count)), NULL);
count = PHYSFS_swapULE32(count);
/* offset of the table of contents */
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &tocPos, sizeof (tocPos)), NULL);
tocPos = PHYSFS_swapULE32(tocPos);
/* seek to the table of contents */
BAIL_IF_ERRPASS(!io->seek(io, tocPos), NULL);
unpkarc = UNPK_openArchive(io, count);
BAIL_IF_ERRPASS(!unpkarc, NULL);
if (!slbLoadEntries(io, count, unpkarc))
{
UNPK_closeArchive(unpkarc);
return NULL;
} /* if */
return unpkarc;
} /* SLB_openArchive */
const PHYSFS_Archiver __PHYSFS_Archiver_SLB =
{
CURRENT_PHYSFS_ARCHIVER_API_VERSION,
{
"SLB",
"I-War / Independence War Slab file",
"Aleksi Nurmi <aleksi.nurmi@gmail.com>",
"https://bitbucket.org/ahnurmi/",
0, /* supportsSymlinks */
},
SLB_openArchive,
UNPK_enumerateFiles,
UNPK_openRead,
UNPK_openWrite,
UNPK_openAppend,
UNPK_remove,
UNPK_mkdir,
UNPK_stat,
UNPK_closeArchive
};
#endif /* defined PHYSFS_SUPPORTS_SLB */
/* end of archiver_slb.c ... */