Moved most the cut-and-paste between simple archivers to one file.

This commit is contained in:
Ryan C. Gordon 2010-09-06 02:50:29 -04:00
parent 9d900f8814
commit 3f02ce767f
7 changed files with 478 additions and 1391 deletions

View File

@ -141,6 +141,7 @@ SET(PHYSFS_SRCS
src/platform_macosx.c
src/platform_windows.c
src/archiver_dir.c
src/archiver_unpacked.c
src/archiver_grp.c
src/archiver_hog.c
src/archiver_lzma.c

View File

@ -34,188 +34,27 @@
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
typedef struct
{
char name[13];
PHYSFS_uint32 startPos;
PHYSFS_uint32 size;
} GRPentry;
typedef struct
{
PHYSFS_Io *io;
PHYSFS_uint32 entryCount;
GRPentry *entries;
} GRPinfo;
typedef struct
{
PHYSFS_Io *io;
GRPentry *entry;
PHYSFS_uint32 curPos;
} GRPfileinfo;
static inline int readAll(PHYSFS_Io *io, void *buf, const PHYSFS_uint64 len)
{
return (io->read(io, buf, len) == len);
} /* readAll */
static void GRP_dirClose(dvoid *opaque)
static UNPKentry *grpLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 fileCount)
{
GRPinfo *info = ((GRPinfo *) opaque);
info->io->destroy(info->io);
allocator.Free(info->entries);
allocator.Free(info);
} /* GRP_dirClose */
static PHYSFS_sint64 GRP_read(PHYSFS_Io *io, void *buffer, PHYSFS_uint64 len)
{
GRPfileinfo *finfo = (GRPfileinfo *) io->opaque;
const GRPentry *entry = finfo->entry;
const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos);
PHYSFS_sint64 rc;
if (bytesLeft < len)
len = bytesLeft;
rc = finfo->io->read(finfo->io, buffer, len);
if (rc > 0)
finfo->curPos += (PHYSFS_uint32) rc;
return rc;
} /* GRP_read */
static PHYSFS_sint64 GRP_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
} /* GRP_write */
static PHYSFS_sint64 GRP_tell(PHYSFS_Io *io)
{
return ((GRPfileinfo *) io->opaque)->curPos;
} /* GRP_tell */
static int GRP_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
{
GRPfileinfo *finfo = (GRPfileinfo *) io->opaque;
const GRPentry *entry = finfo->entry;
int rc;
BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
rc = finfo->io->seek(finfo->io, entry->startPos + offset);
if (rc)
finfo->curPos = (PHYSFS_uint32) offset;
return rc;
} /* GRP_seek */
static PHYSFS_sint64 GRP_length(PHYSFS_Io *io)
{
const GRPfileinfo *finfo = (GRPfileinfo *) io->opaque;
return ((PHYSFS_sint64) finfo->entry->size);
} /* GRP_length */
static PHYSFS_Io *GRP_duplicate(PHYSFS_Io *_io)
{
GRPfileinfo *origfinfo = (GRPfileinfo *) _io->opaque;
PHYSFS_Io *io = NULL;
PHYSFS_Io *retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
GRPfileinfo *finfo = (GRPfileinfo *) allocator.Malloc(sizeof (GRPfileinfo));
GOTO_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, GRP_duplicate_failed);
GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, GRP_duplicate_failed);
io = origfinfo->io->duplicate(origfinfo->io);
GOTO_IF_MACRO(io == NULL, NULL, GRP_duplicate_failed);
finfo->io = io;
finfo->entry = origfinfo->entry;
finfo->curPos = 0;
memcpy(retval, _io, sizeof (PHYSFS_Io));
retval->opaque = finfo;
return retval;
GRP_duplicate_failed:
if (finfo != NULL) allocator.Free(finfo);
if (retval != NULL) allocator.Free(retval);
if (io != NULL) io->destroy(io);
return NULL;
} /* GRP_duplicate */
static int GRP_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
static void GRP_destroy(PHYSFS_Io *io)
{
GRPfileinfo *finfo = (GRPfileinfo *) io->opaque;
finfo->io->destroy(finfo->io);
allocator.Free(finfo);
allocator.Free(io);
} /* GRP_destroy */
static const PHYSFS_Io GRP_Io =
{
GRP_read,
GRP_write,
GRP_seek,
GRP_tell,
GRP_length,
GRP_duplicate,
GRP_flush,
GRP_destroy,
NULL
};
static int grpEntryCmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
{
if (one != two)
{
const GRPentry *a = (const GRPentry *) _a;
return __PHYSFS_stricmpASCII(a[one].name, a[two].name);
} /* if */
return 0;
} /* grpEntryCmp */
static void grpEntrySwap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
{
if (one != two)
{
GRPentry tmp;
GRPentry *first = &(((GRPentry *) _a)[one]);
GRPentry *second = &(((GRPentry *) _a)[two]);
memcpy(&tmp, first, sizeof (GRPentry));
memcpy(first, second, sizeof (GRPentry));
memcpy(second, &tmp, sizeof (GRPentry));
} /* if */
} /* grpEntrySwap */
static int grp_load_entries(PHYSFS_Io *io, GRPinfo *info)
{
PHYSFS_uint32 fileCount = info->entryCount;
PHYSFS_uint32 location = 16; /* sizeof sig. */
GRPentry *entry;
char *ptr;
UNPKentry *entries = NULL;
UNPKentry *entry = NULL;
char *ptr = NULL;
info->entries = (GRPentry *) allocator.Malloc(sizeof(GRPentry)*fileCount);
BAIL_IF_MACRO(info->entries == NULL, ERR_OUT_OF_MEMORY, 0);
entries = (UNPKentry *) allocator.Malloc(sizeof (UNPKentry) * fileCount);
BAIL_IF_MACRO(entries == NULL, ERR_OUT_OF_MEMORY, NULL);
location += (16 * fileCount);
for (entry = info->entries; fileCount > 0; fileCount--, entry++)
for (entry = entries; fileCount > 0; fileCount--, entry++)
{
BAIL_IF_MACRO(!readAll(io, &entry->name, 12), NULL, 0);
BAIL_IF_MACRO(!readAll(io, &entry->size, 4), NULL, 0);
GOTO_IF_MACRO(!readAll(io, &entry->name, 12), NULL, grpLoad_failed);
GOTO_IF_MACRO(!readAll(io, &entry->size, 4), NULL, grpLoad_failed);
entry->name[12] = '\0'; /* name isn't null-terminated in file. */
if ((ptr = strchr(entry->name, ' ')) != NULL)
*ptr = '\0'; /* trim extra spaces. */
@ -225,16 +64,19 @@ static int grp_load_entries(PHYSFS_Io *io, GRPinfo *info)
location += entry->size;
} /* for */
__PHYSFS_sort(info->entries, info->entryCount, grpEntryCmp, grpEntrySwap);
return 1;
} /* grp_load_entries */
return entries;
grpLoad_failed:
allocator.Free(entries);
return NULL;
} /* grpLoadEntries */
static void *GRP_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
{
PHYSFS_uint8 buf[12];
GRPinfo *info = NULL;
PHYSFS_uint32 val = 0;
PHYSFS_uint32 entryCount = 0;
UNPKentry *entries = NULL;
assert(io != NULL); /* shouldn't ever happen. */
@ -242,173 +84,17 @@ static void *GRP_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
BAIL_IF_MACRO(!readAll(io, buf, sizeof (buf)), NULL, NULL);
if (memcmp(buf, "KenSilverman", sizeof (buf)) != 0)
GOTO_MACRO(ERR_NOT_AN_ARCHIVE, GRP_openArchive_failed);
BAIL_MACRO(ERR_NOT_AN_ARCHIVE, NULL);
info = (GRPinfo *) allocator.Malloc(sizeof (GRPinfo));
GOTO_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, GRP_openArchive_failed);
memset(info, '\0', sizeof (GRPinfo));
info->io = io;
BAIL_IF_MACRO(!readAll(io, &entryCount, sizeof (entryCount)), NULL, NULL);
entryCount = PHYSFS_swapULE32(entryCount);
GOTO_IF_MACRO(!readAll(io,&val,sizeof(val)), NULL, GRP_openArchive_failed);
info->entryCount = PHYSFS_swapULE32(val);
GOTO_IF_MACRO(!grp_load_entries(io, info), NULL, GRP_openArchive_failed);
return info;
GRP_openArchive_failed:
if (info != NULL)
{
if (info->entries != NULL)
allocator.Free(info->entries);
allocator.Free(info);
} /* if */
return NULL;
entries = grpLoadEntries(io, entryCount);
BAIL_IF_MACRO(entries == NULL, NULL, NULL);
return UNPK_openArchive(io, entries, entryCount);
} /* GRP_openArchive */
static void GRP_enumerateFiles(dvoid *opaque, const char *dname,
int omitSymLinks, PHYSFS_EnumFilesCallback cb,
const char *origdir, void *callbackdata)
{
/* no directories in GRP files. */
if (*dname == '\0')
{
GRPinfo *info = (GRPinfo *) opaque;
GRPentry *entry = info->entries;
PHYSFS_uint32 max = info->entryCount;
PHYSFS_uint32 i;
for (i = 0; i < max; i++, entry++)
cb(callbackdata, origdir, entry->name);
} /* if */
} /* GRP_enumerateFiles */
static GRPentry *grp_find_entry(const GRPinfo *info, const char *name)
{
char *ptr = strchr(name, '.');
GRPentry *a = info->entries;
PHYSFS_sint32 lo = 0;
PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
PHYSFS_sint32 middle;
int rc;
/*
* Rule out filenames to avoid unneeded processing...no dirs,
* big filenames, or extensions > 3 chars.
*/
BAIL_IF_MACRO((ptr) && (strlen(ptr) > 4), ERR_NO_SUCH_FILE, NULL);
BAIL_IF_MACRO(strlen(name) > 12, ERR_NO_SUCH_FILE, NULL);
BAIL_IF_MACRO(strchr(name, '/') != NULL, ERR_NO_SUCH_FILE, NULL);
while (lo <= hi)
{
middle = lo + ((hi - lo) / 2);
rc = __PHYSFS_stricmpASCII(name, a[middle].name);
if (rc == 0) /* found it! */
return &a[middle];
else if (rc > 0)
lo = middle + 1;
else
hi = middle - 1;
} /* while */
BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
} /* grp_find_entry */
static PHYSFS_Io *GRP_openRead(dvoid *opaque, const char *fnm, int *fileExists)
{
PHYSFS_Io *retval = NULL;
GRPinfo *info = (GRPinfo *) opaque;
GRPfileinfo *finfo;
GRPentry *entry;
entry = grp_find_entry(info, fnm);
*fileExists = (entry != NULL);
GOTO_IF_MACRO(entry == NULL, NULL, GRP_openRead_failed);
retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
GOTO_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, GRP_openRead_failed);
finfo = (GRPfileinfo *) allocator.Malloc(sizeof (GRPfileinfo));
GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, GRP_openRead_failed);
finfo->io = info->io->duplicate(info->io);
GOTO_IF_MACRO(finfo->io == NULL, NULL, GRP_openRead_failed);
if (!finfo->io->seek(finfo->io, entry->startPos))
GOTO_MACRO(NULL, GRP_openRead_failed);
finfo->curPos = 0;
finfo->entry = entry;
memcpy(retval, &GRP_Io, sizeof (*retval));
retval->opaque = finfo;
return retval;
GRP_openRead_failed:
if (finfo != NULL)
{
if (finfo->io != NULL)
finfo->io->destroy(finfo->io);
allocator.Free(finfo);
} /* if */
if (retval != NULL)
allocator.Free(retval);
return NULL;
} /* GRP_openRead */
static PHYSFS_Io *GRP_openWrite(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* GRP_openWrite */
static PHYSFS_Io *GRP_openAppend(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* GRP_openAppend */
static int GRP_remove(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* GRP_remove */
static int GRP_mkdir(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* GRP_mkdir */
static int GRP_stat(dvoid *opaque, const char *filename, int *exists,
PHYSFS_Stat *stat)
{
const GRPinfo *info = (const GRPinfo *) opaque;
const GRPentry *entry = grp_find_entry(info, filename);
*exists = (entry != 0);
if (!entry)
return 0;
stat->filesize = entry->size;
stat->filetype = PHYSFS_FILETYPE_REGULAR;
stat->modtime = -1;
stat->createtime = -1;
stat->accesstime = -1;
stat->readonly = 1;
return 1;
} /* GRP_stat */
const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_GRP =
{
"GRP",
@ -422,14 +108,14 @@ const PHYSFS_Archiver __PHYSFS_Archiver_GRP =
{
&__PHYSFS_ArchiveInfo_GRP,
GRP_openArchive, /* openArchive() method */
GRP_enumerateFiles, /* enumerateFiles() method */
GRP_openRead, /* openRead() method */
GRP_openWrite, /* openWrite() method */
GRP_openAppend, /* openAppend() method */
GRP_remove, /* remove() method */
GRP_mkdir, /* mkdir() method */
GRP_dirClose, /* dirClose() method */
GRP_stat /* stat() 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_dirClose, /* dirClose() method */
UNPK_stat /* stat() method */
};
#endif /* defined PHYSFS_SUPPORTS_GRP */

View File

@ -39,392 +39,68 @@
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
/*
* One HOGentry is kept for each file in an open HOG archive.
*/
typedef struct
{
char name[13];
PHYSFS_uint32 startPos;
PHYSFS_uint32 size;
} HOGentry;
/*
* One HOGinfo is kept for each open HOG archive.
*/
typedef struct
{
PHYSFS_Io *io;
PHYSFS_uint32 entryCount;
HOGentry *entries;
} HOGinfo;
/*
* One HOGfileinfo is kept for each open file in a HOG archive.
*/
typedef struct
{
PHYSFS_Io *io;
HOGentry *entry;
PHYSFS_uint32 curPos;
} HOGfileinfo;
static inline int readAll(PHYSFS_Io *io, void *buf, const PHYSFS_uint64 len)
{
return (io->read(io, buf, len) == len);
} /* readAll */
static void HOG_dirClose(dvoid *opaque)
{
HOGinfo *info = ((HOGinfo *) opaque);
info->io->destroy(info->io);
allocator.Free(info->entries);
allocator.Free(info);
} /* HOG_dirClose */
static PHYSFS_sint64 HOG_read(PHYSFS_Io *io, void *buffer, PHYSFS_uint64 len)
{
HOGfileinfo *finfo = (HOGfileinfo *) io->opaque;
const HOGentry *entry = finfo->entry;
const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos);
PHYSFS_sint64 rc;
if (bytesLeft < len)
len = bytesLeft;
rc = finfo->io->read(finfo->io, buffer, len);
if (rc > 0)
finfo->curPos += (PHYSFS_uint32) rc;
return rc;
} /* HOG_read */
static PHYSFS_sint64 HOG_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
} /* HOG_write */
static PHYSFS_sint64 HOG_tell(PHYSFS_Io *io)
{
return ((HOGfileinfo *) io->opaque)->curPos;
} /* HOG_tell */
static int HOG_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
{
HOGfileinfo *finfo = (HOGfileinfo *) io->opaque;
const HOGentry *entry = finfo->entry;
int rc;
BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
rc = finfo->io->seek(finfo->io, entry->startPos + offset);
if (rc)
finfo->curPos = (PHYSFS_uint32) offset;
return rc;
} /* HOG_seek */
static PHYSFS_sint64 HOG_length(PHYSFS_Io *io)
{
const HOGfileinfo *finfo = (HOGfileinfo *) io->opaque;
return ((PHYSFS_sint64) finfo->entry->size);
} /* HOG_length */
static PHYSFS_Io *HOG_duplicate(PHYSFS_Io *_io)
{
HOGfileinfo *origfinfo = (HOGfileinfo *) _io->opaque;
PHYSFS_Io *io = NULL;
PHYSFS_Io *retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
HOGfileinfo *finfo = (HOGfileinfo *) allocator.Malloc(sizeof (HOGfileinfo));
GOTO_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, HOG_duplicate_failed);
GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, HOG_duplicate_failed);
io = origfinfo->io->duplicate(origfinfo->io);
GOTO_IF_MACRO(io == NULL, NULL, HOG_duplicate_failed);
finfo->io = io;
finfo->entry = origfinfo->entry;
finfo->curPos = 0;
memcpy(retval, _io, sizeof (PHYSFS_Io));
retval->opaque = finfo;
return retval;
HOG_duplicate_failed:
if (finfo != NULL) allocator.Free(finfo);
if (retval != NULL) allocator.Free(retval);
if (io != NULL) io->destroy(io);
return NULL;
} /* HOG_duplicate */
static int HOG_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
static void HOG_destroy(PHYSFS_Io *io)
{
HOGfileinfo *finfo = (HOGfileinfo *) io->opaque;
finfo->io->destroy(finfo->io);
allocator.Free(finfo);
allocator.Free(io);
} /* HOG_destroy */
static const PHYSFS_Io HOG_Io =
{
HOG_read,
HOG_write,
HOG_seek,
HOG_tell,
HOG_length,
HOG_duplicate,
HOG_flush,
HOG_destroy,
NULL
};
static int hogEntryCmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
{
if (one != two)
{
const HOGentry *a = (const HOGentry *) _a;
return __PHYSFS_stricmpASCII(a[one].name, a[two].name);
} /* if */
return 0;
} /* hogEntryCmp */
static void hogEntrySwap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
{
if (one != two)
{
HOGentry tmp;
HOGentry *first = &(((HOGentry *) _a)[one]);
HOGentry *second = &(((HOGentry *) _a)[two]);
memcpy(&tmp, first, sizeof (HOGentry));
memcpy(first, second, sizeof (HOGentry));
memcpy(second, &tmp, sizeof (HOGentry));
} /* if */
} /* hogEntrySwap */
static int hog_load_entries(PHYSFS_Io *io, HOGinfo *info)
static UNPKentry *hogLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 *_entCount)
{
const PHYSFS_uint64 iolen = io->length(io);
PHYSFS_uint32 entCount = 0;
void *ptr = NULL;
HOGentry *entry = NULL;
UNPKentry *entries = NULL;
UNPKentry *entry = NULL;
PHYSFS_uint32 size = 0;
PHYSFS_uint32 pos = 3;
while (pos < iolen)
{
entCount++;
ptr = allocator.Realloc(ptr, sizeof (HOGentry) * entCount);
BAIL_IF_MACRO(ptr == NULL, ERR_OUT_OF_MEMORY, 0);
info->entries = (HOGentry *) ptr;
entry = &info->entries[entCount-1];
ptr = allocator.Realloc(ptr, sizeof (UNPKentry) * entCount);
GOTO_IF_MACRO(ptr == NULL, ERR_OUT_OF_MEMORY, hogLoad_failed);
entries = (UNPKentry *) ptr;
entry = &entries[entCount-1];
BAIL_IF_MACRO(!readAll(io, &entry->name, 13), NULL, 0);
GOTO_IF_MACRO(!readAll(io, &entry->name, 13), NULL, hogLoad_failed);
pos += 13;
BAIL_IF_MACRO(!readAll(io, &size, 4), NULL, 0);
GOTO_IF_MACRO(!readAll(io, &size, 4), NULL, hogLoad_failed);
pos += 4;
entry->size = PHYSFS_swapULE32(size);
entry->startPos = pos;
pos += size;
BAIL_IF_MACRO(!io->seek(io, pos), NULL, 0); /* skip over entry */
} /* for */
/* skip over entry */
GOTO_IF_MACRO(!io->seek(io, pos), NULL, hogLoad_failed);
} /* while */
info->entryCount = entCount;
*_entCount = entCount;
return entries;
__PHYSFS_sort(info->entries, entCount, hogEntryCmp, hogEntrySwap);
return 1;
} /* hog_load_entries */
hogLoad_failed:
allocator.Free(entries);
return NULL;
} /* hogLoadEntries */
static void *HOG_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
{
PHYSFS_uint8 buf[3];
HOGinfo *info = NULL;
PHYSFS_uint32 entryCount = 0;
UNPKentry *entries = NULL;
assert(io != NULL); /* shouldn't ever happen. */
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
BAIL_IF_MACRO(!readAll(io, buf, 3), NULL, 0);
if (memcmp(buf, "DHF", 3) != 0)
GOTO_MACRO(ERR_NOT_AN_ARCHIVE, HOG_openArchive_failed);
BAIL_IF_MACRO(memcmp(buf, "DHF", 3) != 0, ERR_NOT_AN_ARCHIVE, NULL);
info = (HOGinfo *) allocator.Malloc(sizeof (HOGinfo));
GOTO_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, HOG_openArchive_failed);
memset(info, '\0', sizeof (HOGinfo));
info->io = io;
GOTO_IF_MACRO(!hog_load_entries(io, info), NULL, HOG_openArchive_failed);
return info;
HOG_openArchive_failed:
if (info != NULL)
{
if (info->entries != NULL)
allocator.Free(info->entries);
allocator.Free(info);
} /* if */
return NULL;
entries = hogLoadEntries(io, &entryCount);
BAIL_IF_MACRO(entries == NULL, NULL, NULL);
return UNPK_openArchive(io, entries, entryCount);
} /* HOG_openArchive */
static void HOG_enumerateFiles(dvoid *opaque, const char *dname,
int omitSymLinks, PHYSFS_EnumFilesCallback cb,
const char *origdir, void *callbackdata)
{
/* no directories in HOG files. */
if (*dname == '\0')
{
HOGinfo *info = (HOGinfo *) opaque;
HOGentry *entry = info->entries;
PHYSFS_uint32 max = info->entryCount;
PHYSFS_uint32 i;
for (i = 0; i < max; i++, entry++)
cb(callbackdata, origdir, entry->name);
} /* if */
} /* HOG_enumerateFiles */
static HOGentry *hog_find_entry(const HOGinfo *info, const char *name)
{
char *ptr = strchr(name, '.');
HOGentry *a = info->entries;
PHYSFS_sint32 lo = 0;
PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
PHYSFS_sint32 middle;
int rc;
/*
* Rule out filenames to avoid unneeded processing...no dirs,
* big filenames, or extensions > 3 chars.
*/
BAIL_IF_MACRO((ptr) && (strlen(ptr) > 4), ERR_NO_SUCH_FILE, NULL);
BAIL_IF_MACRO(strlen(name) > 12, ERR_NO_SUCH_FILE, NULL);
BAIL_IF_MACRO(strchr(name, '/') != NULL, ERR_NO_SUCH_FILE, NULL);
while (lo <= hi)
{
middle = lo + ((hi - lo) / 2);
rc = __PHYSFS_stricmpASCII(name, a[middle].name);
if (rc == 0) /* found it! */
return &a[middle];
else if (rc > 0)
lo = middle + 1;
else
hi = middle - 1;
} /* while */
BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
} /* hog_find_entry */
static PHYSFS_Io *HOG_openRead(dvoid *opaque, const char *fnm, int *fileExists)
{
PHYSFS_Io *retval = NULL;
HOGinfo *info = (HOGinfo *) opaque;
HOGfileinfo *finfo;
HOGentry *entry;
entry = hog_find_entry(info, fnm);
*fileExists = (entry != NULL);
GOTO_IF_MACRO(entry == NULL, NULL, HOG_openRead_failed);
retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
GOTO_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, HOG_openRead_failed);
finfo = (HOGfileinfo *) allocator.Malloc(sizeof (HOGfileinfo));
GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, HOG_openRead_failed);
finfo->io = info->io->duplicate(info->io);
GOTO_IF_MACRO(finfo->io == NULL, NULL, HOG_openRead_failed);
if (!finfo->io->seek(finfo->io, entry->startPos))
GOTO_MACRO(NULL, HOG_openRead_failed);
finfo->curPos = 0;
finfo->entry = entry;
memcpy(retval, &HOG_Io, sizeof (*retval));
retval->opaque = finfo;
return retval;
HOG_openRead_failed:
if (finfo != NULL)
{
if (finfo->io != NULL)
finfo->io->destroy(finfo->io);
allocator.Free(finfo);
} /* if */
if (retval != NULL)
allocator.Free(retval);
return NULL;
} /* HOG_openRead */
static PHYSFS_Io *HOG_openWrite(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* HOG_openWrite */
static PHYSFS_Io *HOG_openAppend(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* HOG_openAppend */
static int HOG_remove(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* HOG_remove */
static int HOG_mkdir(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* HOG_mkdir */
static int HOG_stat(dvoid *opaque, const char *filename, int *exists,
PHYSFS_Stat *stat)
{
const HOGinfo *info = (const HOGinfo *) opaque;
const HOGentry *entry = hog_find_entry(info, filename);
*exists = (entry != 0);
if (!entry)
return 0;
stat->filesize = entry->size;
stat->filetype = PHYSFS_FILETYPE_REGULAR;
stat->modtime = -1;
stat->createtime = -1;
stat->accesstime = -1;
stat->readonly = 1;
return 1;
} /* HOG_stat */
const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_HOG =
{
"HOG",
@ -438,14 +114,14 @@ const PHYSFS_Archiver __PHYSFS_Archiver_HOG =
{
&__PHYSFS_ArchiveInfo_HOG,
HOG_openArchive, /* openArchive() method */
HOG_enumerateFiles, /* enumerateFiles() method */
HOG_openRead, /* openRead() method */
HOG_openWrite, /* openWrite() method */
HOG_openAppend, /* openAppend() method */
HOG_remove, /* remove() method */
HOG_mkdir, /* mkdir() method */
HOG_dirClose, /* dirClose() method */
HOG_stat /* stat() 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_dirClose, /* dirClose() method */
UNPK_stat /* stat() method */
};
#endif /* defined PHYSFS_SUPPORTS_HOG */

View File

@ -37,27 +37,6 @@
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
typedef struct
{
char name[13];
PHYSFS_uint32 startPos;
PHYSFS_uint32 size;
} MVLentry;
typedef struct
{
PHYSFS_Io *io;
PHYSFS_uint32 entryCount;
MVLentry *entries;
} MVLinfo;
typedef struct
{
PHYSFS_Io *io;
MVLentry *entry;
PHYSFS_uint32 curPos;
} MVLfileinfo;
static inline int readAll(PHYSFS_Io *io, void *buf, const PHYSFS_uint64 len)
{
@ -65,347 +44,53 @@ static inline int readAll(PHYSFS_Io *io, void *buf, const PHYSFS_uint64 len)
} /* readAll */
static void MVL_dirClose(dvoid *opaque)
static UNPKentry *mvlLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 fileCount)
{
MVLinfo *info = ((MVLinfo *) opaque);
info->io->destroy(info->io);
allocator.Free(info->entries);
allocator.Free(info);
} /* MVL_dirClose */
static PHYSFS_sint64 MVL_read(PHYSFS_Io *io, void *buffer, PHYSFS_uint64 len)
{
MVLfileinfo *finfo = (MVLfileinfo *) io->opaque;
const MVLentry *entry = finfo->entry;
const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos);
PHYSFS_sint64 rc;
if (bytesLeft < len)
len = bytesLeft;
rc = finfo->io->read(finfo->io, buffer, len);
if (rc > 0)
finfo->curPos += (PHYSFS_uint32) rc;
return rc;
} /* MVL_read */
static PHYSFS_sint64 MVL_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
} /* MVL_write */
static PHYSFS_sint64 MVL_tell(PHYSFS_Io *io)
{
return ((MVLfileinfo *) io->opaque)->curPos;
} /* MVL_tell */
static int MVL_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
{
MVLfileinfo *finfo = (MVLfileinfo *) io->opaque;
const MVLentry *entry = finfo->entry;
int rc;
BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
rc = finfo->io->seek(finfo->io, entry->startPos + offset);
if (rc)
finfo->curPos = (PHYSFS_uint32) offset;
return rc;
} /* MVL_seek */
static PHYSFS_sint64 MVL_length(PHYSFS_Io *io)
{
const MVLfileinfo *finfo = (MVLfileinfo *) io->opaque;
return ((PHYSFS_sint64) finfo->entry->size);
} /* MVL_length */
static PHYSFS_Io *MVL_duplicate(PHYSFS_Io *_io)
{
MVLfileinfo *origfinfo = (MVLfileinfo *) _io->opaque;
PHYSFS_Io *io = NULL;
PHYSFS_Io *retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
MVLfileinfo *finfo = (MVLfileinfo *) allocator.Malloc(sizeof (MVLfileinfo));
GOTO_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, MVL_duplicate_failed);
GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, MVL_duplicate_failed);
io = origfinfo->io->duplicate(origfinfo->io);
GOTO_IF_MACRO(io == NULL, NULL, MVL_duplicate_failed);
finfo->io = io;
finfo->entry = origfinfo->entry;
finfo->curPos = 0;
memcpy(retval, _io, sizeof (PHYSFS_Io));
retval->opaque = finfo;
return retval;
MVL_duplicate_failed:
if (finfo != NULL) allocator.Free(finfo);
if (retval != NULL) allocator.Free(retval);
if (io != NULL) io->destroy(io);
return NULL;
} /* MVL_duplicate */
static int MVL_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
static void MVL_destroy(PHYSFS_Io *io)
{
MVLfileinfo *finfo = (MVLfileinfo *) io->opaque;
finfo->io->destroy(finfo->io);
allocator.Free(finfo);
allocator.Free(io);
} /* MVL_destroy */
static const PHYSFS_Io MVL_Io =
{
MVL_read,
MVL_write,
MVL_seek,
MVL_tell,
MVL_length,
MVL_duplicate,
MVL_flush,
MVL_destroy,
NULL
};
static int mvlEntryCmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
{
if (one != two)
{
const MVLentry *a = (const MVLentry *) _a;
return __PHYSFS_stricmpASCII(a[one].name, a[two].name);
} /* if */
return 0;
} /* mvlEntryCmp */
static void mvlEntrySwap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
{
if (one != two)
{
MVLentry tmp;
MVLentry *first = &(((MVLentry *) _a)[one]);
MVLentry *second = &(((MVLentry *) _a)[two]);
memcpy(&tmp, first, sizeof (MVLentry));
memcpy(first, second, sizeof (MVLentry));
memcpy(second, &tmp, sizeof (MVLentry));
} /* if */
} /* mvlEntrySwap */
static int mvl_load_entries(PHYSFS_Io *io, MVLinfo *info)
{
PHYSFS_uint32 fileCount = info->entryCount;
PHYSFS_uint32 location = 8; /* sizeof sig. */
MVLentry *entry;
UNPKentry *entries = NULL;
UNPKentry *entry = NULL;
info->entries = (MVLentry *) allocator.Malloc(sizeof(MVLentry)*fileCount);
BAIL_IF_MACRO(info->entries == NULL, ERR_OUT_OF_MEMORY, 0);
entries = (UNPKentry *) allocator.Malloc(sizeof (UNPKentry) * fileCount);
BAIL_IF_MACRO(entries == NULL, ERR_OUT_OF_MEMORY, NULL);
location += (17 * fileCount);
for (entry = info->entries; fileCount > 0; fileCount--, entry++)
for (entry = entries; fileCount > 0; fileCount--, entry++)
{
BAIL_IF_MACRO(!readAll(io, &entry->name, 13), NULL, 0);
BAIL_IF_MACRO(!readAll(io, &entry->size, 4), NULL, 0);
GOTO_IF_MACRO(!readAll(io, &entry->name, 13), NULL, mvlLoad_failed);
GOTO_IF_MACRO(!readAll(io, &entry->size, 4), NULL, mvlLoad_failed);
entry->size = PHYSFS_swapULE32(entry->size);
entry->startPos = location;
location += entry->size;
} /* for */
__PHYSFS_sort(info->entries, info->entryCount, mvlEntryCmp, mvlEntrySwap);
return 1;
} /* mvl_load_entries */
return entries;
mvlLoad_failed:
allocator.Free(entries);
return NULL;
} /* mvlLoadEntries */
static void *MVL_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
{
PHYSFS_uint8 buf[4];
MVLinfo *info = NULL;
PHYSFS_uint32 val = 0;
PHYSFS_uint32 entryCount = 0;
UNPKentry *entries = NULL;
assert(io != NULL); /* shouldn't ever happen. */
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
BAIL_IF_MACRO(!readAll(io, buf, 4), NULL, NULL);
if (memcmp(buf, "DMVL", 4) != 0)
GOTO_MACRO(ERR_NOT_AN_ARCHIVE, MVL_openArchive_failed);
BAIL_IF_MACRO(memcmp(buf, "DMVL", 4) != 0, ERR_NOT_AN_ARCHIVE, NULL);
BAIL_IF_MACRO(!readAll(io, &entryCount, sizeof (entryCount)), NULL, NULL);
info = (MVLinfo *) allocator.Malloc(sizeof (MVLinfo));
GOTO_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, MVL_openArchive_failed);
memset(info, '\0', sizeof (MVLinfo));
info->io = io;
GOTO_IF_MACRO(!readAll(io,&val,sizeof(val)), NULL, MVL_openArchive_failed);
info->entryCount = PHYSFS_swapULE32(val);
GOTO_IF_MACRO(!mvl_load_entries(io, info), NULL, MVL_openArchive_failed);
return info;
MVL_openArchive_failed:
if (info != NULL)
{
if (info->entries != NULL)
allocator.Free(info->entries);
allocator.Free(info);
} /* if */
return NULL;
entryCount = PHYSFS_swapULE32(entryCount);
entries = mvlLoadEntries(io, entryCount);
BAIL_IF_MACRO(entries == NULL, NULL, NULL);
return UNPK_openArchive(io, entries, entryCount);
} /* MVL_openArchive */
static void MVL_enumerateFiles(dvoid *opaque, const char *dname,
int omitSymLinks, PHYSFS_EnumFilesCallback cb,
const char *origdir, void *callbackdata)
{
/* no directories in MVL files. */
if (*dname == '\0')
{
MVLinfo *info = ((MVLinfo *) opaque);
MVLentry *entry = info->entries;
PHYSFS_uint32 max = info->entryCount;
PHYSFS_uint32 i;
for (i = 0; i < max; i++, entry++)
cb(callbackdata, origdir, entry->name);
} /* if */
} /* MVL_enumerateFiles */
static MVLentry *mvl_find_entry(const MVLinfo *info, const char *name)
{
char *ptr = strchr(name, '.');
MVLentry *a = info->entries;
PHYSFS_sint32 lo = 0;
PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
PHYSFS_sint32 middle;
int rc;
/*
* Rule out filenames to avoid unneeded processing...no dirs,
* big filenames, or extensions > 3 chars.
*/
BAIL_IF_MACRO((ptr) && (strlen(ptr) > 4), ERR_NO_SUCH_FILE, NULL);
BAIL_IF_MACRO(strlen(name) > 12, ERR_NO_SUCH_FILE, NULL);
BAIL_IF_MACRO(strchr(name, '/') != NULL, ERR_NO_SUCH_FILE, NULL);
while (lo <= hi)
{
middle = lo + ((hi - lo) / 2);
rc = __PHYSFS_stricmpASCII(name, a[middle].name);
if (rc == 0) /* found it! */
return &a[middle];
else if (rc > 0)
lo = middle + 1;
else
hi = middle - 1;
} /* while */
BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
} /* mvl_find_entry */
static PHYSFS_Io *MVL_openRead(dvoid *opaque, const char *fnm, int *fileExists)
{
PHYSFS_Io *retval = NULL;
MVLinfo *info = (MVLinfo *) opaque;
MVLfileinfo *finfo;
MVLentry *entry;
entry = mvl_find_entry(info, fnm);
*fileExists = (entry != NULL);
GOTO_IF_MACRO(entry == NULL, NULL, MVL_openRead_failed);
retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
GOTO_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, MVL_openRead_failed);
finfo = (MVLfileinfo *) allocator.Malloc(sizeof (MVLfileinfo));
GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, MVL_openRead_failed);
finfo->io = info->io->duplicate(info->io);
GOTO_IF_MACRO(finfo->io == NULL, NULL, MVL_openRead_failed);
if (!finfo->io->seek(finfo->io, entry->startPos))
GOTO_MACRO(NULL, MVL_openRead_failed);
finfo->curPos = 0;
finfo->entry = entry;
memcpy(retval, &MVL_Io, sizeof (*retval));
retval->opaque = finfo;
return retval;
MVL_openRead_failed:
if (finfo != NULL)
{
if (finfo->io != NULL)
finfo->io->destroy(finfo->io);
allocator.Free(finfo);
} /* if */
if (retval != NULL)
allocator.Free(retval);
return NULL;
} /* MVL_openRead */
static PHYSFS_Io *MVL_openWrite(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* MVL_openWrite */
static PHYSFS_Io *MVL_openAppend(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* MVL_openAppend */
static int MVL_remove(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* MVL_remove */
static int MVL_mkdir(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* MVL_mkdir */
static int MVL_stat(dvoid *opaque, const char *filename, int *exists,
PHYSFS_Stat *stat)
{
const MVLinfo *info = (const MVLinfo *) opaque;
const MVLentry *entry = mvl_find_entry(info, filename);
*exists = (entry != 0);
if (!entry)
return 0;
stat->filesize = entry->size;
stat->filetype = PHYSFS_FILETYPE_REGULAR;
stat->modtime = -1;
stat->createtime = -1;
stat->accesstime = -1;
stat->readonly = 1;
return 1;
} /* MVL_stat */
const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_MVL =
{
"MVL",
@ -419,14 +104,14 @@ const PHYSFS_Archiver __PHYSFS_Archiver_MVL =
{
&__PHYSFS_ArchiveInfo_MVL,
MVL_openArchive, /* openArchive() method */
MVL_enumerateFiles, /* enumerateFiles() method */
MVL_openRead, /* openRead() method */
MVL_openWrite, /* openWrite() method */
MVL_openAppend, /* openAppend() method */
MVL_remove, /* remove() method */
MVL_mkdir, /* mkdir() method */
MVL_dirClose, /* dirClose() method */
MVL_stat /* stat() 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_dirClose, /* dirClose() method */
UNPK_stat /* stat() method */
};
#endif /* defined PHYSFS_SUPPORTS_MVL */

328
src/archiver_unpacked.c Normal file
View File

@ -0,0 +1,328 @@
/*
* High-level PhysicsFS archiver for simple unpacked file formats.
*
* This is a framework that basic archivers build on top of. It's for simple
* formats that can just hand back a list of files and the offsets of their
* uncompressed data. There are an alarming number of formats like this.
*
* RULES: Archive entries must be uncompressed, must not have subdirs,
* must be case insensitive filenames < 32 chars. We can relax some of these
* rules as necessary.
*
* Please see the file LICENSE.txt in the source's root directory.
*
* This file written by Ryan C. Gordon.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "physfs.h"
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
typedef struct
{
PHYSFS_Io *io;
PHYSFS_uint32 entryCount;
UNPKentry *entries;
} UNPKinfo;
typedef struct
{
PHYSFS_Io *io;
UNPKentry *entry;
PHYSFS_uint32 curPos;
} UNPKfileinfo;
void UNPK_dirClose(dvoid *opaque)
{
UNPKinfo *info = ((UNPKinfo *) opaque);
info->io->destroy(info->io);
allocator.Free(info->entries);
allocator.Free(info);
} /* UNPK_dirClose */
static PHYSFS_sint64 UNPK_read(PHYSFS_Io *io, void *buffer, PHYSFS_uint64 len)
{
UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque;
const UNPKentry *entry = finfo->entry;
const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos);
PHYSFS_sint64 rc;
if (bytesLeft < len)
len = bytesLeft;
rc = finfo->io->read(finfo->io, buffer, len);
if (rc > 0)
finfo->curPos += (PHYSFS_uint32) rc;
return rc;
} /* UNPK_read */
static PHYSFS_sint64 UNPK_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
} /* UNPK_write */
static PHYSFS_sint64 UNPK_tell(PHYSFS_Io *io)
{
return ((UNPKfileinfo *) io->opaque)->curPos;
} /* UNPK_tell */
static int UNPK_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
{
UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque;
const UNPKentry *entry = finfo->entry;
int rc;
BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
rc = finfo->io->seek(finfo->io, entry->startPos + offset);
if (rc)
finfo->curPos = (PHYSFS_uint32) offset;
return rc;
} /* UNPK_seek */
static PHYSFS_sint64 UNPK_length(PHYSFS_Io *io)
{
const UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque;
return ((PHYSFS_sint64) finfo->entry->size);
} /* UNPK_length */
static PHYSFS_Io *UNPK_duplicate(PHYSFS_Io *_io)
{
UNPKfileinfo *origfinfo = (UNPKfileinfo *) _io->opaque;
PHYSFS_Io *io = NULL;
PHYSFS_Io *retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
UNPKfileinfo *finfo = (UNPKfileinfo *) allocator.Malloc(sizeof (UNPKfileinfo));
GOTO_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, UNPK_duplicate_failed);
GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, UNPK_duplicate_failed);
io = origfinfo->io->duplicate(origfinfo->io);
GOTO_IF_MACRO(io == NULL, NULL, UNPK_duplicate_failed);
finfo->io = io;
finfo->entry = origfinfo->entry;
finfo->curPos = 0;
memcpy(retval, _io, sizeof (PHYSFS_Io));
retval->opaque = finfo;
return retval;
UNPK_duplicate_failed:
if (finfo != NULL) allocator.Free(finfo);
if (retval != NULL) allocator.Free(retval);
if (io != NULL) io->destroy(io);
return NULL;
} /* UNPK_duplicate */
static int UNPK_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
static void UNPK_destroy(PHYSFS_Io *io)
{
UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque;
finfo->io->destroy(finfo->io);
allocator.Free(finfo);
allocator.Free(io);
} /* UNPK_destroy */
static const PHYSFS_Io UNPK_Io =
{
UNPK_read,
UNPK_write,
UNPK_seek,
UNPK_tell,
UNPK_length,
UNPK_duplicate,
UNPK_flush,
UNPK_destroy,
NULL
};
static int entryCmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
{
if (one != two)
{
const UNPKentry *a = (const UNPKentry *) _a;
return strcmp(a[one].name, a[two].name);
} /* if */
return 0;
} /* entryCmp */
static void entrySwap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
{
if (one != two)
{
UNPKentry tmp;
UNPKentry *first = &(((UNPKentry *) _a)[one]);
UNPKentry *second = &(((UNPKentry *) _a)[two]);
memcpy(&tmp, first, sizeof (UNPKentry));
memcpy(first, second, sizeof (UNPKentry));
memcpy(second, &tmp, sizeof (UNPKentry));
} /* if */
} /* entrySwap */
void UNPK_enumerateFiles(dvoid *opaque, const char *dname,
int omitSymLinks, PHYSFS_EnumFilesCallback cb,
const char *origdir, void *callbackdata)
{
/* no directories in UNPK files. */
if (*dname == '\0')
{
UNPKinfo *info = (UNPKinfo *) opaque;
UNPKentry *entry = info->entries;
PHYSFS_uint32 max = info->entryCount;
PHYSFS_uint32 i;
for (i = 0; i < max; i++, entry++)
cb(callbackdata, origdir, entry->name);
} /* if */
} /* UNPK_enumerateFiles */
static UNPKentry *findEntry(const UNPKinfo *info, const char *name)
{
UNPKentry *a = info->entries;
PHYSFS_sint32 lo = 0;
PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
PHYSFS_sint32 middle;
int rc;
while (lo <= hi)
{
middle = lo + ((hi - lo) / 2);
rc = __PHYSFS_utf8strcasecmp(name, a[middle].name);
if (rc == 0) /* found it! */
return &a[middle];
else if (rc > 0)
lo = middle + 1;
else
hi = middle - 1;
} /* while */
BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
} /* findEntry */
PHYSFS_Io *UNPK_openRead(dvoid *opaque, const char *fnm, int *fileExists)
{
PHYSFS_Io *retval = NULL;
UNPKinfo *info = (UNPKinfo *) opaque;
UNPKfileinfo *finfo;
UNPKentry *entry;
entry = findEntry(info, fnm);
*fileExists = (entry != NULL);
GOTO_IF_MACRO(entry == NULL, NULL, UNPK_openRead_failed);
retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
GOTO_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, UNPK_openRead_failed);
finfo = (UNPKfileinfo *) allocator.Malloc(sizeof (UNPKfileinfo));
GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, UNPK_openRead_failed);
finfo->io = info->io->duplicate(info->io);
GOTO_IF_MACRO(finfo->io == NULL, NULL, UNPK_openRead_failed);
if (!finfo->io->seek(finfo->io, entry->startPos))
GOTO_MACRO(NULL, UNPK_openRead_failed);
finfo->curPos = 0;
finfo->entry = entry;
memcpy(retval, &UNPK_Io, sizeof (*retval));
retval->opaque = finfo;
return retval;
UNPK_openRead_failed:
if (finfo != NULL)
{
if (finfo->io != NULL)
finfo->io->destroy(finfo->io);
allocator.Free(finfo);
} /* if */
if (retval != NULL)
allocator.Free(retval);
return NULL;
} /* UNPK_openRead */
PHYSFS_Io *UNPK_openWrite(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* UNPK_openWrite */
PHYSFS_Io *UNPK_openAppend(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* UNPK_openAppend */
int UNPK_remove(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* UNPK_remove */
int UNPK_mkdir(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* UNPK_mkdir */
int UNPK_stat(dvoid *opaque, const char *filename, int *exists,
PHYSFS_Stat *stat)
{
const UNPKinfo *info = (const UNPKinfo *) opaque;
const UNPKentry *entry = findEntry(info, filename);
*exists = (entry != 0);
if (!entry)
return 0;
stat->filesize = entry->size;
stat->filetype = PHYSFS_FILETYPE_REGULAR;
stat->modtime = -1;
stat->createtime = -1;
stat->accesstime = -1;
stat->readonly = 1;
return 1;
} /* UNPK_stat */
dvoid *UNPK_openArchive(PHYSFS_Io *io, UNPKentry *e, const PHYSFS_uint32 num)
{
UNPKinfo *info = (UNPKinfo *) allocator.Malloc(sizeof (UNPKinfo));
if (info == NULL)
{
allocator.Free(e);
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
} /* if */
__PHYSFS_sort(e, num, entryCmp, entrySwap);
info->io = io;
info->entryCount = num;
info->entries = e;
return info;
} /* UNPK_openArchive */
/* end of archiver_unpacked.c ... */

View File

@ -52,380 +52,67 @@
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
typedef struct
{
char name[18];
PHYSFS_uint32 startPos;
PHYSFS_uint32 size;
} WADentry;
typedef struct
{
PHYSFS_Io *io;
PHYSFS_uint32 entryCount;
WADentry *entries;
} WADinfo;
typedef struct
{
PHYSFS_Io *io;
WADentry *entry;
PHYSFS_uint32 curPos;
} WADfileinfo;
static inline int readAll(PHYSFS_Io *io, void *buf, const PHYSFS_uint64 len)
{
return (io->read(io, buf, len) == len);
} /* readAll */
static void WAD_dirClose(dvoid *opaque)
static UNPKentry *wadLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 fileCount)
{
WADinfo *info = ((WADinfo *) opaque);
info->io->destroy(info->io);
allocator.Free(info->entries);
allocator.Free(info);
} /* WAD_dirClose */
static PHYSFS_sint64 WAD_read(PHYSFS_Io *io, void *buffer, PHYSFS_uint64 len)
{
WADfileinfo *finfo = (WADfileinfo *) io->opaque;
const WADentry *entry = finfo->entry;
const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos);
PHYSFS_sint64 rc;
if (bytesLeft < len)
len = bytesLeft;
rc = finfo->io->read(finfo->io, buffer, len);
if (rc > 0)
finfo->curPos += (PHYSFS_uint32) rc;
return rc;
} /* WAD_read */
static PHYSFS_sint64 WAD_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
} /* WAD_write */
static PHYSFS_sint64 WAD_tell(PHYSFS_Io *io)
{
return ((WADfileinfo *) io->opaque)->curPos;
} /* WAD_tell */
static int WAD_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
{
WADfileinfo *finfo = (WADfileinfo *) io->opaque;
const WADentry *entry = finfo->entry;
int rc;
BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
rc = finfo->io->seek(finfo->io, entry->startPos + offset);
if (rc)
finfo->curPos = (PHYSFS_uint32) offset;
return rc;
} /* WAD_seek */
static PHYSFS_sint64 WAD_length(PHYSFS_Io *io)
{
const WADfileinfo *finfo = (WADfileinfo *) io->opaque;
return ((PHYSFS_sint64) finfo->entry->size);
} /* WAD_length */
static PHYSFS_Io *WAD_duplicate(PHYSFS_Io *_io)
{
WADfileinfo *origfinfo = (WADfileinfo *) _io->opaque;
PHYSFS_Io *io = NULL;
PHYSFS_Io *retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
WADfileinfo *finfo = (WADfileinfo *) allocator.Malloc(sizeof (WADfileinfo));
GOTO_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, WAD_duplicate_failed);
GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, WAD_duplicate_failed);
io = origfinfo->io->duplicate(origfinfo->io);
GOTO_IF_MACRO(io == NULL, NULL, WAD_duplicate_failed);
finfo->io = io;
finfo->entry = origfinfo->entry;
finfo->curPos = 0;
memcpy(retval, _io, sizeof (PHYSFS_Io));
retval->opaque = finfo;
return retval;
WAD_duplicate_failed:
if (finfo != NULL) allocator.Free(finfo);
if (retval != NULL) allocator.Free(retval);
if (io != NULL) io->destroy(io);
return NULL;
} /* WAD_duplicate */
static int WAD_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
static void WAD_destroy(PHYSFS_Io *io)
{
WADfileinfo *finfo = (WADfileinfo *) io->opaque;
finfo->io->destroy(finfo->io);
allocator.Free(finfo);
allocator.Free(io);
} /* WAD_destroy */
static const PHYSFS_Io WAD_Io =
{
WAD_read,
WAD_write,
WAD_seek,
WAD_tell,
WAD_length,
WAD_duplicate,
WAD_flush,
WAD_destroy,
NULL
};
static int wadEntryCmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
{
if (one != two)
{
const WADentry *a = (const WADentry *) _a;
return __PHYSFS_stricmpASCII(a[one].name, a[two].name);
} /* if */
return 0;
} /* wadEntryCmp */
static void wadEntrySwap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
{
if (one != two)
{
WADentry tmp;
WADentry *first = &(((WADentry *) _a)[one]);
WADentry *second = &(((WADentry *) _a)[two]);
memcpy(&tmp, first, sizeof (WADentry));
memcpy(first, second, sizeof (WADentry));
memcpy(second, &tmp, sizeof (WADentry));
} /* if */
} /* wadEntrySwap */
static int wad_load_entries(PHYSFS_Io *io, WADinfo *info)
{
PHYSFS_uint32 fileCount = info->entryCount;
PHYSFS_uint32 directoryOffset;
WADentry *entry;
UNPKentry *entries = NULL;
UNPKentry *entry = NULL;
BAIL_IF_MACRO(!readAll(io, &directoryOffset, 4), NULL, 0);
directoryOffset = PHYSFS_swapULE32(directoryOffset);
info->entries = (WADentry *) allocator.Malloc(sizeof(WADentry)*fileCount);
BAIL_IF_MACRO(info->entries == NULL, ERR_OUT_OF_MEMORY, 0);
BAIL_IF_MACRO(!io->seek(io, directoryOffset), NULL, 0);
for (entry = info->entries; fileCount > 0; fileCount--, entry++)
entries = (UNPKentry *) allocator.Malloc(sizeof (UNPKentry) * fileCount);
BAIL_IF_MACRO(entries == NULL, ERR_OUT_OF_MEMORY, NULL);
for (entry = entries; fileCount > 0; fileCount--, entry++)
{
BAIL_IF_MACRO(!readAll(io, &entry->startPos, 4), NULL, 0);
BAIL_IF_MACRO(!readAll(io, &entry->size, 4), NULL, 0);
BAIL_IF_MACRO(!readAll(io, &entry->name, 8), NULL, 0);
GOTO_IF_MACRO(!readAll(io, &entry->startPos, 4), NULL, wadLoad_failed);
GOTO_IF_MACRO(!readAll(io, &entry->size, 4), NULL, wadLoad_failed);
GOTO_IF_MACRO(!readAll(io, &entry->name, 8), NULL, wadLoad_failed);
entry->name[8] = '\0'; /* name might not be null-terminated in file. */
entry->size = PHYSFS_swapULE32(entry->size);
entry->startPos = PHYSFS_swapULE32(entry->startPos);
} /* for */
__PHYSFS_sort(info->entries, info->entryCount, wadEntryCmp, wadEntrySwap);
return 1;
} /* wad_load_entries */
return entries;
wadLoad_failed:
allocator.Free(entries);
return NULL;
} /* wadLoadEntries */
static void *WAD_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
{
PHYSFS_uint8 buf[4];
WADinfo *info = NULL;
PHYSFS_uint32 val = 0;
UNPKentry *entries = NULL;
PHYSFS_uint32 entryCount = 0;
assert(io != NULL); /* shouldn't ever happen. */
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
BAIL_IF_MACRO(!readAll(io, buf, sizeof (buf)), NULL, NULL);
if ((memcmp(buf, "IWAD", 4) != 0) && (memcmp(buf, "PWAD", 4) != 0))
GOTO_MACRO(ERR_NOT_AN_ARCHIVE, WAD_openArchive_failed);
BAIL_MACRO(ERR_NOT_AN_ARCHIVE, NULL);
info = (WADinfo *) allocator.Malloc(sizeof (WADinfo));
GOTO_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, WAD_openArchive_failed);
memset(info, '\0', sizeof (WADinfo));
info->io = io;
BAIL_IF_MACRO(!readAll(io, &entryCount, sizeof (entryCount)), NULL, NULL);
entryCount = PHYSFS_swapULE32(entryCount);
GOTO_IF_MACRO(!readAll(io,&val,sizeof(val)), NULL, WAD_openArchive_failed);
info->entryCount = PHYSFS_swapULE32(val);
GOTO_IF_MACRO(!wad_load_entries(io, info), NULL, WAD_openArchive_failed);
return info;
WAD_openArchive_failed:
if (info != NULL)
{
if (info->entries != NULL)
allocator.Free(info->entries);
allocator.Free(info);
} /* if */
return NULL;
entries = wadLoadEntries(io, entryCount);
BAIL_IF_MACRO(entries == NULL, NULL, NULL);
return UNPK_openArchive(io, entries, entryCount);
} /* WAD_openArchive */
static void WAD_enumerateFiles(dvoid *opaque, const char *dname,
int omitSymLinks, PHYSFS_EnumFilesCallback cb,
const char *origdir, void *callbackdata)
{
/* no directories in WAD files. */
if (*dname == '\0')
{
WADinfo *info = (WADinfo *) opaque;
WADentry *entry = info->entries;
PHYSFS_uint32 max = info->entryCount;
PHYSFS_uint32 i;
for (i = 0; i < max; i++, entry++)
cb(callbackdata, origdir, entry->name);
} /* if */
} /* WAD_enumerateFiles */
static WADentry *wad_find_entry(const WADinfo *info, const char *name)
{
char *ptr = strchr(name, '.');
WADentry *a = info->entries;
PHYSFS_sint32 lo = 0;
PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
PHYSFS_sint32 middle;
int rc;
/*
* Rule out filenames to avoid unneeded processing...no dirs,
* big filenames, or extensions.
*/
BAIL_IF_MACRO(ptr != NULL, ERR_NO_SUCH_FILE, NULL);
BAIL_IF_MACRO(strlen(name) > 8, ERR_NO_SUCH_FILE, NULL);
BAIL_IF_MACRO(strchr(name, '/') != NULL, ERR_NO_SUCH_FILE, NULL);
while (lo <= hi)
{
middle = lo + ((hi - lo) / 2);
rc = __PHYSFS_stricmpASCII(name, a[middle].name);
if (rc == 0) /* found it! */
return &a[middle];
else if (rc > 0)
lo = middle + 1;
else
hi = middle - 1;
} /* while */
BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
} /* wad_find_entry */
static PHYSFS_Io *WAD_openRead(dvoid *opaque, const char *fnm, int *fileExists)
{
PHYSFS_Io *retval = NULL;
WADinfo *info = (WADinfo *) opaque;
WADfileinfo *finfo;
WADentry *entry;
entry = wad_find_entry(info, fnm);
*fileExists = (entry != NULL);
GOTO_IF_MACRO(entry == NULL, NULL, WAD_openRead_failed);
retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
GOTO_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, WAD_openRead_failed);
finfo = (WADfileinfo *) allocator.Malloc(sizeof (WADfileinfo));
GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, WAD_openRead_failed);
finfo->io = info->io->duplicate(info->io);
GOTO_IF_MACRO(finfo->io == NULL, NULL, WAD_openRead_failed);
if (!finfo->io->seek(finfo->io, entry->startPos))
GOTO_MACRO(NULL, WAD_openRead_failed);
finfo->curPos = 0;
finfo->entry = entry;
memcpy(retval, &WAD_Io, sizeof (*retval));
retval->opaque = finfo;
return retval;
WAD_openRead_failed:
if (finfo != NULL)
{
if (finfo->io != NULL)
finfo->io->destroy(finfo->io);
allocator.Free(finfo);
} /* if */
if (retval != NULL)
allocator.Free(retval);
return NULL;
} /* WAD_openRead */
static PHYSFS_Io *WAD_openWrite(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* WAD_openWrite */
static PHYSFS_Io *WAD_openAppend(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* WAD_openAppend */
static int WAD_remove(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* WAD_remove */
static int WAD_mkdir(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* WAD_mkdir */
static int WAD_stat(dvoid *opaque, const char *filename, int *exists,
PHYSFS_Stat *stat)
{
const WADinfo *info = (const WADinfo *) opaque;
const WADentry *entry = wad_find_entry(info, filename);
*exists = (entry != 0);
if (!entry)
return 0;
stat->filesize = entry->size;
stat->filetype = PHYSFS_FILETYPE_REGULAR;
stat->modtime = -1;
stat->createtime = -1;
stat->accesstime = -1;
stat->readonly = 1;
return 1;
} /* WAD_stat */
const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_WAD =
{
"WAD",
@ -439,14 +126,14 @@ const PHYSFS_Archiver __PHYSFS_Archiver_WAD =
{
&__PHYSFS_ArchiveInfo_WAD,
WAD_openArchive, /* openArchive() method */
WAD_enumerateFiles, /* enumerateFiles() method */
WAD_openRead, /* openRead() method */
WAD_openWrite, /* openWrite() method */
WAD_openAppend, /* openAppend() method */
WAD_remove, /* remove() method */
WAD_mkdir, /* mkdir() method */
WAD_dirClose, /* dirClose() method */
WAD_stat /* stat() 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_dirClose, /* dirClose() method */
UNPK_stat /* stat() method */
};
#endif /* defined PHYSFS_SUPPORTS_WAD */

View File

@ -1014,6 +1014,30 @@ PHYSFS_Io *__PHYSFS_createMemoryIo(const void *buf, PHYSFS_uint64 len,
void (*destruct)(void *));
/* These are shared between some archivers. */
typedef struct
{
char name[32];
PHYSFS_uint32 startPos;
PHYSFS_uint32 size;
} UNPKentry;
void UNPK_dirClose(dvoid *opaque);
dvoid *UNPK_openArchive(PHYSFS_Io *io, UNPKentry *e, const PHYSFS_uint32 num);
void UNPK_enumerateFiles(dvoid *opaque, const char *dname,
int omitSymLinks, PHYSFS_EnumFilesCallback cb,
const char *origdir, void *callbackdata);
PHYSFS_Io *UNPK_openRead(dvoid *opaque, const char *fnm, int *fileExists);
PHYSFS_Io *UNPK_openWrite(dvoid *opaque, const char *name);
PHYSFS_Io *UNPK_openAppend(dvoid *opaque, const char *name);
int UNPK_remove(dvoid *opaque, const char *name);
int UNPK_mkdir(dvoid *opaque, const char *name);
int UNPK_stat(dvoid *opaque, const char *fn, int *exists, PHYSFS_Stat *stat);
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
/*------------ ----------------*/