Moved most the cut-and-paste between simple archivers to one file.
This commit is contained in:
parent
9d900f8814
commit
3f02ce767f
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 ... */
|
||||
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/*------------ ----------------*/
|
||||
|
|
Loading…
Reference in New Issue