Abstracted file i/o into PHYSFS_Io interface.
This touched a lot of code, and involved cleaning up a lot of stuff.
This commit is contained in:
parent
c2e77d7e35
commit
4bc5ed1725
|
@ -14,68 +14,23 @@
|
|||
#define __PHYSICSFS_INTERNAL__
|
||||
#include "physfs_internal.h"
|
||||
|
||||
static PHYSFS_sint64 DIR_read(fvoid *opaque, void *buffer, PHYSFS_uint64 len)
|
||||
{
|
||||
return __PHYSFS_platformRead(opaque, buffer, len);
|
||||
} /* DIR_read */
|
||||
/* There's no PHYSFS_Io interface here. Use __PHYSFS_createNativeIo(). */
|
||||
|
||||
|
||||
static PHYSFS_sint64 DIR_write(fvoid *f, const void *buf, PHYSFS_uint64 len)
|
||||
{
|
||||
return __PHYSFS_platformWrite(f, buf, len);
|
||||
} /* DIR_write */
|
||||
|
||||
|
||||
static int DIR_eof(fvoid *opaque)
|
||||
{
|
||||
return __PHYSFS_platformEOF(opaque);
|
||||
} /* DIR_eof */
|
||||
|
||||
|
||||
static PHYSFS_sint64 DIR_tell(fvoid *opaque)
|
||||
{
|
||||
return __PHYSFS_platformTell(opaque);
|
||||
} /* DIR_tell */
|
||||
|
||||
|
||||
static int DIR_seek(fvoid *opaque, PHYSFS_uint64 offset)
|
||||
{
|
||||
return __PHYSFS_platformSeek(opaque, offset);
|
||||
} /* DIR_seek */
|
||||
|
||||
|
||||
static PHYSFS_sint64 DIR_fileLength(fvoid *opaque)
|
||||
{
|
||||
return __PHYSFS_platformFileLength(opaque);
|
||||
} /* DIR_fileLength */
|
||||
|
||||
|
||||
static int DIR_fileClose(fvoid *opaque)
|
||||
{
|
||||
/*
|
||||
* we manually flush the buffer, since that's the place a close will
|
||||
* most likely fail, but that will leave the file handle in an undefined
|
||||
* state if it fails. Flush failures we can recover from.
|
||||
*/
|
||||
BAIL_IF_MACRO(!__PHYSFS_platformFlush(opaque), NULL, 0);
|
||||
BAIL_IF_MACRO(!__PHYSFS_platformClose(opaque), NULL, 0);
|
||||
return 1;
|
||||
} /* DIR_fileClose */
|
||||
|
||||
|
||||
static void *DIR_openArchive(const char *name, int forWriting)
|
||||
static void *DIR_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
|
||||
{
|
||||
const char *dirsep = PHYSFS_getDirSeparator();
|
||||
char *retval = NULL;
|
||||
size_t namelen = strlen(name);
|
||||
size_t seplen = strlen(dirsep);
|
||||
const size_t namelen = strlen(name);
|
||||
const size_t seplen = strlen(dirsep);
|
||||
|
||||
assert(io == NULL); /* shouldn't create an Io for these. */
|
||||
BAIL_IF_MACRO(!__PHYSFS_platformIsDirectory(name), ERR_NOT_AN_ARCHIVE, NULL);
|
||||
|
||||
retval = allocator.Malloc(namelen + seplen + 1);
|
||||
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
|
||||
|
||||
/* make sure there's a dir separator at the end of the string */
|
||||
/* make sure there's a dir separator at the end of the string */
|
||||
/* !!! FIXME: is there really any place where (seplen != 1)? */
|
||||
strcpy(retval, name);
|
||||
if (strcmp((name + namelen) - seplen, dirsep) != 0)
|
||||
strcat(retval, dirsep);
|
||||
|
@ -84,11 +39,13 @@ static void *DIR_openArchive(const char *name, int forWriting)
|
|||
} /* DIR_openArchive */
|
||||
|
||||
|
||||
/* !!! FIXME: I would like to smallAlloc() all these conversions somehow. */
|
||||
|
||||
static void DIR_enumerateFiles(dvoid *opaque, const char *dname,
|
||||
int omitSymLinks, PHYSFS_EnumFilesCallback cb,
|
||||
const char *origdir, void *callbackdata)
|
||||
{
|
||||
char *d = __PHYSFS_platformCvtToDependent((char *)opaque, dname, NULL);
|
||||
char *d = __PHYSFS_platformCvtToDependent((char *) opaque, dname, NULL);
|
||||
if (d != NULL)
|
||||
{
|
||||
__PHYSFS_platformEnumerateFiles(d, omitSymLinks, cb,
|
||||
|
@ -138,47 +95,48 @@ static int DIR_isSymLink(dvoid *opaque, const char *name, int *fileExists)
|
|||
} /* DIR_isSymLink */
|
||||
|
||||
|
||||
static fvoid *doOpen(dvoid *opaque, const char *name,
|
||||
void *(*openFunc)(const char *filename),
|
||||
int *fileExists)
|
||||
static PHYSFS_Io *doOpen(dvoid *opaque, const char *name,
|
||||
const int mode, int *fileExists)
|
||||
{
|
||||
char *f = __PHYSFS_platformCvtToDependent((char *) opaque, name, NULL);
|
||||
void *rc = NULL;
|
||||
PHYSFS_Io *io = NULL;
|
||||
int existtmp = 0;
|
||||
|
||||
if (fileExists == NULL)
|
||||
fileExists = &existtmp;
|
||||
|
||||
*fileExists = 0;
|
||||
|
||||
BAIL_IF_MACRO(f == NULL, NULL, NULL);
|
||||
|
||||
if (fileExists != NULL)
|
||||
io = __PHYSFS_createNativeIo(f, mode);
|
||||
allocator.Free(f);
|
||||
if (io == NULL)
|
||||
{
|
||||
*fileExists = __PHYSFS_platformExists(f);
|
||||
if (!(*fileExists))
|
||||
{
|
||||
allocator.Free(f);
|
||||
return NULL;
|
||||
} /* if */
|
||||
return NULL;
|
||||
} /* if */
|
||||
|
||||
rc = openFunc(f);
|
||||
allocator.Free(f);
|
||||
|
||||
return ((fvoid *) rc);
|
||||
*fileExists = 1;
|
||||
return io;
|
||||
} /* doOpen */
|
||||
|
||||
|
||||
static fvoid *DIR_openRead(dvoid *opaque, const char *fnm, int *exist)
|
||||
static PHYSFS_Io *DIR_openRead(dvoid *opaque, const char *fnm, int *exist)
|
||||
{
|
||||
return doOpen(opaque, fnm, __PHYSFS_platformOpenRead, exist);
|
||||
return doOpen(opaque, fnm, 'r', exist);
|
||||
} /* DIR_openRead */
|
||||
|
||||
|
||||
static fvoid *DIR_openWrite(dvoid *opaque, const char *filename)
|
||||
static PHYSFS_Io *DIR_openWrite(dvoid *opaque, const char *filename)
|
||||
{
|
||||
return doOpen(opaque, filename, __PHYSFS_platformOpenWrite, NULL);
|
||||
return doOpen(opaque, filename, 'w', NULL);
|
||||
} /* DIR_openWrite */
|
||||
|
||||
|
||||
static fvoid *DIR_openAppend(dvoid *opaque, const char *filename)
|
||||
static PHYSFS_Io *DIR_openAppend(dvoid *opaque, const char *filename)
|
||||
{
|
||||
return doOpen(opaque, filename, __PHYSFS_platformOpenAppend, NULL);
|
||||
return doOpen(opaque, filename, 'a', NULL);
|
||||
} /* DIR_openAppend */
|
||||
|
||||
|
||||
|
@ -248,14 +206,7 @@ const PHYSFS_Archiver __PHYSFS_Archiver_DIR =
|
|||
DIR_remove, /* remove() method */
|
||||
DIR_mkdir, /* mkdir() method */
|
||||
DIR_dirClose, /* dirClose() method */
|
||||
DIR_stat, /* stat() method */
|
||||
DIR_read, /* read() method */
|
||||
DIR_write, /* write() method */
|
||||
DIR_eof, /* eof() method */
|
||||
DIR_tell, /* tell() method */
|
||||
DIR_seek, /* seek() method */
|
||||
DIR_fileLength, /* fileLength() method */
|
||||
DIR_fileClose /* fileClose() method */
|
||||
DIR_stat /* stat() method */
|
||||
};
|
||||
|
||||
/* end of dir.c ... */
|
||||
|
|
|
@ -43,37 +43,37 @@ typedef struct
|
|||
|
||||
typedef struct
|
||||
{
|
||||
char *filename;
|
||||
PHYSFS_Io *io;
|
||||
PHYSFS_uint32 entryCount;
|
||||
GRPentry *entries;
|
||||
} GRPinfo;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void *handle;
|
||||
PHYSFS_Io *io;
|
||||
GRPentry *entry;
|
||||
PHYSFS_uint32 curPos;
|
||||
} GRPfileinfo;
|
||||
|
||||
|
||||
static inline int readAll(void *fh, void *buf, const PHYSFS_uint64 len)
|
||||
static inline int readAll(PHYSFS_Io *io, void *buf, const PHYSFS_uint64 len)
|
||||
{
|
||||
return (__PHYSFS_platformRead(fh, buf, len) == len);
|
||||
return (io->read(io, buf, len) == len);
|
||||
} /* readAll */
|
||||
|
||||
|
||||
static void GRP_dirClose(dvoid *opaque)
|
||||
{
|
||||
GRPinfo *info = ((GRPinfo *) opaque);
|
||||
allocator.Free(info->filename);
|
||||
info->io->destroy(info->io);
|
||||
allocator.Free(info->entries);
|
||||
allocator.Free(info);
|
||||
} /* GRP_dirClose */
|
||||
|
||||
|
||||
static PHYSFS_sint64 GRP_read(fvoid *opaque, void *buffer, PHYSFS_uint64 len)
|
||||
static PHYSFS_sint64 GRP_read(PHYSFS_Io *io, void *buffer, PHYSFS_uint64 len)
|
||||
{
|
||||
GRPfileinfo *finfo = (GRPfileinfo *) opaque;
|
||||
GRPfileinfo *finfo = (GRPfileinfo *) io->opaque;
|
||||
const GRPentry *entry = finfo->entry;
|
||||
const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos);
|
||||
PHYSFS_sint64 rc;
|
||||
|
@ -81,7 +81,7 @@ static PHYSFS_sint64 GRP_read(fvoid *opaque, void *buffer, PHYSFS_uint64 len)
|
|||
if (bytesLeft < len)
|
||||
len = bytesLeft;
|
||||
|
||||
rc = __PHYSFS_platformRead(finfo->handle, buffer, len);
|
||||
rc = finfo->io->read(finfo->io, buffer, len);
|
||||
if (rc > 0)
|
||||
finfo->curPos += (PHYSFS_uint32) rc;
|
||||
|
||||
|
@ -89,35 +89,26 @@ static PHYSFS_sint64 GRP_read(fvoid *opaque, void *buffer, PHYSFS_uint64 len)
|
|||
} /* GRP_read */
|
||||
|
||||
|
||||
static PHYSFS_sint64 GRP_write(fvoid *f, const void *buf, PHYSFS_uint64 len)
|
||||
static PHYSFS_sint64 GRP_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
|
||||
{
|
||||
BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
|
||||
} /* GRP_write */
|
||||
|
||||
|
||||
static int GRP_eof(fvoid *opaque)
|
||||
static PHYSFS_sint64 GRP_tell(PHYSFS_Io *io)
|
||||
{
|
||||
GRPfileinfo *finfo = (GRPfileinfo *) opaque;
|
||||
GRPentry *entry = finfo->entry;
|
||||
return (finfo->curPos >= entry->size);
|
||||
} /* GRP_eof */
|
||||
|
||||
|
||||
static PHYSFS_sint64 GRP_tell(fvoid *opaque)
|
||||
{
|
||||
return ((GRPfileinfo *) opaque)->curPos;
|
||||
return ((GRPfileinfo *) io->opaque)->curPos;
|
||||
} /* GRP_tell */
|
||||
|
||||
|
||||
static int GRP_seek(fvoid *opaque, PHYSFS_uint64 offset)
|
||||
static int GRP_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
|
||||
{
|
||||
GRPfileinfo *finfo = (GRPfileinfo *) opaque;
|
||||
GRPentry *entry = finfo->entry;
|
||||
GRPfileinfo *finfo = (GRPfileinfo *) io->opaque;
|
||||
const GRPentry *entry = finfo->entry;
|
||||
int rc;
|
||||
|
||||
BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
|
||||
BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
|
||||
rc = __PHYSFS_platformSeek(finfo->handle, entry->startPos + offset);
|
||||
rc = finfo->io->seek(finfo->io, entry->startPos + offset);
|
||||
if (rc)
|
||||
finfo->curPos = (PHYSFS_uint32) offset;
|
||||
|
||||
|
@ -125,72 +116,77 @@ static int GRP_seek(fvoid *opaque, PHYSFS_uint64 offset)
|
|||
} /* GRP_seek */
|
||||
|
||||
|
||||
static PHYSFS_sint64 GRP_fileLength(fvoid *opaque)
|
||||
static PHYSFS_sint64 GRP_length(PHYSFS_Io *io)
|
||||
{
|
||||
GRPfileinfo *finfo = (GRPfileinfo *) opaque;
|
||||
const GRPfileinfo *finfo = (GRPfileinfo *) io->opaque;
|
||||
return ((PHYSFS_sint64) finfo->entry->size);
|
||||
} /* GRP_fileLength */
|
||||
} /* GRP_length */
|
||||
|
||||
|
||||
static int GRP_fileClose(fvoid *opaque)
|
||||
static PHYSFS_Io *GRP_duplicate(PHYSFS_Io *_io)
|
||||
{
|
||||
GRPfileinfo *finfo = (GRPfileinfo *) opaque;
|
||||
BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0);
|
||||
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);
|
||||
return 1;
|
||||
} /* GRP_fileClose */
|
||||
allocator.Free(io);
|
||||
} /* GRP_destroy */
|
||||
|
||||
|
||||
static int grp_open(const char *filename, int forWriting,
|
||||
void **fh, PHYSFS_uint32 *count)
|
||||
static const PHYSFS_Io GRP_Io =
|
||||
{
|
||||
PHYSFS_uint8 buf[12];
|
||||
|
||||
*fh = NULL;
|
||||
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
|
||||
|
||||
*fh = __PHYSFS_platformOpenRead(filename);
|
||||
BAIL_IF_MACRO(*fh == NULL, NULL, 0);
|
||||
|
||||
if (!readAll(*fh, buf, 12))
|
||||
goto openGrp_failed;
|
||||
|
||||
if (memcmp(buf, "KenSilverman", 12) != 0)
|
||||
{
|
||||
__PHYSFS_setError(ERR_UNSUPPORTED_ARCHIVE);
|
||||
goto openGrp_failed;
|
||||
} /* if */
|
||||
|
||||
if (!readAll(*fh, count, sizeof (PHYSFS_uint32)))
|
||||
goto openGrp_failed;
|
||||
|
||||
*count = PHYSFS_swapULE32(*count);
|
||||
|
||||
return 1;
|
||||
|
||||
openGrp_failed:
|
||||
if (*fh != NULL)
|
||||
__PHYSFS_platformClose(*fh);
|
||||
|
||||
*count = -1;
|
||||
*fh = NULL;
|
||||
return 0;
|
||||
} /* grp_open */
|
||||
GRP_read,
|
||||
GRP_write,
|
||||
GRP_seek,
|
||||
GRP_tell,
|
||||
GRP_length,
|
||||
GRP_duplicate,
|
||||
GRP_flush,
|
||||
GRP_destroy,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
static int grp_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
|
||||
|
||||
static int grpEntryCmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
|
||||
{
|
||||
if (one != two)
|
||||
{
|
||||
const GRPentry *a = (const GRPentry *) _a;
|
||||
return (strcmp(a[one].name, a[two].name));
|
||||
return __PHYSFS_stricmpASCII(a[one].name, a[two].name);
|
||||
} /* if */
|
||||
|
||||
return 0;
|
||||
} /* grp_entry_cmp */
|
||||
} /* grpEntryCmp */
|
||||
|
||||
|
||||
static void grp_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
|
||||
static void grpEntrySwap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
|
||||
{
|
||||
if (one != two)
|
||||
{
|
||||
|
@ -201,37 +197,25 @@ static void grp_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
|
|||
memcpy(first, second, sizeof (GRPentry));
|
||||
memcpy(second, &tmp, sizeof (GRPentry));
|
||||
} /* if */
|
||||
} /* grp_entry_swap */
|
||||
} /* grpEntrySwap */
|
||||
|
||||
|
||||
static int grp_load_entries(const char *name, int forWriting, GRPinfo *info)
|
||||
static int grp_load_entries(PHYSFS_Io *io, GRPinfo *info)
|
||||
{
|
||||
void *fh = NULL;
|
||||
PHYSFS_uint32 fileCount;
|
||||
PHYSFS_uint32 fileCount = info->entryCount;
|
||||
PHYSFS_uint32 location = 16; /* sizeof sig. */
|
||||
GRPentry *entry;
|
||||
char *ptr;
|
||||
|
||||
BAIL_IF_MACRO(!grp_open(name, forWriting, &fh, &fileCount), NULL, 0);
|
||||
info->entryCount = fileCount;
|
||||
info->entries = (GRPentry *) allocator.Malloc(sizeof(GRPentry)*fileCount);
|
||||
if (info->entries == NULL)
|
||||
{
|
||||
__PHYSFS_platformClose(fh);
|
||||
BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
|
||||
} /* if */
|
||||
BAIL_IF_MACRO(info->entries == NULL, ERR_OUT_OF_MEMORY, 0);
|
||||
|
||||
location += (16 * fileCount);
|
||||
|
||||
for (entry = info->entries; fileCount > 0; fileCount--, entry++)
|
||||
{
|
||||
if ( (!readAll(fh, &entry->name, 12)) ||
|
||||
(!readAll(fh, &entry->size, sizeof (PHYSFS_uint32))) )
|
||||
{
|
||||
__PHYSFS_platformClose(fh);
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
BAIL_IF_MACRO(!readAll(io, &entry->name, 12), NULL, 0);
|
||||
BAIL_IF_MACRO(!readAll(io, &entry->size, 4), NULL, 0);
|
||||
entry->name[12] = '\0'; /* name isn't null-terminated in file. */
|
||||
if ((ptr = strchr(entry->name, ' ')) != NULL)
|
||||
*ptr = '\0'; /* trim extra spaces. */
|
||||
|
@ -241,36 +225,40 @@ static int grp_load_entries(const char *name, int forWriting, GRPinfo *info)
|
|||
location += entry->size;
|
||||
} /* for */
|
||||
|
||||
__PHYSFS_platformClose(fh);
|
||||
|
||||
__PHYSFS_sort(info->entries, info->entryCount,
|
||||
grp_entry_cmp, grp_entry_swap);
|
||||
__PHYSFS_sort(info->entries, info->entryCount, grpEntryCmp, grpEntrySwap);
|
||||
return 1;
|
||||
} /* grp_load_entries */
|
||||
|
||||
|
||||
static void *GRP_openArchive(const char *name, int forWriting)
|
||||
static void *GRP_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
|
||||
{
|
||||
GRPinfo *info = (GRPinfo *) allocator.Malloc(sizeof (GRPinfo));
|
||||
PHYSFS_uint8 buf[12];
|
||||
GRPinfo *info = NULL;
|
||||
PHYSFS_uint32 val = 0;
|
||||
|
||||
BAIL_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, 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, "KenSilverman", sizeof (buf)) != 0)
|
||||
GOTO_MACRO(ERR_NOT_AN_ARCHIVE, GRP_openArchive_failed);
|
||||
|
||||
info = (GRPinfo *) allocator.Malloc(sizeof (GRPinfo));
|
||||
GOTO_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, GRP_openArchive_failed);
|
||||
memset(info, '\0', sizeof (GRPinfo));
|
||||
info->filename = (char *) allocator.Malloc(strlen(name) + 1);
|
||||
GOTO_IF_MACRO(!info->filename, ERR_OUT_OF_MEMORY, GRP_openArchive_failed);
|
||||
info->io = io;
|
||||
|
||||
if (!grp_load_entries(name, forWriting, info))
|
||||
goto GRP_openArchive_failed;
|
||||
GOTO_IF_MACRO(!readAll(io,&val,sizeof(val)), NULL, GRP_openArchive_failed);
|
||||
info->entryCount = PHYSFS_swapULE32(val);
|
||||
|
||||
strcpy(info->filename, name);
|
||||
GOTO_IF_MACRO(!grp_load_entries(io, info), NULL, GRP_openArchive_failed);
|
||||
|
||||
return info;
|
||||
|
||||
GRP_openArchive_failed:
|
||||
if (info != NULL)
|
||||
{
|
||||
if (info->filename != NULL)
|
||||
allocator.Free(info->filename);
|
||||
if (info->entries != NULL)
|
||||
allocator.Free(info->entries);
|
||||
allocator.Free(info);
|
||||
|
@ -318,7 +306,7 @@ static GRPentry *grp_find_entry(const GRPinfo *info, const char *name)
|
|||
while (lo <= hi)
|
||||
{
|
||||
middle = lo + ((hi - lo) / 2);
|
||||
rc = strcmp(name, a[middle].name);
|
||||
rc = __PHYSFS_stricmpASCII(name, a[middle].name);
|
||||
if (rc == 0) /* found it! */
|
||||
return &a[middle];
|
||||
else if (rc > 0)
|
||||
|
@ -351,40 +339,58 @@ static int GRP_isSymLink(dvoid *opaque, const char *name, int *fileExists)
|
|||
} /* GRP_isSymLink */
|
||||
|
||||
|
||||
static fvoid *GRP_openRead(dvoid *opaque, const char *fnm, int *fileExists)
|
||||
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);
|
||||
BAIL_IF_MACRO(entry == NULL, NULL, 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));
|
||||
BAIL_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, NULL);
|
||||
GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, GRP_openRead_failed);
|
||||
|
||||
finfo->handle = __PHYSFS_platformOpenRead(info->filename);
|
||||
if ( (finfo->handle == NULL) ||
|
||||
(!__PHYSFS_platformSeek(finfo->handle, entry->startPos)) )
|
||||
{
|
||||
allocator.Free(finfo);
|
||||
return NULL;
|
||||
} /* if */
|
||||
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;
|
||||
return finfo;
|
||||
|
||||
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 fvoid *GRP_openWrite(dvoid *opaque, const char *name)
|
||||
static PHYSFS_Io *GRP_openWrite(dvoid *opaque, const char *name)
|
||||
{
|
||||
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
|
||||
} /* GRP_openWrite */
|
||||
|
||||
|
||||
static fvoid *GRP_openAppend(dvoid *opaque, const char *name)
|
||||
static PHYSFS_Io *GRP_openAppend(dvoid *opaque, const char *name)
|
||||
{
|
||||
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
|
||||
} /* GRP_openAppend */
|
||||
|
@ -446,14 +452,7 @@ const PHYSFS_Archiver __PHYSFS_Archiver_GRP =
|
|||
GRP_remove, /* remove() method */
|
||||
GRP_mkdir, /* mkdir() method */
|
||||
GRP_dirClose, /* dirClose() method */
|
||||
GRP_stat, /* stat() method */
|
||||
GRP_read, /* read() method */
|
||||
GRP_write, /* write() method */
|
||||
GRP_eof, /* eof() method */
|
||||
GRP_tell, /* tell() method */
|
||||
GRP_seek, /* seek() method */
|
||||
GRP_fileLength, /* fileLength() method */
|
||||
GRP_fileClose /* fileClose() method */
|
||||
GRP_stat /* stat() method */
|
||||
};
|
||||
|
||||
#endif /* defined PHYSFS_SUPPORTS_GRP */
|
||||
|
|
|
@ -54,7 +54,7 @@ typedef struct
|
|||
*/
|
||||
typedef struct
|
||||
{
|
||||
char *filename;
|
||||
PHYSFS_Io *io;
|
||||
PHYSFS_uint32 entryCount;
|
||||
HOGentry *entries;
|
||||
} HOGinfo;
|
||||
|
@ -64,30 +64,30 @@ typedef struct
|
|||
*/
|
||||
typedef struct
|
||||
{
|
||||
void *handle;
|
||||
PHYSFS_Io *io;
|
||||
HOGentry *entry;
|
||||
PHYSFS_uint32 curPos;
|
||||
} HOGfileinfo;
|
||||
|
||||
|
||||
static inline int readAll(void *fh, void *buf, const PHYSFS_uint64 len)
|
||||
static inline int readAll(PHYSFS_Io *io, void *buf, const PHYSFS_uint64 len)
|
||||
{
|
||||
return (__PHYSFS_platformRead(fh, buf, len) == len);
|
||||
return (io->read(io, buf, len) == len);
|
||||
} /* readAll */
|
||||
|
||||
|
||||
static void HOG_dirClose(dvoid *opaque)
|
||||
{
|
||||
HOGinfo *info = ((HOGinfo *) opaque);
|
||||
allocator.Free(info->filename);
|
||||
info->io->destroy(info->io);
|
||||
allocator.Free(info->entries);
|
||||
allocator.Free(info);
|
||||
} /* HOG_dirClose */
|
||||
|
||||
|
||||
static PHYSFS_sint64 HOG_read(fvoid *opaque, void *buffer, PHYSFS_uint64 len)
|
||||
static PHYSFS_sint64 HOG_read(PHYSFS_Io *io, void *buffer, PHYSFS_uint64 len)
|
||||
{
|
||||
HOGfileinfo *finfo = (HOGfileinfo *) opaque;
|
||||
HOGfileinfo *finfo = (HOGfileinfo *) io->opaque;
|
||||
const HOGentry *entry = finfo->entry;
|
||||
const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos);
|
||||
PHYSFS_sint64 rc;
|
||||
|
@ -95,7 +95,7 @@ static PHYSFS_sint64 HOG_read(fvoid *opaque, void *buffer, PHYSFS_uint64 len)
|
|||
if (bytesLeft < len)
|
||||
len = bytesLeft;
|
||||
|
||||
rc = __PHYSFS_platformRead(finfo->handle, buffer, len);
|
||||
rc = finfo->io->read(finfo->io, buffer, len);
|
||||
if (rc > 0)
|
||||
finfo->curPos += (PHYSFS_uint32) rc;
|
||||
|
||||
|
@ -103,35 +103,26 @@ static PHYSFS_sint64 HOG_read(fvoid *opaque, void *buffer, PHYSFS_uint64 len)
|
|||
} /* HOG_read */
|
||||
|
||||
|
||||
static PHYSFS_sint64 HOG_write(fvoid *f, const void *buf, PHYSFS_uint64 len)
|
||||
static PHYSFS_sint64 HOG_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
|
||||
{
|
||||
BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
|
||||
} /* HOG_write */
|
||||
|
||||
|
||||
static int HOG_eof(fvoid *opaque)
|
||||
static PHYSFS_sint64 HOG_tell(PHYSFS_Io *io)
|
||||
{
|
||||
HOGfileinfo *finfo = (HOGfileinfo *) opaque;
|
||||
HOGentry *entry = finfo->entry;
|
||||
return (finfo->curPos >= entry->size);
|
||||
} /* HOG_eof */
|
||||
|
||||
|
||||
static PHYSFS_sint64 HOG_tell(fvoid *opaque)
|
||||
{
|
||||
return ((HOGfileinfo *) opaque)->curPos;
|
||||
return ((HOGfileinfo *) io->opaque)->curPos;
|
||||
} /* HOG_tell */
|
||||
|
||||
|
||||
static int HOG_seek(fvoid *opaque, PHYSFS_uint64 offset)
|
||||
static int HOG_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
|
||||
{
|
||||
HOGfileinfo *finfo = (HOGfileinfo *) opaque;
|
||||
HOGentry *entry = finfo->entry;
|
||||
HOGfileinfo *finfo = (HOGfileinfo *) io->opaque;
|
||||
const HOGentry *entry = finfo->entry;
|
||||
int rc;
|
||||
|
||||
BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
|
||||
BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
|
||||
rc = __PHYSFS_platformSeek(finfo->handle, entry->startPos + offset);
|
||||
rc = finfo->io->seek(finfo->io, entry->startPos + offset);
|
||||
if (rc)
|
||||
finfo->curPos = (PHYSFS_uint32) offset;
|
||||
|
||||
|
@ -139,83 +130,65 @@ static int HOG_seek(fvoid *opaque, PHYSFS_uint64 offset)
|
|||
} /* HOG_seek */
|
||||
|
||||
|
||||
static PHYSFS_sint64 HOG_fileLength(fvoid *opaque)
|
||||
static PHYSFS_sint64 HOG_length(PHYSFS_Io *io)
|
||||
{
|
||||
HOGfileinfo *finfo = (HOGfileinfo *) opaque;
|
||||
const HOGfileinfo *finfo = (HOGfileinfo *) io->opaque;
|
||||
return ((PHYSFS_sint64) finfo->entry->size);
|
||||
} /* HOG_fileLength */
|
||||
} /* HOG_length */
|
||||
|
||||
|
||||
static int HOG_fileClose(fvoid *opaque)
|
||||
static PHYSFS_Io *HOG_duplicate(PHYSFS_Io *_io)
|
||||
{
|
||||
HOGfileinfo *finfo = (HOGfileinfo *) opaque;
|
||||
BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0);
|
||||
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);
|
||||
return 1;
|
||||
} /* HOG_fileClose */
|
||||
allocator.Free(io);
|
||||
} /* HOG_destroy */
|
||||
|
||||
|
||||
static int hog_open(const char *filename, int forWriting,
|
||||
void **fh, PHYSFS_uint32 *count)
|
||||
static const PHYSFS_Io HOG_Io =
|
||||
{
|
||||
PHYSFS_uint8 buf[13];
|
||||
PHYSFS_uint32 size;
|
||||
PHYSFS_sint64 pos;
|
||||
|
||||
*count = 0;
|
||||
|
||||
*fh = NULL;
|
||||
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
|
||||
|
||||
*fh = __PHYSFS_platformOpenRead(filename);
|
||||
BAIL_IF_MACRO(*fh == NULL, NULL, 0);
|
||||
|
||||
if (!readAll(*fh, buf, 3))
|
||||
goto openHog_failed;
|
||||
|
||||
if (memcmp(buf, "DHF", 3) != 0)
|
||||
{
|
||||
__PHYSFS_setError(ERR_UNSUPPORTED_ARCHIVE);
|
||||
goto openHog_failed;
|
||||
} /* if */
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (!readAll(*fh, buf, 13))
|
||||
break; /* eof here is ok */
|
||||
|
||||
if (!readAll(*fh, &size, sizeof (PHYSFS_uint32)))
|
||||
goto openHog_failed;
|
||||
|
||||
size = PHYSFS_swapULE32(size);
|
||||
|
||||
(*count)++;
|
||||
|
||||
/* Skip over entry... */
|
||||
pos = __PHYSFS_platformTell(*fh);
|
||||
if (pos == -1)
|
||||
goto openHog_failed;
|
||||
if (!__PHYSFS_platformSeek(*fh, pos + size))
|
||||
goto openHog_failed;
|
||||
} /* while */
|
||||
|
||||
/* Rewind to start of entries... */
|
||||
if (!__PHYSFS_platformSeek(*fh, 3))
|
||||
goto openHog_failed;
|
||||
|
||||
return 1;
|
||||
|
||||
openHog_failed:
|
||||
if (*fh != NULL)
|
||||
__PHYSFS_platformClose(*fh);
|
||||
|
||||
*count = -1;
|
||||
*fh = NULL;
|
||||
return 0;
|
||||
} /* hog_open */
|
||||
HOG_read,
|
||||
HOG_write,
|
||||
HOG_seek,
|
||||
HOG_tell,
|
||||
HOG_length,
|
||||
HOG_duplicate,
|
||||
HOG_flush,
|
||||
HOG_destroy,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
static int hog_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
|
||||
|
||||
static int hogEntryCmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
|
||||
{
|
||||
if (one != two)
|
||||
{
|
||||
|
@ -224,10 +197,10 @@ static int hog_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
|
|||
} /* if */
|
||||
|
||||
return 0;
|
||||
} /* hog_entry_cmp */
|
||||
} /* hogEntryCmp */
|
||||
|
||||
|
||||
static void hog_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
|
||||
static void hogEntrySwap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
|
||||
{
|
||||
if (one != two)
|
||||
{
|
||||
|
@ -238,74 +211,70 @@ static void hog_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
|
|||
memcpy(first, second, sizeof (HOGentry));
|
||||
memcpy(second, &tmp, sizeof (HOGentry));
|
||||
} /* if */
|
||||
} /* hog_entry_swap */
|
||||
} /* hogEntrySwap */
|
||||
|
||||
|
||||
static int hog_load_entries(const char *name, int forWriting, HOGinfo *info)
|
||||
static int hog_load_entries(PHYSFS_Io *io, HOGinfo *info)
|
||||
{
|
||||
void *fh = NULL;
|
||||
PHYSFS_uint32 fileCount;
|
||||
HOGentry *entry;
|
||||
const PHYSFS_uint64 iolen = io->length(io);
|
||||
PHYSFS_uint32 entCount = 0;
|
||||
void *ptr = NULL;
|
||||
HOGentry *entry = NULL;
|
||||
PHYSFS_uint32 size = 0;
|
||||
PHYSFS_uint32 pos = 3;
|
||||
|
||||
BAIL_IF_MACRO(!hog_open(name, forWriting, &fh, &fileCount), NULL, 0);
|
||||
info->entryCount = fileCount;
|
||||
info->entries = (HOGentry *) allocator.Malloc(sizeof(HOGentry)*fileCount);
|
||||
if (info->entries == NULL)
|
||||
while (pos < iolen)
|
||||
{
|
||||
__PHYSFS_platformClose(fh);
|
||||
BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
|
||||
} /* if */
|
||||
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];
|
||||
|
||||
for (entry = info->entries; fileCount > 0; fileCount--, entry++)
|
||||
{
|
||||
if ( (!readAll(fh, &entry->name, 13)) ||
|
||||
(!readAll(fh, &entry->size, sizeof (PHYSFS_uint32))) )
|
||||
{
|
||||
__PHYSFS_platformClose(fh);
|
||||
return 0;
|
||||
} /* if */
|
||||
BAIL_IF_MACRO(!readAll(io, &entry->name, 13), NULL, 0);
|
||||
pos += 13;
|
||||
BAIL_IF_MACRO(!readAll(io, &size, 4), NULL, 0);
|
||||
pos += 4;
|
||||
|
||||
entry->size = PHYSFS_swapULE32(entry->size);
|
||||
entry->startPos = (unsigned int) __PHYSFS_platformTell(fh);
|
||||
entry->size = PHYSFS_swapULE32(size);
|
||||
entry->startPos = pos;
|
||||
pos += size;
|
||||
|
||||
/* Skip over entry */
|
||||
if ( (entry->startPos == -1) ||
|
||||
(!__PHYSFS_platformSeek(fh, entry->startPos + entry->size)) )
|
||||
{
|
||||
__PHYSFS_platformClose(fh);
|
||||
return 0;
|
||||
} /* if */
|
||||
BAIL_IF_MACRO(!io->seek(io, pos), NULL, 0); /* skip over entry */
|
||||
} /* for */
|
||||
|
||||
__PHYSFS_platformClose(fh);
|
||||
info->entryCount = entCount;
|
||||
|
||||
__PHYSFS_sort(info->entries, info->entryCount,
|
||||
hog_entry_cmp, hog_entry_swap);
|
||||
__PHYSFS_sort(info->entries, entCount, hogEntryCmp, hogEntrySwap);
|
||||
return 1;
|
||||
} /* hog_load_entries */
|
||||
|
||||
|
||||
static void *HOG_openArchive(const char *name, int forWriting)
|
||||
static void *HOG_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
|
||||
{
|
||||
HOGinfo *info = (HOGinfo *) allocator.Malloc(sizeof (HOGinfo));
|
||||
PHYSFS_uint8 buf[3];
|
||||
HOGinfo *info = NULL;
|
||||
|
||||
BAIL_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, 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);
|
||||
|
||||
info = (HOGinfo *) allocator.Malloc(sizeof (HOGinfo));
|
||||
GOTO_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, HOG_openArchive_failed);
|
||||
memset(info, '\0', sizeof (HOGinfo));
|
||||
info->filename = (char *) allocator.Malloc(strlen(name) + 1);
|
||||
GOTO_IF_MACRO(!info->filename, ERR_OUT_OF_MEMORY, HOG_openArchive_failed);
|
||||
info->io = io;
|
||||
|
||||
if (!hog_load_entries(name, forWriting, info))
|
||||
goto HOG_openArchive_failed;
|
||||
|
||||
strcpy(info->filename, name);
|
||||
GOTO_IF_MACRO(!hog_load_entries(io, info), NULL, HOG_openArchive_failed);
|
||||
|
||||
return info;
|
||||
|
||||
HOG_openArchive_failed:
|
||||
if (info != NULL)
|
||||
{
|
||||
if (info->filename != NULL)
|
||||
allocator.Free(info->filename);
|
||||
if (info->entries != NULL)
|
||||
allocator.Free(info->entries);
|
||||
allocator.Free(info);
|
||||
|
@ -368,7 +337,7 @@ static HOGentry *hog_find_entry(const HOGinfo *info, const char *name)
|
|||
|
||||
static int HOG_exists(dvoid *opaque, const char *name)
|
||||
{
|
||||
return (hog_find_entry(((HOGinfo *) opaque), name) != NULL);
|
||||
return (hog_find_entry((HOGinfo *) opaque, name) != NULL);
|
||||
} /* HOG_exists */
|
||||
|
||||
|
||||
|
@ -386,40 +355,58 @@ static int HOG_isSymLink(dvoid *opaque, const char *name, int *fileExists)
|
|||
} /* HOG_isSymLink */
|
||||
|
||||
|
||||
static fvoid *HOG_openRead(dvoid *opaque, const char *fnm, int *fileExists)
|
||||
static PHYSFS_Io *HOG_openRead(dvoid *opaque, const char *fnm, int *fileExists)
|
||||
{
|
||||
HOGinfo *info = ((HOGinfo *) opaque);
|
||||
PHYSFS_Io *retval = NULL;
|
||||
HOGinfo *info = (HOGinfo *) opaque;
|
||||
HOGfileinfo *finfo;
|
||||
HOGentry *entry;
|
||||
|
||||
entry = hog_find_entry(info, fnm);
|
||||
*fileExists = (entry != NULL);
|
||||
BAIL_IF_MACRO(entry == NULL, NULL, 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));
|
||||
BAIL_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, NULL);
|
||||
GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, HOG_openRead_failed);
|
||||
|
||||
finfo->handle = __PHYSFS_platformOpenRead(info->filename);
|
||||
if ( (finfo->handle == NULL) ||
|
||||
(!__PHYSFS_platformSeek(finfo->handle, entry->startPos)) )
|
||||
{
|
||||
allocator.Free(finfo);
|
||||
return NULL;
|
||||
} /* if */
|
||||
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;
|
||||
return finfo;
|
||||
|
||||
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 fvoid *HOG_openWrite(dvoid *opaque, const char *name)
|
||||
static PHYSFS_Io *HOG_openWrite(dvoid *opaque, const char *name)
|
||||
{
|
||||
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
|
||||
} /* HOG_openWrite */
|
||||
|
||||
|
||||
static fvoid *HOG_openAppend(dvoid *opaque, const char *name)
|
||||
static PHYSFS_Io *HOG_openAppend(dvoid *opaque, const char *name)
|
||||
{
|
||||
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
|
||||
} /* HOG_openAppend */
|
||||
|
@ -481,14 +468,7 @@ const PHYSFS_Archiver __PHYSFS_Archiver_HOG =
|
|||
HOG_remove, /* remove() method */
|
||||
HOG_mkdir, /* mkdir() method */
|
||||
HOG_dirClose, /* dirClose() method */
|
||||
HOG_stat, /* stat() method */
|
||||
HOG_read, /* read() method */
|
||||
HOG_write, /* write() method */
|
||||
HOG_eof, /* eof() method */
|
||||
HOG_tell, /* tell() method */
|
||||
HOG_seek, /* seek() method */
|
||||
HOG_fileLength, /* fileLength() method */
|
||||
HOG_fileClose /* fileClose() method */
|
||||
HOG_stat /* stat() method */
|
||||
};
|
||||
|
||||
#endif /* defined PHYSFS_SUPPORTS_HOG */
|
||||
|
|
|
@ -200,7 +200,7 @@ typedef struct
|
|||
|
||||
typedef struct
|
||||
{
|
||||
void *fhandle;
|
||||
PHYSFS_Io *io;
|
||||
PHYSFS_uint32 rootdirstart;
|
||||
PHYSFS_uint32 rootdirsize;
|
||||
PHYSFS_uint64 currpos;
|
||||
|
@ -219,12 +219,13 @@ typedef struct __ISO9660FileHandle
|
|||
PHYSFS_uint32 (*read) (struct __ISO9660FileHandle *filehandle, void *buffer,
|
||||
PHYSFS_uint64 len);
|
||||
int (*seek)(struct __ISO9660FileHandle *filehandle, PHYSFS_sint64 offset);
|
||||
int (*close)(struct __ISO9660FileHandle *filehandle);
|
||||
void (*close)(struct __ISO9660FileHandle *filehandle);
|
||||
/* !!! FIXME: anonymouse union is going to cause problems. */
|
||||
union
|
||||
{
|
||||
/* !!! FIXME: just use a memory PHYSFS_Io here, unify all this code. */
|
||||
char *cacheddata; /* data of file when cached */
|
||||
void *filehandle; /* handle to separate opened file */
|
||||
PHYSFS_Io *io; /* handle to separate opened file */
|
||||
};
|
||||
} ISO9660FileHandle;
|
||||
|
||||
|
@ -349,9 +350,8 @@ static int iso_readimage(ISO9660Handle *handle, PHYSFS_uint64 where,
|
|||
ERR_LOCK_VIOLATION, -1);
|
||||
int rc = -1;
|
||||
if (where != handle->currpos)
|
||||
GOTO_IF_MACRO(!__PHYSFS_platformSeek(handle->fhandle,where), NULL,
|
||||
unlockme);
|
||||
rc = __PHYSFS_platformRead(handle->fhandle, buffer, len);
|
||||
GOTO_IF_MACRO(!handle->io->seek(handle->io,where), NULL, unlockme);
|
||||
rc = handle->io->read(handle->io, buffer, len);
|
||||
if (rc == -1)
|
||||
{
|
||||
handle->currpos = (PHYSFS_uint64) -1;
|
||||
|
@ -479,53 +479,94 @@ static int iso_read_ext_attributes(ISO9660Handle *handle, int block,
|
|||
} /* iso_read_ext_attributes */
|
||||
|
||||
|
||||
static int ISO9660_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
|
||||
|
||||
static PHYSFS_Io *ISO9660_duplicate(PHYSFS_Io *_io)
|
||||
{
|
||||
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL); /* !!! FIXME: write me. */
|
||||
} /* ISO9660_duplicate */
|
||||
|
||||
|
||||
static void ISO9660_destroy(PHYSFS_Io *io)
|
||||
{
|
||||
ISO9660FileHandle *fhandle = (ISO9660FileHandle*) io->opaque;
|
||||
fhandle->close(fhandle);
|
||||
allocator.Free(io);
|
||||
} /* ISO9660_destroy */
|
||||
|
||||
|
||||
static PHYSFS_sint64 ISO9660_read(PHYSFS_Io *io, void *buf, PHYSFS_uint64 len)
|
||||
{
|
||||
ISO9660FileHandle *fhandle = (ISO9660FileHandle*) io->opaque;
|
||||
return fhandle->read(fhandle, buf, len);
|
||||
} /* ISO9660_read */
|
||||
|
||||
|
||||
static PHYSFS_sint64 ISO9660_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 l)
|
||||
{
|
||||
BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
|
||||
} /* ISO9660_write */
|
||||
|
||||
|
||||
static PHYSFS_sint64 ISO9660_tell(PHYSFS_Io *io)
|
||||
{
|
||||
return ((ISO9660FileHandle*) io->opaque)->currpos;
|
||||
} /* ISO9660_tell */
|
||||
|
||||
|
||||
static int ISO9660_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
|
||||
{
|
||||
ISO9660FileHandle *fhandle = (ISO9660FileHandle*) io->opaque;
|
||||
return fhandle->seek(fhandle, offset);
|
||||
} /* ISO9660_seek */
|
||||
|
||||
|
||||
static PHYSFS_sint64 ISO9660_length(PHYSFS_Io *io)
|
||||
{
|
||||
return ((ISO9660FileHandle*) io->opaque)->filesize;
|
||||
} /* ISO9660_length */
|
||||
|
||||
|
||||
static const PHYSFS_Io ISO9660_Io =
|
||||
{
|
||||
ISO9660_read,
|
||||
ISO9660_write,
|
||||
ISO9660_seek,
|
||||
ISO9660_tell,
|
||||
ISO9660_length,
|
||||
ISO9660_duplicate,
|
||||
ISO9660_flush,
|
||||
ISO9660_destroy,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Archive management functions
|
||||
******************************************************************************/
|
||||
|
||||
/* !!! FIXME: don't open/close file here, merge with openArchive(). */
|
||||
static int isIso(const char *filename)
|
||||
{
|
||||
char magicnumber[6] = {0,0,0,0,0,0};
|
||||
void *in;
|
||||
|
||||
in = __PHYSFS_platformOpenRead(filename);
|
||||
BAIL_IF_MACRO(in == NULL, NULL, 0);
|
||||
|
||||
/* Skip system area to magic number in Volume descriptor */
|
||||
if (__PHYSFS_platformSeek(in, 32769) == 0)
|
||||
{
|
||||
__PHYSFS_platformClose(in); /* Don't forget to close the file before returning... */
|
||||
BAIL_MACRO(NULL, 0);
|
||||
} /* if */
|
||||
|
||||
/* Read magic number */
|
||||
if (__PHYSFS_platformRead(in, magicnumber, 5) != 5)
|
||||
{
|
||||
__PHYSFS_platformClose(in); /* Don't forget to close the file before returning... */
|
||||
BAIL_MACRO(NULL, 0);
|
||||
} /* if */
|
||||
|
||||
__PHYSFS_platformClose(in);
|
||||
|
||||
return (strcmp(magicnumber, "CD001") == 0);
|
||||
} /* isIso */
|
||||
|
||||
|
||||
static void *ISO9660_openArchive(const char *filename, int forWriting)
|
||||
static void *ISO9660_openArchive(PHYSFS_Io *io, const char *filename, int forWriting)
|
||||
{
|
||||
char magicnumber[6];
|
||||
ISO9660Handle *handle;
|
||||
int founddescriptor = 0;
|
||||
int foundjoliet = 0;
|
||||
|
||||
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
|
||||
BAIL_IF_MACRO(!isIso(filename), ERR_UNSUPPORTED_ARCHIVE, NULL);
|
||||
assert(io != NULL); /* shouldn't ever happen. */
|
||||
|
||||
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, NULL);
|
||||
|
||||
/* Skip system area to magic number in Volume descriptor */
|
||||
BAIL_IF_MACRO(!io->seek(io, 32769), NULL, NULL);
|
||||
BAIL_IF_MACRO(!io->read(io, magicnumber, 5) != 5, NULL, NULL);
|
||||
if (memcmp(magicnumber, "CD001", 6) != 0)
|
||||
BAIL_MACRO(ERR_NOT_AN_ARCHIVE, NULL);
|
||||
|
||||
handle = allocator.Malloc(sizeof(ISO9660Handle));
|
||||
GOTO_IF_MACRO(!handle, ERR_OUT_OF_MEMORY, errorcleanup);
|
||||
handle->path = 0;
|
||||
handle->mutex= 0;
|
||||
handle->fhandle = 0;
|
||||
handle->io = NULL;
|
||||
|
||||
handle->path = allocator.Malloc(strlen(filename) + 1);
|
||||
GOTO_IF_MACRO(!handle->path, ERR_OUT_OF_MEMORY, errorcleanup);
|
||||
|
@ -534,16 +575,15 @@ static void *ISO9660_openArchive(const char *filename, int forWriting)
|
|||
handle->mutex = __PHYSFS_platformCreateMutex();
|
||||
GOTO_IF_MACRO(!handle->mutex, "Cannot create Mutex", errorcleanup);
|
||||
|
||||
handle->fhandle = __PHYSFS_platformOpenRead(filename);
|
||||
GOTO_IF_MACRO(!handle->fhandle, NULL, errorcleanup);
|
||||
handle->io = io;
|
||||
|
||||
/* seek Primary Volume Descriptor */
|
||||
GOTO_IF_MACRO(!__PHYSFS_platformSeek(handle->fhandle, 32768), ERR_SEEK_ERROR, errorcleanup);
|
||||
GOTO_IF_MACRO(!io->seek(io, 32768), ERR_SEEK_ERROR, errorcleanup);
|
||||
|
||||
while (1)
|
||||
{
|
||||
ISO9660VolumeDescriptor descriptor;
|
||||
GOTO_IF_MACRO(__PHYSFS_platformRead(handle->fhandle, &descriptor, sizeof(ISO9660VolumeDescriptor)) != sizeof(ISO9660VolumeDescriptor), "Cannot read from image", errorcleanup);
|
||||
GOTO_IF_MACRO(io->read(io, &descriptor, sizeof(ISO9660VolumeDescriptor)) != sizeof(ISO9660VolumeDescriptor), "Cannot read from image", errorcleanup);
|
||||
GOTO_IF_MACRO(strncmp(descriptor.identifier, "CD001", 5) != 0, ERR_NOT_AN_ARCHIVE, errorcleanup);
|
||||
|
||||
if (descriptor.type == 255)
|
||||
|
@ -556,7 +596,7 @@ static void *ISO9660_openArchive(const char *filename, int forWriting)
|
|||
} /* if */
|
||||
if (descriptor.type == 1 && !founddescriptor)
|
||||
{
|
||||
handle->currpos = __PHYSFS_platformTell(handle->fhandle);
|
||||
handle->currpos = io->tell(io);
|
||||
handle->rootdirstart =
|
||||
descriptor.rootdirectory.extent_location * 2048;
|
||||
handle->rootdirsize =
|
||||
|
@ -575,7 +615,7 @@ static void *ISO9660_openArchive(const char *filename, int forWriting)
|
|||
if (!joliet)
|
||||
continue;
|
||||
|
||||
handle->currpos = __PHYSFS_platformTell(handle->fhandle);
|
||||
handle->currpos = io->tell(io);
|
||||
handle->rootdirstart =
|
||||
descriptor.rootdirectory.extent_location * 2048;
|
||||
handle->rootdirsize =
|
||||
|
@ -591,12 +631,11 @@ static void *ISO9660_openArchive(const char *filename, int forWriting)
|
|||
errorcleanup:
|
||||
if (handle)
|
||||
{
|
||||
if (handle->fhandle)
|
||||
__PHYSFS_platformClose(handle->fhandle);
|
||||
if (handle->path)
|
||||
allocator.Free(handle->path);
|
||||
if (handle->mutex)
|
||||
__PHYSFS_platformDestroyMutex(handle->mutex);
|
||||
allocator.Free(handle);
|
||||
} /* if */
|
||||
return NULL;
|
||||
} /* ISO9660_openArchive */
|
||||
|
@ -605,7 +644,7 @@ errorcleanup:
|
|||
static void ISO9660_dirClose(dvoid *opaque)
|
||||
{
|
||||
ISO9660Handle *handle = (ISO9660Handle*) opaque;
|
||||
__PHYSFS_platformClose(handle->fhandle);
|
||||
handle->io->destroy(handle->io);
|
||||
__PHYSFS_platformDestroyMutex(handle->mutex);
|
||||
allocator.Free(handle->path);
|
||||
allocator.Free(handle);
|
||||
|
@ -645,12 +684,11 @@ static int iso_file_seek_mem(ISO9660FileHandle *fhandle, PHYSFS_sint64 offset)
|
|||
} /* iso_file_seek_mem */
|
||||
|
||||
|
||||
static int iso_file_close_mem(ISO9660FileHandle *fhandle)
|
||||
static void iso_file_close_mem(ISO9660FileHandle *fhandle)
|
||||
{
|
||||
allocator.Free(fhandle->cacheddata);
|
||||
allocator.Free(fhandle);
|
||||
return -1;
|
||||
} /* iso_file_seek_mem */
|
||||
} /* iso_file_close_mem */
|
||||
|
||||
|
||||
static PHYSFS_uint32 iso_file_read_foreign(ISO9660FileHandle *filehandle,
|
||||
|
@ -661,8 +699,7 @@ static PHYSFS_uint32 iso_file_read_foreign(ISO9660FileHandle *filehandle,
|
|||
if (bytesleft < len)
|
||||
len = bytesleft;
|
||||
|
||||
PHYSFS_sint64 rc = __PHYSFS_platformRead(filehandle->filehandle, buffer,
|
||||
len);
|
||||
const PHYSFS_sint64 rc = filehandle->io->read(filehandle->io, buffer, len);
|
||||
BAIL_IF_MACRO(rc == -1, NULL, -1);
|
||||
|
||||
filehandle->currpos += rc; /* i trust my internal book keeping */
|
||||
|
@ -678,19 +715,17 @@ static int iso_file_seek_foreign(ISO9660FileHandle *fhandle,
|
|||
BAIL_IF_MACRO(offset >= fhandle->filesize, ERR_PAST_EOF, 0);
|
||||
|
||||
PHYSFS_sint64 pos = fhandle->startblock * 2048 + offset;
|
||||
int rc = __PHYSFS_platformSeek(fhandle->filehandle, pos);
|
||||
BAIL_IF_MACRO(rc, NULL, -1);
|
||||
BAIL_IF_MACRO(!fhandle->io->seek(fhandle->io, pos), NULL, -1);
|
||||
|
||||
fhandle->currpos = offset;
|
||||
return 0;
|
||||
} /* iso_file_seek_foreign */
|
||||
|
||||
|
||||
static int iso_file_close_foreign(ISO9660FileHandle *fhandle)
|
||||
static void iso_file_close_foreign(ISO9660FileHandle *fhandle)
|
||||
{
|
||||
void *filehandle = fhandle->filehandle;
|
||||
fhandle->io->destroy(fhandle->io);
|
||||
allocator.Free(fhandle);
|
||||
return __PHYSFS_platformClose(filehandle);
|
||||
} /* iso_file_close_foreign */
|
||||
|
||||
|
||||
|
@ -717,10 +752,10 @@ freemem:
|
|||
static int iso_file_open_foreign(ISO9660Handle *handle,
|
||||
ISO9660FileHandle *fhandle)
|
||||
{
|
||||
fhandle->filehandle = __PHYSFS_platformOpenRead(handle->path);
|
||||
BAIL_IF_MACRO(!fhandle->filehandle, NULL, -1);
|
||||
int rc = __PHYSFS_platformSeek(fhandle->filehandle,
|
||||
fhandle->startblock * 2048);
|
||||
int rc;
|
||||
fhandle->io = __PHYSFS_createNativeIo(handle->path, 'r');
|
||||
BAIL_IF_MACRO(!fhandle->io, NULL, -1);
|
||||
rc = fhandle->io->seek(fhandle->io, fhandle->startblock * 2048);
|
||||
GOTO_IF_MACRO(!rc, NULL, closefile);
|
||||
|
||||
fhandle->read = iso_file_read_foreign;
|
||||
|
@ -728,14 +763,15 @@ static int iso_file_open_foreign(ISO9660Handle *handle,
|
|||
fhandle->close = iso_file_close_foreign;
|
||||
return 0;
|
||||
|
||||
closefile:
|
||||
__PHYSFS_platformClose(fhandle->filehandle);
|
||||
closefile:
|
||||
fhandle->io->destroy(fhandle->io);
|
||||
return -1;
|
||||
} /* iso_file_open_foreign */
|
||||
|
||||
|
||||
static fvoid *ISO9660_openRead(dvoid *opaque, const char *filename, int *exists)
|
||||
static PHYSFS_Io *ISO9660_openRead(dvoid *opaque, const char *filename, int *exists)
|
||||
{
|
||||
PHYSFS_Io *retval = NULL;
|
||||
ISO9660Handle *handle = (ISO9660Handle*) opaque;
|
||||
ISO9660FileHandle *fhandle;
|
||||
ISO9660FileDescriptor descriptor;
|
||||
|
@ -745,6 +781,9 @@ static fvoid *ISO9660_openRead(dvoid *opaque, const char *filename, int *exists)
|
|||
BAIL_IF_MACRO(fhandle == 0, ERR_OUT_OF_MEMORY, NULL);
|
||||
fhandle->cacheddata = 0;
|
||||
|
||||
retval = allocator.Malloc(sizeof(PHYSFS_Io));
|
||||
GOTO_IF_MACRO(retval == 0, ERR_OUT_OF_MEMORY, errorhandling);
|
||||
|
||||
/* find file descriptor */
|
||||
rc = iso_find_dir_entry(handle, filename, &descriptor, exists);
|
||||
GOTO_IF_MACRO(rc, NULL, errorhandling);
|
||||
|
@ -755,7 +794,7 @@ static fvoid *ISO9660_openRead(dvoid *opaque, const char *filename, int *exists)
|
|||
fhandle->currpos = 0;
|
||||
fhandle->isohandle = handle;
|
||||
fhandle->cacheddata = NULL;
|
||||
fhandle->filehandle = NULL;
|
||||
fhandle->io = NULL;
|
||||
|
||||
if (descriptor.datalen <= ISO9660_FULLCACHEMAXSIZE)
|
||||
rc = iso_file_open_mem(handle, fhandle);
|
||||
|
@ -763,53 +802,17 @@ static fvoid *ISO9660_openRead(dvoid *opaque, const char *filename, int *exists)
|
|||
rc = iso_file_open_foreign(handle, fhandle);
|
||||
GOTO_IF_MACRO(rc, NULL, errorhandling);
|
||||
|
||||
return fhandle;
|
||||
memcpy(retval, &ISO9660_Io, sizeof (PHYSFS_Io));
|
||||
retval->opaque = fhandle;
|
||||
return retval;
|
||||
|
||||
errorhandling:
|
||||
if (!fhandle)
|
||||
return NULL;
|
||||
allocator.Free(fhandle);
|
||||
if (retval) allocator.Free(retval);
|
||||
if (fhandle) allocator.Free(fhandle);
|
||||
return NULL;
|
||||
} /* ISO9660_openRead */
|
||||
|
||||
|
||||
static int ISO9660_fileClose(fvoid *opaque)
|
||||
{
|
||||
ISO9660FileHandle *fhandle = (ISO9660FileHandle*) opaque;
|
||||
return fhandle->close(fhandle);
|
||||
} /* ISO9660_fileClose */
|
||||
|
||||
static PHYSFS_sint64 ISO9660_read(fvoid *opaque, void *buf, PHYSFS_uint64 len)
|
||||
{
|
||||
ISO9660FileHandle *fhandle = (ISO9660FileHandle*) opaque;
|
||||
return fhandle->read(fhandle, buf, len);
|
||||
} /* ISO9660_read */
|
||||
|
||||
|
||||
static PHYSFS_sint64 ISO9660_tell(fvoid *opaque)
|
||||
{
|
||||
return ((ISO9660FileHandle*) opaque)->currpos;
|
||||
} /* ISO9660_tell */
|
||||
|
||||
|
||||
static int ISO9660_seek(fvoid *opaque, PHYSFS_uint64 offset)
|
||||
{
|
||||
ISO9660FileHandle *fhandle = (ISO9660FileHandle*) opaque;
|
||||
return fhandle->seek(fhandle, offset);
|
||||
} /* ISO9660_seek */
|
||||
|
||||
|
||||
static int ISO9660_eof(fvoid *opaque)
|
||||
{
|
||||
ISO9660FileHandle *fhandle = (ISO9660FileHandle*) opaque;
|
||||
return fhandle->currpos >= fhandle->filesize;
|
||||
} /* ISO9660_eof */
|
||||
|
||||
|
||||
static PHYSFS_sint64 ISO9660_fileLength(fvoid *opaque)
|
||||
{
|
||||
return ((ISO9660FileHandle*) opaque)->filesize;
|
||||
} /* ISO9660_fileLength */
|
||||
|
||||
/*******************************************************************************
|
||||
* Information gathering functions
|
||||
|
@ -945,13 +948,13 @@ static int ISO9660_isSymLink(dvoid *opaque, const char *name, int *fileExists)
|
|||
* Not supported functions
|
||||
******************************************************************************/
|
||||
|
||||
static fvoid* ISO9660_openWrite(dvoid *opaque, const char *name)
|
||||
static PHYSFS_Io *ISO9660_openWrite(dvoid *opaque, const char *name)
|
||||
{
|
||||
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
|
||||
} /* ISO9660_openWrite */
|
||||
|
||||
|
||||
static fvoid* ISO9660_openAppend(dvoid *opaque, const char *name)
|
||||
static PHYSFS_Io *ISO9660_openAppend(dvoid *opaque, const char *name)
|
||||
{
|
||||
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
|
||||
} /* ISO9660_openAppend */
|
||||
|
@ -969,11 +972,6 @@ static int ISO9660_mkdir(dvoid *opaque, const char *name)
|
|||
} /* ISO9660_mkdir */
|
||||
|
||||
|
||||
static PHYSFS_sint64 ISO9660_write(fvoid *f, const void *buf, PHYSFS_uint64 len)
|
||||
{
|
||||
BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
|
||||
} /* ISO9660_write */
|
||||
|
||||
|
||||
const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_ISO9660 =
|
||||
{
|
||||
|
@ -997,14 +995,7 @@ const PHYSFS_Archiver __PHYSFS_Archiver_ISO9660 =
|
|||
ISO9660_remove, /* remove() method */
|
||||
ISO9660_mkdir, /* mkdir() method */
|
||||
ISO9660_dirClose, /* dirClose() method */
|
||||
ISO9660_stat, /* stat() method */
|
||||
ISO9660_read, /* read() method */
|
||||
ISO9660_write, /* write() method */
|
||||
ISO9660_eof, /* eof() method */
|
||||
ISO9660_tell, /* tell() method */
|
||||
ISO9660_seek, /* seek() method */
|
||||
ISO9660_fileLength, /* fileLength() method */
|
||||
ISO9660_fileClose /* fileClose() method */
|
||||
ISO9660_stat /* stat() method */
|
||||
};
|
||||
|
||||
#endif /* defined PHYSFS_SUPPORTS_ISO9660 */
|
||||
|
|
|
@ -40,7 +40,7 @@ typedef struct _FileInputStream
|
|||
ISzAlloc allocImp; /* Allocation implementation, used by 7z */
|
||||
ISzAlloc allocTempImp; /* Temporary allocation implementation, used by 7z */
|
||||
ISzInStream inStream; /* Input stream with read callbacks, used by 7z */
|
||||
void *file; /* Filehandle, used by read implementation */
|
||||
PHYSFS_Io *io; /* Filehandle, used by read implementation */
|
||||
#ifdef _LZMA_IN_CB
|
||||
Byte buffer[BUFFER_SIZE]; /* Buffer, used by read implementation */
|
||||
#endif /* _LZMA_IN_CB */
|
||||
|
@ -113,7 +113,7 @@ SZ_RESULT SzFileReadImp(void *object, void **buffer, size_t maxReqSize,
|
|||
|
||||
if (maxReqSize > BUFFER_SIZE)
|
||||
maxReqSize = BUFFER_SIZE;
|
||||
processedSizeLoc = __PHYSFS_platformRead(s->file, s->buffer, maxReqSize);
|
||||
processedSizeLoc = s->io->read(s->io, s->buffer, maxReqSize);
|
||||
*buffer = s->buffer;
|
||||
if (processedSize != NULL)
|
||||
*processedSize = (size_t) processedSizeLoc;
|
||||
|
@ -131,8 +131,8 @@ SZ_RESULT SzFileReadImp(void *object, void *buffer, size_t size,
|
|||
size_t *processedSize)
|
||||
{
|
||||
FileInputStream *s = (FileInputStream *)((unsigned long)object - offsetof(FileInputStream, inStream)); /* HACK! */
|
||||
size_t processedSizeLoc = __PHYSFS_platformRead(s->file, buffer, size);
|
||||
if (processedSize != 0)
|
||||
const size_t processedSizeLoc = s->io->read(s->io, buffer, size);
|
||||
if (processedSize != NULL)
|
||||
*processedSize = processedSizeLoc;
|
||||
return SZ_OK;
|
||||
} /* SzFileReadImp */
|
||||
|
@ -146,7 +146,7 @@ SZ_RESULT SzFileReadImp(void *object, void *buffer, size_t size,
|
|||
SZ_RESULT SzFileSeekImp(void *object, CFileSize pos)
|
||||
{
|
||||
FileInputStream *s = (FileInputStream *)((unsigned long)object - offsetof(FileInputStream, inStream)); /* HACK! */
|
||||
if (__PHYSFS_platformSeek(s->file, (PHYSFS_uint64) pos))
|
||||
if (s->io->seek(s->io, (PHYSFS_uint64) pos))
|
||||
return SZ_OK;
|
||||
return SZE_FAIL;
|
||||
} /* SzFileSeekImp */
|
||||
|
@ -322,12 +322,12 @@ static int lzma_err(SZ_RESULT rc)
|
|||
} /* lzma_err */
|
||||
|
||||
|
||||
static PHYSFS_sint64 LZMA_read(fvoid *opaque, void *outBuf, PHYSFS_uint64 len)
|
||||
static PHYSFS_sint64 LZMA_read(PHYSFS_Io *io, void *outBuf, PHYSFS_uint64 len)
|
||||
{
|
||||
LZMAfile *file = (LZMAfile *) opaque;
|
||||
LZMAfile *file = (LZMAfile *) io->opaque;
|
||||
|
||||
size_t wantedSize = (size_t) len;
|
||||
size_t remainingSize = file->item->Size - file->position;
|
||||
const size_t remainingSize = file->item->Size - file->position;
|
||||
size_t fileSize = 0;
|
||||
|
||||
BAIL_IF_MACRO(wantedSize == 0, NULL, 0); /* quick rejection. */
|
||||
|
@ -336,10 +336,10 @@ static PHYSFS_sint64 LZMA_read(fvoid *opaque, void *outBuf, PHYSFS_uint64 len)
|
|||
if (wantedSize > remainingSize)
|
||||
wantedSize = remainingSize;
|
||||
|
||||
/* Only decompress the folder if it is not allready cached */
|
||||
/* Only decompress the folder if it is not already cached */
|
||||
if (file->folder->cache == NULL)
|
||||
{
|
||||
int rc = lzma_err(SzExtract(
|
||||
const int rc = lzma_err(SzExtract(
|
||||
&file->archive->stream.inStream, /* compressed data */
|
||||
&file->archive->db, /* 7z's database, containing everything */
|
||||
file->index, /* Index into database arrays */
|
||||
|
@ -360,9 +360,7 @@ static PHYSFS_sint64 LZMA_read(fvoid *opaque, void *outBuf, PHYSFS_uint64 len)
|
|||
} /* if */
|
||||
|
||||
/* Copy wanted bytes over from cache to outBuf */
|
||||
memcpy(outBuf,
|
||||
(file->folder->cache +
|
||||
file->offset + file->position),
|
||||
memcpy(outBuf, (file->folder->cache + file->offset + file->position),
|
||||
wantedSize);
|
||||
file->position += wantedSize; /* Increase virtual position */
|
||||
|
||||
|
@ -370,31 +368,23 @@ static PHYSFS_sint64 LZMA_read(fvoid *opaque, void *outBuf, PHYSFS_uint64 len)
|
|||
} /* LZMA_read */
|
||||
|
||||
|
||||
static PHYSFS_sint64 LZMA_write(fvoid *f, const void *buf, PHYSFS_uint64 len)
|
||||
static PHYSFS_sint64 LZMA_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
|
||||
{
|
||||
BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
|
||||
} /* LZMA_write */
|
||||
|
||||
|
||||
static int LZMA_eof(fvoid *opaque)
|
||||
static PHYSFS_sint64 LZMA_tell(PHYSFS_Io *io)
|
||||
{
|
||||
LZMAfile *file = (LZMAfile *) opaque;
|
||||
return (file->position >= file->item->Size);
|
||||
} /* LZMA_eof */
|
||||
|
||||
|
||||
static PHYSFS_sint64 LZMA_tell(fvoid *opaque)
|
||||
{
|
||||
LZMAfile *file = (LZMAfile *) opaque;
|
||||
return (file->position);
|
||||
LZMAfile *file = (LZMAfile *) io->opaque;
|
||||
return file->position;
|
||||
} /* LZMA_tell */
|
||||
|
||||
|
||||
static int LZMA_seek(fvoid *opaque, PHYSFS_uint64 offset)
|
||||
static int LZMA_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
|
||||
{
|
||||
LZMAfile *file = (LZMAfile *) opaque;
|
||||
LZMAfile *file = (LZMAfile *) io->opaque;
|
||||
|
||||
BAIL_IF_MACRO(offset < 0, ERR_SEEK_OUT_OF_RANGE, 0);
|
||||
BAIL_IF_MACRO(offset > file->item->Size, ERR_PAST_EOF, 0);
|
||||
|
||||
file->position = offset; /* We only use a virtual position... */
|
||||
|
@ -403,75 +393,78 @@ static int LZMA_seek(fvoid *opaque, PHYSFS_uint64 offset)
|
|||
} /* LZMA_seek */
|
||||
|
||||
|
||||
static PHYSFS_sint64 LZMA_fileLength(fvoid *opaque)
|
||||
static PHYSFS_sint64 LZMA_length(PHYSFS_Io *io)
|
||||
{
|
||||
LZMAfile *file = (LZMAfile *) opaque;
|
||||
const LZMAfile *file = (LZMAfile *) io->opaque;
|
||||
return (file->item->Size);
|
||||
} /* LZMA_fileLength */
|
||||
} /* LZMA_length */
|
||||
|
||||
|
||||
static int LZMA_fileClose(fvoid *opaque)
|
||||
static PHYSFS_Io *LZMA_duplicate(PHYSFS_Io *_io)
|
||||
{
|
||||
LZMAfile *file = (LZMAfile *) opaque;
|
||||
/* !!! FIXME: this archiver needs to be reworked to allow multiple
|
||||
* !!! FIXME: opens before we worry about duplication. */
|
||||
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
|
||||
} /* LZMA_duplicate */
|
||||
|
||||
BAIL_IF_MACRO(file->folder == NULL, ERR_NOT_A_FILE, 0);
|
||||
|
||||
/* Only decrease refcount if someone actually requested this file... Prevents from overflows and close-on-open... */
|
||||
if (file->folder->references > 0)
|
||||
file->folder->references--;
|
||||
if (file->folder->references == 0)
|
||||
static int LZMA_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
|
||||
|
||||
|
||||
static void LZMA_destroy(PHYSFS_Io *io)
|
||||
{
|
||||
LZMAfile *file = (LZMAfile *) io->opaque;
|
||||
|
||||
if (file->folder != NULL)
|
||||
{
|
||||
/* Free the cache which might have been allocated by LZMA_read() */
|
||||
allocator.Free(file->folder->cache);
|
||||
file->folder->cache = NULL;
|
||||
}
|
||||
|
||||
return 1;
|
||||
} /* LZMA_fileClose */
|
||||
/* Only decrease refcount if someone actually requested this file... Prevents from overflows and close-on-open... */
|
||||
if (file->folder->references > 0)
|
||||
file->folder->references--;
|
||||
if (file->folder->references == 0)
|
||||
{
|
||||
/* Free the cache which might have been allocated by LZMA_read() */
|
||||
allocator.Free(file->folder->cache);
|
||||
file->folder->cache = NULL;
|
||||
}
|
||||
/* !!! FIXME: we don't free (file) or (file->folder)?! */
|
||||
} /* if */
|
||||
} /* LZMA_destroy */
|
||||
|
||||
|
||||
/* !!! FIXME: don't open/close file here, merge with openArchive(). */
|
||||
static int isLzma(const char *filename)
|
||||
static const PHYSFS_Io LZMA_Io =
|
||||
{
|
||||
LZMA_read,
|
||||
LZMA_write,
|
||||
LZMA_seek,
|
||||
LZMA_tell,
|
||||
LZMA_length,
|
||||
LZMA_duplicate,
|
||||
LZMA_flush,
|
||||
LZMA_destroy,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
static void *LZMA_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
|
||||
{
|
||||
PHYSFS_uint8 sig[k7zSignatureSize];
|
||||
void *in;
|
||||
|
||||
in = __PHYSFS_platformOpenRead(filename);
|
||||
BAIL_IF_MACRO(in == NULL, NULL, 0);
|
||||
|
||||
/* Read signature bytes */
|
||||
if (__PHYSFS_platformRead(in, sig, k7zSignatureSize) != k7zSignatureSize)
|
||||
{
|
||||
__PHYSFS_platformClose(in); /* Don't forget to close the file before returning... */
|
||||
BAIL_MACRO(NULL, 0);
|
||||
}
|
||||
|
||||
__PHYSFS_platformClose(in);
|
||||
|
||||
/* Test whether sig is the 7z signature */
|
||||
return TestSignatureCandidate(sig);
|
||||
} /* isLzma */
|
||||
|
||||
|
||||
static void *LZMA_openArchive(const char *name, int forWriting)
|
||||
{
|
||||
size_t len = 0;
|
||||
LZMAarchive *archive = NULL;
|
||||
|
||||
assert(io != NULL); /* shouldn't ever happen. */
|
||||
|
||||
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, NULL);
|
||||
BAIL_IF_MACRO(!isLzma(name), ERR_UNSUPPORTED_ARCHIVE, NULL);
|
||||
|
||||
if (io->read(io, sig, k7zSignatureSize) != k7zSignatureSize)
|
||||
BAIL_MACRO(NULL, 0);
|
||||
BAIL_IF_MACRO(!TestSignatureCandidate(sig), ERR_NOT_AN_ARCHIVE, NULL);
|
||||
BAIL_IF_MACRO(!io->seek(io, 0), NULL, NULL);
|
||||
|
||||
archive = (LZMAarchive *) allocator.Malloc(sizeof (LZMAarchive));
|
||||
BAIL_IF_MACRO(archive == NULL, ERR_OUT_OF_MEMORY, NULL);
|
||||
|
||||
lzma_archive_init(archive);
|
||||
|
||||
if ( (archive->stream.file = __PHYSFS_platformOpenRead(name)) == NULL )
|
||||
{
|
||||
__PHYSFS_platformClose(archive->stream.file);
|
||||
lzma_archive_exit(archive);
|
||||
return NULL; /* Error is set by platformOpenRead! */
|
||||
}
|
||||
archive->stream.io = io;
|
||||
|
||||
CrcGenerateTable();
|
||||
SzArDbExInit(&archive->db);
|
||||
|
@ -481,7 +474,6 @@ static void *LZMA_openArchive(const char *name, int forWriting)
|
|||
&archive->stream.allocTempImp)) != SZ_OK)
|
||||
{
|
||||
SzArDbExFree(&archive->db, SzFreePhysicsFS);
|
||||
__PHYSFS_platformClose(archive->stream.file);
|
||||
lzma_archive_exit(archive);
|
||||
return NULL; /* Error is set by lzma_err! */
|
||||
} /* if */
|
||||
|
@ -491,7 +483,6 @@ static void *LZMA_openArchive(const char *name, int forWriting)
|
|||
if (archive->files == NULL)
|
||||
{
|
||||
SzArDbExFree(&archive->db, SzFreePhysicsFS);
|
||||
__PHYSFS_platformClose(archive->stream.file);
|
||||
lzma_archive_exit(archive);
|
||||
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
|
||||
}
|
||||
|
@ -507,7 +498,6 @@ static void *LZMA_openArchive(const char *name, int forWriting)
|
|||
if (archive->folders == NULL)
|
||||
{
|
||||
SzArDbExFree(&archive->db, SzFreePhysicsFS);
|
||||
__PHYSFS_platformClose(archive->stream.file);
|
||||
lzma_archive_exit(archive);
|
||||
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
|
||||
}
|
||||
|
@ -521,7 +511,6 @@ static void *LZMA_openArchive(const char *name, int forWriting)
|
|||
if(!lzma_files_init(archive))
|
||||
{
|
||||
SzArDbExFree(&archive->db, SzFreePhysicsFS);
|
||||
__PHYSFS_platformClose(archive->stream.file);
|
||||
lzma_archive_exit(archive);
|
||||
BAIL_MACRO(ERR_UNKNOWN_ERROR, NULL);
|
||||
}
|
||||
|
@ -616,10 +605,11 @@ static int LZMA_isSymLink(dvoid *opaque, const char *name, int *fileExists)
|
|||
} /* LZMA_isSymLink */
|
||||
|
||||
|
||||
static fvoid *LZMA_openRead(dvoid *opaque, const char *name, int *fileExists)
|
||||
static PHYSFS_Io *LZMA_openRead(dvoid *opaque, const char *name, int *fileExists)
|
||||
{
|
||||
LZMAarchive *archive = (LZMAarchive *) opaque;
|
||||
LZMAfile *file = lzma_find_file(archive, name);
|
||||
PHYSFS_Io *io = NULL;
|
||||
|
||||
*fileExists = (file != NULL);
|
||||
BAIL_IF_MACRO(file == NULL, ERR_NO_SUCH_FILE, NULL);
|
||||
|
@ -628,17 +618,22 @@ static fvoid *LZMA_openRead(dvoid *opaque, const char *name, int *fileExists)
|
|||
file->position = 0;
|
||||
file->folder->references++; /* Increase refcount for automatic cleanup... */
|
||||
|
||||
return file;
|
||||
io = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
|
||||
BAIL_IF_MACRO(io == NULL, ERR_OUT_OF_MEMORY, NULL);
|
||||
memcpy(io, &LZMA_Io, sizeof (*io));
|
||||
io->opaque = file;
|
||||
|
||||
return io;
|
||||
} /* LZMA_openRead */
|
||||
|
||||
|
||||
static fvoid *LZMA_openWrite(dvoid *opaque, const char *filename)
|
||||
static PHYSFS_Io *LZMA_openWrite(dvoid *opaque, const char *filename)
|
||||
{
|
||||
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
|
||||
} /* LZMA_openWrite */
|
||||
|
||||
|
||||
static fvoid *LZMA_openAppend(dvoid *opaque, const char *filename)
|
||||
static PHYSFS_Io *LZMA_openAppend(dvoid *opaque, const char *filename)
|
||||
{
|
||||
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
|
||||
} /* LZMA_openAppend */
|
||||
|
@ -647,15 +642,17 @@ static fvoid *LZMA_openAppend(dvoid *opaque, const char *filename)
|
|||
static void LZMA_dirClose(dvoid *opaque)
|
||||
{
|
||||
LZMAarchive *archive = (LZMAarchive *) opaque;
|
||||
PHYSFS_uint32 fileIndex = 0, numFiles = archive->db.Database.NumFiles;
|
||||
|
||||
#if 0 /* !!! FIXME: you shouldn't have to do this. */
|
||||
PHYSFS_uint32 fileIndex = 0, numFiles = archive->db.Database.NumFiles;
|
||||
for (fileIndex = 0; fileIndex < numFiles; fileIndex++)
|
||||
{
|
||||
LZMA_fileClose(&archive->files[fileIndex]);
|
||||
} /* for */
|
||||
#endif
|
||||
|
||||
SzArDbExFree(&archive->db, SzFreePhysicsFS);
|
||||
__PHYSFS_platformClose(archive->stream.file);
|
||||
archive->stream.io->destroy(archive->stream.io);
|
||||
lzma_archive_exit(archive);
|
||||
} /* LZMA_dirClose */
|
||||
|
||||
|
@ -731,14 +728,7 @@ const PHYSFS_Archiver __PHYSFS_Archiver_LZMA =
|
|||
LZMA_remove, /* remove() method */
|
||||
LZMA_mkdir, /* mkdir() method */
|
||||
LZMA_dirClose, /* dirClose() method */
|
||||
LZMA_stat, /* stat() method */
|
||||
LZMA_read, /* read() method */
|
||||
LZMA_write, /* write() method */
|
||||
LZMA_eof, /* eof() method */
|
||||
LZMA_tell, /* tell() method */
|
||||
LZMA_seek, /* seek() method */
|
||||
LZMA_fileLength, /* fileLength() method */
|
||||
LZMA_fileClose /* fileClose() method */
|
||||
LZMA_stat /* stat() method */
|
||||
};
|
||||
|
||||
#endif /* defined PHYSFS_SUPPORTS_7Z */
|
||||
|
|
|
@ -46,31 +46,37 @@ typedef struct
|
|||
|
||||
typedef struct
|
||||
{
|
||||
char *filename;
|
||||
PHYSFS_Io *io;
|
||||
PHYSFS_uint32 entryCount;
|
||||
MVLentry *entries;
|
||||
} MVLinfo;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void *handle;
|
||||
PHYSFS_Io *io;
|
||||
MVLentry *entry;
|
||||
PHYSFS_uint32 curPos;
|
||||
} MVLfileinfo;
|
||||
|
||||
|
||||
static inline int readAll(PHYSFS_Io *io, void *buf, const PHYSFS_uint64 len)
|
||||
{
|
||||
return (io->read(io, buf, len) == len);
|
||||
} /* readAll */
|
||||
|
||||
|
||||
static void MVL_dirClose(dvoid *opaque)
|
||||
{
|
||||
MVLinfo *info = ((MVLinfo *) opaque);
|
||||
allocator.Free(info->filename);
|
||||
info->io->destroy(info->io);
|
||||
allocator.Free(info->entries);
|
||||
allocator.Free(info);
|
||||
} /* MVL_dirClose */
|
||||
|
||||
|
||||
static PHYSFS_sint64 MVL_read(fvoid *opaque, void *buffer, PHYSFS_uint64 len)
|
||||
static PHYSFS_sint64 MVL_read(PHYSFS_Io *io, void *buffer, PHYSFS_uint64 len)
|
||||
{
|
||||
MVLfileinfo *finfo = (MVLfileinfo *) opaque;
|
||||
MVLfileinfo *finfo = (MVLfileinfo *) io->opaque;
|
||||
const MVLentry *entry = finfo->entry;
|
||||
const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos);
|
||||
PHYSFS_sint64 rc;
|
||||
|
@ -78,7 +84,7 @@ static PHYSFS_sint64 MVL_read(fvoid *opaque, void *buffer, PHYSFS_uint64 len)
|
|||
if (bytesLeft < len)
|
||||
len = bytesLeft;
|
||||
|
||||
rc = __PHYSFS_platformRead(finfo->handle, buffer, len);
|
||||
rc = finfo->io->read(finfo->io, buffer, len);
|
||||
if (rc > 0)
|
||||
finfo->curPos += (PHYSFS_uint32) rc;
|
||||
|
||||
|
@ -86,35 +92,26 @@ static PHYSFS_sint64 MVL_read(fvoid *opaque, void *buffer, PHYSFS_uint64 len)
|
|||
} /* MVL_read */
|
||||
|
||||
|
||||
static PHYSFS_sint64 MVL_write(fvoid *f, const void *buf, PHYSFS_uint64 len)
|
||||
static PHYSFS_sint64 MVL_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
|
||||
{
|
||||
BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
|
||||
} /* MVL_write */
|
||||
|
||||
|
||||
static int MVL_eof(fvoid *opaque)
|
||||
static PHYSFS_sint64 MVL_tell(PHYSFS_Io *io)
|
||||
{
|
||||
MVLfileinfo *finfo = (MVLfileinfo *) opaque;
|
||||
MVLentry *entry = finfo->entry;
|
||||
return (finfo->curPos >= entry->size);
|
||||
} /* MVL_eof */
|
||||
|
||||
|
||||
static PHYSFS_sint64 MVL_tell(fvoid *opaque)
|
||||
{
|
||||
return ((MVLfileinfo *) opaque)->curPos;
|
||||
return ((MVLfileinfo *) io->opaque)->curPos;
|
||||
} /* MVL_tell */
|
||||
|
||||
|
||||
static int MVL_seek(fvoid *opaque, PHYSFS_uint64 offset)
|
||||
static int MVL_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
|
||||
{
|
||||
MVLfileinfo *finfo = (MVLfileinfo *) opaque;
|
||||
MVLentry *entry = finfo->entry;
|
||||
MVLfileinfo *finfo = (MVLfileinfo *) io->opaque;
|
||||
const MVLentry *entry = finfo->entry;
|
||||
int rc;
|
||||
|
||||
BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
|
||||
BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
|
||||
rc = __PHYSFS_platformSeek(finfo->handle, entry->startPos + offset);
|
||||
rc = finfo->io->seek(finfo->io, entry->startPos + offset);
|
||||
if (rc)
|
||||
finfo->curPos = (PHYSFS_uint32) offset;
|
||||
|
||||
|
@ -122,72 +119,76 @@ static int MVL_seek(fvoid *opaque, PHYSFS_uint64 offset)
|
|||
} /* MVL_seek */
|
||||
|
||||
|
||||
static PHYSFS_sint64 MVL_fileLength(fvoid *opaque)
|
||||
static PHYSFS_sint64 MVL_length(PHYSFS_Io *io)
|
||||
{
|
||||
MVLfileinfo *finfo = (MVLfileinfo *) opaque;
|
||||
const MVLfileinfo *finfo = (MVLfileinfo *) io->opaque;
|
||||
return ((PHYSFS_sint64) finfo->entry->size);
|
||||
} /* MVL_fileLength */
|
||||
} /* MVL_length */
|
||||
|
||||
|
||||
static int MVL_fileClose(fvoid *opaque)
|
||||
static PHYSFS_Io *MVL_duplicate(PHYSFS_Io *_io)
|
||||
{
|
||||
MVLfileinfo *finfo = (MVLfileinfo *) opaque;
|
||||
BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0);
|
||||
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);
|
||||
return 1;
|
||||
} /* MVL_fileClose */
|
||||
allocator.Free(io);
|
||||
} /* MVL_destroy */
|
||||
|
||||
|
||||
static int mvl_open(const char *filename, int forWriting,
|
||||
void **fh, PHYSFS_uint32 *count)
|
||||
static const PHYSFS_Io MVL_Io =
|
||||
{
|
||||
PHYSFS_uint8 buf[4];
|
||||
|
||||
*fh = NULL;
|
||||
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
|
||||
|
||||
*fh = __PHYSFS_platformOpenRead(filename);
|
||||
BAIL_IF_MACRO(*fh == NULL, NULL, 0);
|
||||
|
||||
if (__PHYSFS_platformRead(*fh, buf, 4) != 4)
|
||||
goto openMvl_failed;
|
||||
|
||||
if (memcmp(buf, "DMVL", 4) != 0)
|
||||
{
|
||||
__PHYSFS_setError(ERR_UNSUPPORTED_ARCHIVE);
|
||||
goto openMvl_failed;
|
||||
} /* if */
|
||||
|
||||
if (__PHYSFS_platformRead(*fh, count, 4) != 4)
|
||||
goto openMvl_failed;
|
||||
|
||||
*count = PHYSFS_swapULE32(*count);
|
||||
|
||||
return 1;
|
||||
|
||||
openMvl_failed:
|
||||
if (*fh != NULL)
|
||||
__PHYSFS_platformClose(*fh);
|
||||
|
||||
*count = -1;
|
||||
*fh = NULL;
|
||||
return 0;
|
||||
} /* mvl_open */
|
||||
MVL_read,
|
||||
MVL_write,
|
||||
MVL_seek,
|
||||
MVL_tell,
|
||||
MVL_length,
|
||||
MVL_duplicate,
|
||||
MVL_flush,
|
||||
MVL_destroy,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
static int mvl_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
|
||||
static int mvlEntryCmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
|
||||
{
|
||||
if (one != two)
|
||||
{
|
||||
const MVLentry *a = (const MVLentry *) _a;
|
||||
return strcmp(a[one].name, a[two].name);
|
||||
return __PHYSFS_stricmpASCII(a[one].name, a[two].name);
|
||||
} /* if */
|
||||
|
||||
return 0;
|
||||
} /* mvl_entry_cmp */
|
||||
} /* mvlEntryCmp */
|
||||
|
||||
|
||||
static void mvl_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
|
||||
static void mvlEntrySwap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
|
||||
{
|
||||
if (one != two)
|
||||
{
|
||||
|
@ -198,74 +199,63 @@ static void mvl_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
|
|||
memcpy(first, second, sizeof (MVLentry));
|
||||
memcpy(second, &tmp, sizeof (MVLentry));
|
||||
} /* if */
|
||||
} /* mvl_entry_swap */
|
||||
} /* mvlEntrySwap */
|
||||
|
||||
|
||||
static int mvl_load_entries(const char *name, int forWriting, MVLinfo *info)
|
||||
static int mvl_load_entries(PHYSFS_Io *io, MVLinfo *info)
|
||||
{
|
||||
void *fh = NULL;
|
||||
PHYSFS_uint32 fileCount;
|
||||
PHYSFS_uint32 fileCount = info->entryCount;
|
||||
PHYSFS_uint32 location = 8; /* sizeof sig. */
|
||||
MVLentry *entry;
|
||||
|
||||
BAIL_IF_MACRO(!mvl_open(name, forWriting, &fh, &fileCount), NULL, 0);
|
||||
info->entryCount = fileCount;
|
||||
info->entries = (MVLentry *) allocator.Malloc(sizeof(MVLentry)*fileCount);
|
||||
if (info->entries == NULL)
|
||||
{
|
||||
__PHYSFS_platformClose(fh);
|
||||
BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
|
||||
} /* if */
|
||||
BAIL_IF_MACRO(info->entries == NULL, ERR_OUT_OF_MEMORY, 0);
|
||||
|
||||
location += (17 * fileCount);
|
||||
|
||||
for (entry = info->entries; fileCount > 0; fileCount--, entry++)
|
||||
{
|
||||
if (__PHYSFS_platformRead(fh, &entry->name, 13) != 13)
|
||||
{
|
||||
__PHYSFS_platformClose(fh);
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
if (__PHYSFS_platformRead(fh, &entry->size, 4) != 4)
|
||||
{
|
||||
__PHYSFS_platformClose(fh);
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
BAIL_IF_MACRO(!readAll(io, &entry->name, 13), NULL, 0);
|
||||
BAIL_IF_MACRO(!readAll(io, &entry->size, 4), NULL, 0);
|
||||
entry->size = PHYSFS_swapULE32(entry->size);
|
||||
entry->startPos = location;
|
||||
location += entry->size;
|
||||
} /* for */
|
||||
|
||||
__PHYSFS_platformClose(fh);
|
||||
|
||||
__PHYSFS_sort(info->entries, info->entryCount,
|
||||
mvl_entry_cmp, mvl_entry_swap);
|
||||
__PHYSFS_sort(info->entries, info->entryCount, mvlEntryCmp, mvlEntrySwap);
|
||||
return 1;
|
||||
} /* mvl_load_entries */
|
||||
|
||||
|
||||
static void *MVL_openArchive(const char *name, int forWriting)
|
||||
static void *MVL_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
|
||||
{
|
||||
MVLinfo *info = (MVLinfo *) allocator.Malloc(sizeof (MVLinfo));
|
||||
PHYSFS_uint8 buf[4];
|
||||
MVLinfo *info = NULL;
|
||||
PHYSFS_uint32 val = 0;
|
||||
|
||||
BAIL_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, 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);
|
||||
|
||||
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;
|
||||
|
||||
info->filename = (char *) allocator.Malloc(strlen(name) + 1);
|
||||
GOTO_IF_MACRO(!info->filename, ERR_OUT_OF_MEMORY, MVL_openArchive_failed);
|
||||
if (!mvl_load_entries(name, forWriting, info))
|
||||
goto MVL_openArchive_failed;
|
||||
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);
|
||||
|
||||
strcpy(info->filename, name);
|
||||
return info;
|
||||
|
||||
MVL_openArchive_failed:
|
||||
if (info != NULL)
|
||||
{
|
||||
if (info->filename != NULL)
|
||||
allocator.Free(info->filename);
|
||||
if (info->entries != NULL)
|
||||
allocator.Free(info->entries);
|
||||
allocator.Free(info);
|
||||
|
@ -346,40 +336,58 @@ static int MVL_isSymLink(dvoid *opaque, const char *name, int *fileExists)
|
|||
} /* MVL_isSymLink */
|
||||
|
||||
|
||||
static fvoid *MVL_openRead(dvoid *opaque, const char *fnm, int *fileExists)
|
||||
static PHYSFS_Io *MVL_openRead(dvoid *opaque, const char *fnm, int *fileExists)
|
||||
{
|
||||
MVLinfo *info = ((MVLinfo *) opaque);
|
||||
PHYSFS_Io *retval = NULL;
|
||||
MVLinfo *info = (MVLinfo *) opaque;
|
||||
MVLfileinfo *finfo;
|
||||
MVLentry *entry;
|
||||
|
||||
entry = mvl_find_entry(info, fnm);
|
||||
*fileExists = (entry != NULL);
|
||||
BAIL_IF_MACRO(entry == NULL, NULL, 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));
|
||||
BAIL_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, NULL);
|
||||
GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, MVL_openRead_failed);
|
||||
|
||||
finfo->handle = __PHYSFS_platformOpenRead(info->filename);
|
||||
if ( (finfo->handle == NULL) ||
|
||||
(!__PHYSFS_platformSeek(finfo->handle, entry->startPos)) )
|
||||
{
|
||||
allocator.Free(finfo);
|
||||
return NULL;
|
||||
} /* if */
|
||||
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;
|
||||
return finfo;
|
||||
|
||||
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 fvoid *MVL_openWrite(dvoid *opaque, const char *name)
|
||||
static PHYSFS_Io *MVL_openWrite(dvoid *opaque, const char *name)
|
||||
{
|
||||
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
|
||||
} /* MVL_openWrite */
|
||||
|
||||
|
||||
static fvoid *MVL_openAppend(dvoid *opaque, const char *name)
|
||||
static PHYSFS_Io *MVL_openAppend(dvoid *opaque, const char *name)
|
||||
{
|
||||
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
|
||||
} /* MVL_openAppend */
|
||||
|
@ -441,14 +449,7 @@ const PHYSFS_Archiver __PHYSFS_Archiver_MVL =
|
|||
MVL_remove, /* remove() method */
|
||||
MVL_mkdir, /* mkdir() method */
|
||||
MVL_dirClose, /* dirClose() method */
|
||||
MVL_stat, /* stat() method */
|
||||
MVL_read, /* read() method */
|
||||
MVL_write, /* write() method */
|
||||
MVL_eof, /* eof() method */
|
||||
MVL_tell, /* tell() method */
|
||||
MVL_seek, /* seek() method */
|
||||
MVL_fileLength, /* fileLength() method */
|
||||
MVL_fileClose /* fileClose() method */
|
||||
MVL_stat /* stat() method */
|
||||
};
|
||||
|
||||
#endif /* defined PHYSFS_SUPPORTS_MVL */
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#define __PHYSICSFS_INTERNAL__
|
||||
#include "physfs_internal.h"
|
||||
|
||||
/* !!! FIXME: what is this here for? */
|
||||
#if 1 /* Make this case insensitive? */
|
||||
#define QPAK_strcmp(x, y) __PHYSFS_stricmpASCII(x, y)
|
||||
#define QPAK_strncmp(x, y, z) __PHYSFS_strnicmpASCII(x, y, z)
|
||||
|
@ -57,14 +58,14 @@ typedef struct
|
|||
|
||||
typedef struct
|
||||
{
|
||||
char *filename;
|
||||
PHYSFS_Io *io;
|
||||
PHYSFS_uint32 entryCount;
|
||||
QPAKentry *entries;
|
||||
} QPAKinfo;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void *handle;
|
||||
PHYSFS_Io *io;
|
||||
QPAKentry *entry;
|
||||
PHYSFS_uint32 curPos;
|
||||
} QPAKfileinfo;
|
||||
|
@ -73,18 +74,24 @@ typedef struct
|
|||
#define QPAK_SIG 0x4b434150 /* "PACK" in ASCII. */
|
||||
|
||||
|
||||
static inline int readAll(PHYSFS_Io *io, void *buf, const PHYSFS_uint64 len)
|
||||
{
|
||||
return (io->read(io, buf, len) == len);
|
||||
} /* readAll */
|
||||
|
||||
|
||||
static void QPAK_dirClose(dvoid *opaque)
|
||||
{
|
||||
QPAKinfo *info = ((QPAKinfo *) opaque);
|
||||
allocator.Free(info->filename);
|
||||
info->io->destroy(info->io);
|
||||
allocator.Free(info->entries);
|
||||
allocator.Free(info);
|
||||
} /* QPAK_dirClose */
|
||||
|
||||
|
||||
static PHYSFS_sint64 QPAK_read(fvoid *opaque, void *buffer, PHYSFS_uint64 len)
|
||||
static PHYSFS_sint64 QPAK_read(PHYSFS_Io *io, void *buffer, PHYSFS_uint64 len)
|
||||
{
|
||||
QPAKfileinfo *finfo = (QPAKfileinfo *) opaque;
|
||||
QPAKfileinfo *finfo = (QPAKfileinfo *) io->opaque;
|
||||
const QPAKentry *entry = finfo->entry;
|
||||
const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos);
|
||||
PHYSFS_sint64 rc;
|
||||
|
@ -92,7 +99,7 @@ static PHYSFS_sint64 QPAK_read(fvoid *opaque, void *buffer, PHYSFS_uint64 len)
|
|||
if (bytesLeft < len)
|
||||
len = bytesLeft;
|
||||
|
||||
rc = __PHYSFS_platformRead(finfo->handle, buffer, len);
|
||||
rc = finfo->io->read(finfo->io, buffer, len);
|
||||
if (rc > 0)
|
||||
finfo->curPos += (PHYSFS_uint32) rc;
|
||||
|
||||
|
@ -100,35 +107,26 @@ static PHYSFS_sint64 QPAK_read(fvoid *opaque, void *buffer, PHYSFS_uint64 len)
|
|||
} /* QPAK_read */
|
||||
|
||||
|
||||
static PHYSFS_sint64 QPAK_write(fvoid *f, const void *buf, PHYSFS_uint64 len)
|
||||
static PHYSFS_sint64 QPAK_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
|
||||
{
|
||||
BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
|
||||
} /* QPAK_write */
|
||||
|
||||
|
||||
static int QPAK_eof(fvoid *opaque)
|
||||
static PHYSFS_sint64 QPAK_tell(PHYSFS_Io *io)
|
||||
{
|
||||
QPAKfileinfo *finfo = (QPAKfileinfo *) opaque;
|
||||
QPAKentry *entry = finfo->entry;
|
||||
return (finfo->curPos >= entry->size);
|
||||
} /* QPAK_eof */
|
||||
|
||||
|
||||
static PHYSFS_sint64 QPAK_tell(fvoid *opaque)
|
||||
{
|
||||
return ((QPAKfileinfo *) opaque)->curPos;
|
||||
return ((QPAKfileinfo *) io->opaque)->curPos;
|
||||
} /* QPAK_tell */
|
||||
|
||||
|
||||
static int QPAK_seek(fvoid *opaque, PHYSFS_uint64 offset)
|
||||
static int QPAK_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
|
||||
{
|
||||
QPAKfileinfo *finfo = (QPAKfileinfo *) opaque;
|
||||
QPAKentry *entry = finfo->entry;
|
||||
QPAKfileinfo *finfo = (QPAKfileinfo *) io->opaque;
|
||||
const QPAKentry *entry = finfo->entry;
|
||||
int rc;
|
||||
|
||||
BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
|
||||
BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
|
||||
rc = __PHYSFS_platformSeek(finfo->handle, entry->startPos + offset);
|
||||
rc = finfo->io->seek(finfo->io, entry->startPos + offset);
|
||||
if (rc)
|
||||
finfo->curPos = (PHYSFS_uint32) offset;
|
||||
|
||||
|
@ -136,74 +134,66 @@ static int QPAK_seek(fvoid *opaque, PHYSFS_uint64 offset)
|
|||
} /* QPAK_seek */
|
||||
|
||||
|
||||
static PHYSFS_sint64 QPAK_fileLength(fvoid *opaque)
|
||||
static PHYSFS_sint64 QPAK_length(PHYSFS_Io *io)
|
||||
{
|
||||
QPAKfileinfo *finfo = (QPAKfileinfo *) opaque;
|
||||
const QPAKfileinfo *finfo = (QPAKfileinfo *) io->opaque;
|
||||
return ((PHYSFS_sint64) finfo->entry->size);
|
||||
} /* QPAK_fileLength */
|
||||
} /* QPAK_length */
|
||||
|
||||
|
||||
static int QPAK_fileClose(fvoid *opaque)
|
||||
static PHYSFS_Io *QPAK_duplicate(PHYSFS_Io *_io)
|
||||
{
|
||||
QPAKfileinfo *finfo = (QPAKfileinfo *) opaque;
|
||||
BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0);
|
||||
QPAKfileinfo *origfinfo = (QPAKfileinfo *) _io->opaque;
|
||||
PHYSFS_Io *io = NULL;
|
||||
PHYSFS_Io *retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
|
||||
QPAKfileinfo *finfo = (QPAKfileinfo *) allocator.Malloc(sizeof (QPAKfileinfo));
|
||||
GOTO_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, QPAK_duplicate_failed);
|
||||
GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, QPAK_duplicate_failed);
|
||||
|
||||
io = origfinfo->io->duplicate(origfinfo->io);
|
||||
GOTO_IF_MACRO(io == NULL, NULL, QPAK_duplicate_failed);
|
||||
finfo->io = io;
|
||||
finfo->entry = origfinfo->entry;
|
||||
finfo->curPos = 0;
|
||||
memcpy(retval, _io, sizeof (PHYSFS_Io));
|
||||
retval->opaque = finfo;
|
||||
return retval;
|
||||
|
||||
QPAK_duplicate_failed:
|
||||
if (finfo != NULL) allocator.Free(finfo);
|
||||
if (retval != NULL) allocator.Free(retval);
|
||||
if (io != NULL) io->destroy(io);
|
||||
return NULL;
|
||||
} /* QPAK_duplicate */
|
||||
|
||||
static int QPAK_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
|
||||
|
||||
|
||||
static void QPAK_destroy(PHYSFS_Io *io)
|
||||
{
|
||||
QPAKfileinfo *finfo = (QPAKfileinfo *) io->opaque;
|
||||
finfo->io->destroy(finfo->io);
|
||||
allocator.Free(finfo);
|
||||
return 1;
|
||||
} /* QPAK_fileClose */
|
||||
allocator.Free(io);
|
||||
} /* QPAK_destroy */
|
||||
|
||||
|
||||
static inline int readAll(void *fh, void *buf, const PHYSFS_uint64 len)
|
||||
static const PHYSFS_Io QPAK_Io =
|
||||
{
|
||||
return (__PHYSFS_platformRead(fh, buf, len) == len);
|
||||
} /* readAll */
|
||||
|
||||
static int qpak_open(const char *filename, int forWriting,
|
||||
void **fh, PHYSFS_uint32 *count)
|
||||
{
|
||||
PHYSFS_uint32 buf;
|
||||
|
||||
*fh = NULL;
|
||||
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
|
||||
|
||||
*fh = __PHYSFS_platformOpenRead(filename);
|
||||
BAIL_IF_MACRO(*fh == NULL, NULL, 0);
|
||||
|
||||
if (!readAll(*fh, &buf, sizeof (PHYSFS_uint32)))
|
||||
goto openQpak_failed;
|
||||
|
||||
buf = PHYSFS_swapULE32(buf);
|
||||
GOTO_IF_MACRO(buf != QPAK_SIG, ERR_UNSUPPORTED_ARCHIVE, openQpak_failed);
|
||||
|
||||
if (!readAll(*fh, &buf, sizeof (PHYSFS_uint32)))
|
||||
goto openQpak_failed;
|
||||
|
||||
buf = PHYSFS_swapULE32(buf); /* directory table offset. */
|
||||
|
||||
if (!readAll(*fh, count, sizeof (PHYSFS_uint32)))
|
||||
goto openQpak_failed;
|
||||
|
||||
*count = PHYSFS_swapULE32(*count);
|
||||
|
||||
/* corrupted archive? */
|
||||
GOTO_IF_MACRO((*count % 64) != 0, ERR_CORRUPTED, openQpak_failed);
|
||||
|
||||
if (!__PHYSFS_platformSeek(*fh, buf))
|
||||
goto openQpak_failed;
|
||||
|
||||
*count /= 64;
|
||||
return 1;
|
||||
|
||||
openQpak_failed:
|
||||
if (*fh != NULL)
|
||||
__PHYSFS_platformClose(*fh);
|
||||
|
||||
*count = -1;
|
||||
*fh = NULL;
|
||||
return 0;
|
||||
} /* qpak_open */
|
||||
QPAK_read,
|
||||
QPAK_write,
|
||||
QPAK_seek,
|
||||
QPAK_tell,
|
||||
QPAK_length,
|
||||
QPAK_duplicate,
|
||||
QPAK_flush,
|
||||
QPAK_destroy,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
static int qpak_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
|
||||
|
||||
static int qpakEntryCmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
|
||||
{
|
||||
if (one != two)
|
||||
{
|
||||
|
@ -212,10 +202,10 @@ static int qpak_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
|
|||
} /* if */
|
||||
|
||||
return 0;
|
||||
} /* qpak_entry_cmp */
|
||||
} /* qpakEntryCmp */
|
||||
|
||||
|
||||
static void qpak_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
|
||||
static void qpakEntrySwap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
|
||||
{
|
||||
if (one != two)
|
||||
{
|
||||
|
@ -226,77 +216,73 @@ static void qpak_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
|
|||
memcpy(first, second, sizeof (QPAKentry));
|
||||
memcpy(second, &tmp, sizeof (QPAKentry));
|
||||
} /* if */
|
||||
} /* qpak_entry_swap */
|
||||
} /* qpakEntrySwap */
|
||||
|
||||
|
||||
static int qpak_load_entries(const char *name, int forWriting, QPAKinfo *info)
|
||||
static int qpak_load_entries(QPAKinfo *info)
|
||||
{
|
||||
void *fh = NULL;
|
||||
PHYSFS_uint32 fileCount;
|
||||
PHYSFS_Io *io = info->io;
|
||||
PHYSFS_uint32 fileCount = info->entryCount;
|
||||
QPAKentry *entry;
|
||||
|
||||
BAIL_IF_MACRO(!qpak_open(name, forWriting, &fh, &fileCount), NULL, 0);
|
||||
info->entryCount = fileCount;
|
||||
info->entries = (QPAKentry*) allocator.Malloc(sizeof(QPAKentry)*fileCount);
|
||||
if (info->entries == NULL)
|
||||
{
|
||||
__PHYSFS_platformClose(fh);
|
||||
BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
|
||||
} /* if */
|
||||
BAIL_IF_MACRO(info->entries == NULL, ERR_OUT_OF_MEMORY, 0);
|
||||
|
||||
for (entry = info->entries; fileCount > 0; fileCount--, entry++)
|
||||
{
|
||||
if ( (!readAll(fh, &entry->name, sizeof (entry->name))) ||
|
||||
(!readAll(fh, &entry->startPos, sizeof (entry->startPos))) ||
|
||||
(!readAll(fh, &entry->size, sizeof(entry->size))) )
|
||||
{
|
||||
__PHYSFS_platformClose(fh);
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
BAIL_IF_MACRO(!readAll(io, &entry->name, 56), NULL, 0);
|
||||
BAIL_IF_MACRO(!readAll(io, &entry->startPos, 4), NULL, 0);
|
||||
BAIL_IF_MACRO(!readAll(io, &entry->size, 4), NULL, 0);
|
||||
entry->size = PHYSFS_swapULE32(entry->size);
|
||||
entry->startPos = PHYSFS_swapULE32(entry->startPos);
|
||||
} /* for */
|
||||
|
||||
__PHYSFS_platformClose(fh);
|
||||
|
||||
__PHYSFS_sort(info->entries, info->entryCount,
|
||||
qpak_entry_cmp, qpak_entry_swap);
|
||||
__PHYSFS_sort(info->entries, info->entryCount, qpakEntryCmp, qpakEntrySwap);
|
||||
return 1;
|
||||
} /* qpak_load_entries */
|
||||
|
||||
|
||||
static void *QPAK_openArchive(const char *name, int forWriting)
|
||||
static void *QPAK_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
|
||||
{
|
||||
QPAKinfo *info = (QPAKinfo *) allocator.Malloc(sizeof (QPAKinfo));
|
||||
QPAKinfo *info = NULL;
|
||||
PHYSFS_uint32 val = 0;
|
||||
PHYSFS_uint32 pos = 0;
|
||||
PHYSFS_uint32 count = 0;
|
||||
|
||||
assert(io != NULL); /* shouldn't ever happen. */
|
||||
|
||||
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
|
||||
|
||||
BAIL_IF_MACRO(!readAll(io, &val, 4), NULL, NULL);
|
||||
BAIL_IF_MACRO(PHYSFS_swapULE32(val) != QPAK_SIG, ERR_NOT_AN_ARCHIVE, NULL);
|
||||
|
||||
BAIL_IF_MACRO(!readAll(io, &val, 4), NULL, NULL);
|
||||
pos = PHYSFS_swapULE32(val); /* directory table offset. */
|
||||
|
||||
BAIL_IF_MACRO(!readAll(io, &val, 4), NULL, NULL);
|
||||
count = PHYSFS_swapULE32(val);
|
||||
|
||||
/* corrupted archive? */
|
||||
BAIL_IF_MACRO((count % 64) != 0, ERR_CORRUPTED, NULL);
|
||||
count /= 64;
|
||||
|
||||
BAIL_IF_MACRO(io->seek(io, pos), NULL, NULL);
|
||||
|
||||
info = (QPAKinfo *) allocator.Malloc(sizeof (QPAKinfo));
|
||||
BAIL_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, NULL);
|
||||
memset(info, '\0', sizeof (QPAKinfo));
|
||||
info->io = io;
|
||||
info->entryCount = count;
|
||||
|
||||
info->filename = (char *) allocator.Malloc(strlen(name) + 1);
|
||||
if (info->filename == NULL)
|
||||
if (!qpak_load_entries(info))
|
||||
{
|
||||
__PHYSFS_setError(ERR_OUT_OF_MEMORY);
|
||||
goto QPAK_openArchive_failed;
|
||||
} /* if */
|
||||
|
||||
if (!qpak_load_entries(name, forWriting, info))
|
||||
goto QPAK_openArchive_failed;
|
||||
|
||||
strcpy(info->filename, name);
|
||||
return info;
|
||||
|
||||
QPAK_openArchive_failed:
|
||||
if (info != NULL)
|
||||
{
|
||||
if (info->filename != NULL)
|
||||
allocator.Free(info->filename);
|
||||
if (info->entries != NULL)
|
||||
allocator.Free(info->entries);
|
||||
allocator.Free(info);
|
||||
return NULL;
|
||||
} /* if */
|
||||
|
||||
return NULL;
|
||||
return info;
|
||||
} /* QPAK_openArchive */
|
||||
|
||||
|
||||
|
@ -495,8 +481,9 @@ static int QPAK_isSymLink(dvoid *opaque, const char *name, int *fileExists)
|
|||
} /* QPAK_isSymLink */
|
||||
|
||||
|
||||
static fvoid *QPAK_openRead(dvoid *opaque, const char *fnm, int *fileExists)
|
||||
static PHYSFS_Io *QPAK_openRead(dvoid *opaque, const char *fnm, int *fileExists)
|
||||
{
|
||||
PHYSFS_Io *io = NULL;
|
||||
QPAKinfo *info = ((QPAKinfo *) opaque);
|
||||
QPAKfileinfo *finfo;
|
||||
QPAKentry *entry;
|
||||
|
@ -510,27 +497,42 @@ static fvoid *QPAK_openRead(dvoid *opaque, const char *fnm, int *fileExists)
|
|||
finfo = (QPAKfileinfo *) allocator.Malloc(sizeof (QPAKfileinfo));
|
||||
BAIL_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, NULL);
|
||||
|
||||
finfo->handle = __PHYSFS_platformOpenRead(info->filename);
|
||||
if ( (finfo->handle == NULL) ||
|
||||
(!__PHYSFS_platformSeek(finfo->handle, entry->startPos)) )
|
||||
{
|
||||
allocator.Free(finfo);
|
||||
return NULL;
|
||||
} /* if */
|
||||
finfo->io = info->io->duplicate(info->io);
|
||||
GOTO_IF_MACRO(finfo->io == NULL, NULL, QPAK_openRead_failed);
|
||||
if (!finfo->io->seek(finfo->io, entry->startPos))
|
||||
GOTO_MACRO(NULL, QPAK_openRead_failed);
|
||||
|
||||
finfo->curPos = 0;
|
||||
finfo->entry = entry;
|
||||
return finfo;
|
||||
io = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
|
||||
GOTO_IF_MACRO(io == NULL, ERR_OUT_OF_MEMORY, QPAK_openRead_failed);
|
||||
memcpy(io, &QPAK_Io, sizeof (PHYSFS_Io));
|
||||
io->opaque = finfo;
|
||||
|
||||
return io;
|
||||
|
||||
QPAK_openRead_failed:
|
||||
if (finfo != NULL)
|
||||
{
|
||||
if (finfo->io != NULL)
|
||||
finfo->io->destroy(finfo->io);
|
||||
allocator.Free(finfo);
|
||||
} /* if */
|
||||
|
||||
if (io != NULL)
|
||||
allocator.Free(io);
|
||||
|
||||
return NULL;
|
||||
} /* QPAK_openRead */
|
||||
|
||||
|
||||
static fvoid *QPAK_openWrite(dvoid *opaque, const char *name)
|
||||
static PHYSFS_Io *QPAK_openWrite(dvoid *opaque, const char *name)
|
||||
{
|
||||
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
|
||||
} /* QPAK_openWrite */
|
||||
|
||||
|
||||
static fvoid *QPAK_openAppend(dvoid *opaque, const char *name)
|
||||
static PHYSFS_Io *QPAK_openAppend(dvoid *opaque, const char *name)
|
||||
{
|
||||
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
|
||||
} /* QPAK_openAppend */
|
||||
|
@ -602,14 +604,7 @@ const PHYSFS_Archiver __PHYSFS_Archiver_QPAK =
|
|||
QPAK_remove, /* remove() method */
|
||||
QPAK_mkdir, /* mkdir() method */
|
||||
QPAK_dirClose, /* dirClose() method */
|
||||
QPAK_stat, /* stat() method */
|
||||
QPAK_read, /* read() method */
|
||||
QPAK_write, /* write() method */
|
||||
QPAK_eof, /* eof() method */
|
||||
QPAK_tell, /* tell() method */
|
||||
QPAK_seek, /* seek() method */
|
||||
QPAK_fileLength, /* fileLength() method */
|
||||
QPAK_fileClose /* fileClose() method */
|
||||
QPAK_stat /* stat() method */
|
||||
};
|
||||
|
||||
#endif /* defined PHYSFS_SUPPORTS_QPAK */
|
||||
|
|
|
@ -61,32 +61,37 @@ typedef struct
|
|||
|
||||
typedef struct
|
||||
{
|
||||
char *filename;
|
||||
PHYSFS_Io *io;
|
||||
PHYSFS_uint32 entryCount;
|
||||
PHYSFS_uint32 entryOffset;
|
||||
WADentry *entries;
|
||||
} WADinfo;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void *handle;
|
||||
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)
|
||||
{
|
||||
WADinfo *info = ((WADinfo *) opaque);
|
||||
allocator.Free(info->filename);
|
||||
info->io->destroy(info->io);
|
||||
allocator.Free(info->entries);
|
||||
allocator.Free(info);
|
||||
} /* WAD_dirClose */
|
||||
|
||||
|
||||
static PHYSFS_sint64 WAD_read(fvoid *opaque, void *buffer, PHYSFS_uint64 len)
|
||||
static PHYSFS_sint64 WAD_read(PHYSFS_Io *io, void *buffer, PHYSFS_uint64 len)
|
||||
{
|
||||
WADfileinfo *finfo = (WADfileinfo *) opaque;
|
||||
WADfileinfo *finfo = (WADfileinfo *) io->opaque;
|
||||
const WADentry *entry = finfo->entry;
|
||||
const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos);
|
||||
PHYSFS_sint64 rc;
|
||||
|
@ -94,7 +99,7 @@ static PHYSFS_sint64 WAD_read(fvoid *opaque, void *buffer, PHYSFS_uint64 len)
|
|||
if (bytesLeft < len)
|
||||
len = bytesLeft;
|
||||
|
||||
rc = __PHYSFS_platformRead(finfo->handle, buffer, len);
|
||||
rc = finfo->io->read(finfo->io, buffer, len);
|
||||
if (rc > 0)
|
||||
finfo->curPos += (PHYSFS_uint32) rc;
|
||||
|
||||
|
@ -102,35 +107,26 @@ static PHYSFS_sint64 WAD_read(fvoid *opaque, void *buffer, PHYSFS_uint64 len)
|
|||
} /* WAD_read */
|
||||
|
||||
|
||||
static PHYSFS_sint64 WAD_write(fvoid *f, const void *buf, PHYSFS_uint64 len)
|
||||
static PHYSFS_sint64 WAD_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
|
||||
{
|
||||
BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
|
||||
} /* WAD_write */
|
||||
|
||||
|
||||
static int WAD_eof(fvoid *opaque)
|
||||
static PHYSFS_sint64 WAD_tell(PHYSFS_Io *io)
|
||||
{
|
||||
WADfileinfo *finfo = (WADfileinfo *) opaque;
|
||||
WADentry *entry = finfo->entry;
|
||||
return (finfo->curPos >= entry->size);
|
||||
} /* WAD_eof */
|
||||
|
||||
|
||||
static PHYSFS_sint64 WAD_tell(fvoid *opaque)
|
||||
{
|
||||
return ((WADfileinfo *) opaque)->curPos;
|
||||
return ((WADfileinfo *) io->opaque)->curPos;
|
||||
} /* WAD_tell */
|
||||
|
||||
|
||||
static int WAD_seek(fvoid *opaque, PHYSFS_uint64 offset)
|
||||
static int WAD_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
|
||||
{
|
||||
WADfileinfo *finfo = (WADfileinfo *) opaque;
|
||||
WADentry *entry = finfo->entry;
|
||||
WADfileinfo *finfo = (WADfileinfo *) io->opaque;
|
||||
const WADentry *entry = finfo->entry;
|
||||
int rc;
|
||||
|
||||
BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
|
||||
BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
|
||||
rc = __PHYSFS_platformSeek(finfo->handle, entry->startPos + offset);
|
||||
rc = finfo->io->seek(finfo->io, entry->startPos + offset);
|
||||
if (rc)
|
||||
finfo->curPos = (PHYSFS_uint32) offset;
|
||||
|
||||
|
@ -138,83 +134,77 @@ static int WAD_seek(fvoid *opaque, PHYSFS_uint64 offset)
|
|||
} /* WAD_seek */
|
||||
|
||||
|
||||
static PHYSFS_sint64 WAD_fileLength(fvoid *opaque)
|
||||
static PHYSFS_sint64 WAD_length(PHYSFS_Io *io)
|
||||
{
|
||||
WADfileinfo *finfo = (WADfileinfo *) opaque;
|
||||
const WADfileinfo *finfo = (WADfileinfo *) io->opaque;
|
||||
return ((PHYSFS_sint64) finfo->entry->size);
|
||||
} /* WAD_fileLength */
|
||||
} /* WAD_length */
|
||||
|
||||
|
||||
static int WAD_fileClose(fvoid *opaque)
|
||||
static PHYSFS_Io *WAD_duplicate(PHYSFS_Io *_io)
|
||||
{
|
||||
WADfileinfo *finfo = (WADfileinfo *) opaque;
|
||||
BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0);
|
||||
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);
|
||||
return 1;
|
||||
} /* WAD_fileClose */
|
||||
allocator.Free(io);
|
||||
} /* WAD_destroy */
|
||||
|
||||
|
||||
static inline int readAll(void *fh, void *buf, const PHYSFS_uint64 len)
|
||||
static const PHYSFS_Io WAD_Io =
|
||||
{
|
||||
return (__PHYSFS_platformRead(fh, buf, len) == len);
|
||||
} /* readAll */
|
||||
WAD_read,
|
||||
WAD_write,
|
||||
WAD_seek,
|
||||
WAD_tell,
|
||||
WAD_length,
|
||||
WAD_duplicate,
|
||||
WAD_flush,
|
||||
WAD_destroy,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
static int wad_open(const char *filename, int forWriting,
|
||||
void **fh, PHYSFS_uint32 *count,PHYSFS_uint32 *offset)
|
||||
{
|
||||
PHYSFS_uint8 buf[4];
|
||||
|
||||
*fh = NULL;
|
||||
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
|
||||
|
||||
*fh = __PHYSFS_platformOpenRead(filename);
|
||||
BAIL_IF_MACRO(*fh == NULL, NULL, 0);
|
||||
|
||||
if (!readAll(*fh, buf, 4))
|
||||
goto openWad_failed;
|
||||
|
||||
if (memcmp(buf, "IWAD", 4) != 0 && memcmp(buf, "PWAD", 4) != 0)
|
||||
{
|
||||
__PHYSFS_setError(ERR_UNSUPPORTED_ARCHIVE);
|
||||
goto openWad_failed;
|
||||
} /* if */
|
||||
|
||||
if (!readAll(*fh, count, sizeof (PHYSFS_uint32)))
|
||||
goto openWad_failed;
|
||||
|
||||
*count = PHYSFS_swapULE32(*count);
|
||||
|
||||
if (!readAll(*fh, offset, sizeof (PHYSFS_uint32)))
|
||||
goto openWad_failed;
|
||||
|
||||
*offset = PHYSFS_swapULE32(*offset);
|
||||
|
||||
return 1;
|
||||
|
||||
openWad_failed:
|
||||
if (*fh != NULL)
|
||||
__PHYSFS_platformClose(*fh);
|
||||
|
||||
*count = -1;
|
||||
*fh = NULL;
|
||||
return 0;
|
||||
} /* wad_open */
|
||||
|
||||
|
||||
static int wad_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
|
||||
static int wadEntryCmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
|
||||
{
|
||||
if (one != two)
|
||||
{
|
||||
const WADentry *a = (const WADentry *) _a;
|
||||
return strcmp(a[one].name, a[two].name);
|
||||
return __PHYSFS_stricmpASCII(a[one].name, a[two].name);
|
||||
} /* if */
|
||||
|
||||
return 0;
|
||||
} /* wad_entry_cmp */
|
||||
} /* wadEntryCmp */
|
||||
|
||||
|
||||
static void wad_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
|
||||
static void wadEntrySwap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
|
||||
{
|
||||
if (one != two)
|
||||
{
|
||||
|
@ -225,74 +215,67 @@ static void wad_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
|
|||
memcpy(first, second, sizeof (WADentry));
|
||||
memcpy(second, &tmp, sizeof (WADentry));
|
||||
} /* if */
|
||||
} /* wad_entry_swap */
|
||||
} /* wadEntrySwap */
|
||||
|
||||
|
||||
static int wad_load_entries(const char *name, int forWriting, WADinfo *info)
|
||||
static int wad_load_entries(PHYSFS_Io *io, WADinfo *info)
|
||||
{
|
||||
void *fh = NULL;
|
||||
PHYSFS_uint32 fileCount;
|
||||
PHYSFS_uint32 fileCount = info->entryCount;
|
||||
PHYSFS_uint32 directoryOffset;
|
||||
WADentry *entry;
|
||||
char lastDirectory[9];
|
||||
|
||||
lastDirectory[8] = 0; /* Make sure lastDirectory stays null-terminated. */
|
||||
BAIL_IF_MACRO(!readAll(io, &directoryOffset, 4), NULL, 0);
|
||||
directoryOffset = PHYSFS_swapULE32(directoryOffset);
|
||||
|
||||
BAIL_IF_MACRO(!wad_open(name, forWriting, &fh, &fileCount,&directoryOffset), NULL, 0);
|
||||
info->entryCount = fileCount;
|
||||
info->entries = (WADentry *) allocator.Malloc(sizeof(WADentry)*fileCount);
|
||||
if (info->entries == NULL)
|
||||
{
|
||||
__PHYSFS_platformClose(fh);
|
||||
BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
|
||||
} /* if */
|
||||
|
||||
__PHYSFS_platformSeek(fh,directoryOffset);
|
||||
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++)
|
||||
{
|
||||
if ( (!readAll(fh, &entry->startPos, sizeof (PHYSFS_uint32))) ||
|
||||
(!readAll(fh, &entry->size, sizeof (PHYSFS_uint32))) ||
|
||||
(!readAll(fh, &entry->name, 8)) )
|
||||
{
|
||||
__PHYSFS_platformClose(fh);
|
||||
return 0;
|
||||
} /* if */
|
||||
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);
|
||||
|
||||
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_platformClose(fh);
|
||||
|
||||
__PHYSFS_sort(info->entries, info->entryCount,
|
||||
wad_entry_cmp, wad_entry_swap);
|
||||
__PHYSFS_sort(info->entries, info->entryCount, wadEntryCmp, wadEntrySwap);
|
||||
return 1;
|
||||
} /* wad_load_entries */
|
||||
|
||||
|
||||
static void *WAD_openArchive(const char *name, int forWriting)
|
||||
static void *WAD_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
|
||||
{
|
||||
WADinfo *info = (WADinfo *) allocator.Malloc(sizeof (WADinfo));
|
||||
PHYSFS_uint8 buf[4];
|
||||
WADinfo *info = NULL;
|
||||
PHYSFS_uint32 val = 0;
|
||||
|
||||
BAIL_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, NULL);
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
info->filename = (char *) allocator.Malloc(strlen(name) + 1);
|
||||
GOTO_IF_MACRO(!info->filename, ERR_OUT_OF_MEMORY, WAD_openArchive_failed);
|
||||
GOTO_IF_MACRO(!readAll(io,&val,sizeof(val)), NULL, WAD_openArchive_failed);
|
||||
info->entryCount = PHYSFS_swapULE32(val);
|
||||
|
||||
if (!wad_load_entries(name, forWriting, info))
|
||||
goto WAD_openArchive_failed;
|
||||
GOTO_IF_MACRO(!wad_load_entries(io, info), NULL, WAD_openArchive_failed);
|
||||
|
||||
strcpy(info->filename, name);
|
||||
return info;
|
||||
|
||||
WAD_openArchive_failed:
|
||||
if (info != NULL)
|
||||
{
|
||||
if (info->filename != NULL)
|
||||
allocator.Free(info->filename);
|
||||
if (info->entries != NULL)
|
||||
allocator.Free(info->entries);
|
||||
allocator.Free(info);
|
||||
|
@ -306,50 +289,41 @@ static void WAD_enumerateFiles(dvoid *opaque, const char *dname,
|
|||
int omitSymLinks, PHYSFS_EnumFilesCallback cb,
|
||||
const char *origdir, void *callbackdata)
|
||||
{
|
||||
WADinfo *info = ((WADinfo *) opaque);
|
||||
WADentry *entry = info->entries;
|
||||
PHYSFS_uint32 max = info->entryCount;
|
||||
PHYSFS_uint32 i;
|
||||
const char *name;
|
||||
char *sep;
|
||||
/* no directories in WAD files. */
|
||||
if (*dname == '\0')
|
||||
{
|
||||
WADinfo *info = (WADinfo *) opaque;
|
||||
WADentry *entry = info->entries;
|
||||
PHYSFS_uint32 max = info->entryCount;
|
||||
PHYSFS_uint32 i;
|
||||
|
||||
if (*dname == '\0') /* root directory enumeration? */
|
||||
{
|
||||
for (i = 0; i < max; i++, entry++)
|
||||
{
|
||||
name = entry->name;
|
||||
if (strchr(name, '/') == NULL)
|
||||
cb(callbackdata, origdir, name);
|
||||
} /* for */
|
||||
cb(callbackdata, origdir, entry->name);
|
||||
} /* if */
|
||||
else
|
||||
{
|
||||
for (i = 0; i < max; i++, entry++)
|
||||
{
|
||||
name = entry->name;
|
||||
sep = strchr(name, '/');
|
||||
if (sep != NULL)
|
||||
{
|
||||
if (strncmp(dname, name, (sep - name)) == 0)
|
||||
cb(callbackdata, origdir, sep + 1);
|
||||
} /* if */
|
||||
} /* for */
|
||||
} /* else */
|
||||
} /* 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 = strcmp(name, a[middle].name);
|
||||
rc = __PHYSFS_stricmpASCII(name, a[middle].name);
|
||||
if (rc == 0) /* found it! */
|
||||
return &a[middle];
|
||||
else if (rc > 0)
|
||||
|
@ -371,16 +345,18 @@ static int WAD_exists(dvoid *opaque, const char *name)
|
|||
static int WAD_isDirectory(dvoid *opaque, const char *name, int *fileExists)
|
||||
{
|
||||
WADentry *entry = wad_find_entry(((WADinfo *) opaque), name);
|
||||
if (entry != NULL)
|
||||
const int exists = (entry != NULL);
|
||||
*fileExists = exists;
|
||||
if (exists)
|
||||
{
|
||||
char *n;
|
||||
|
||||
*fileExists = 1;
|
||||
|
||||
/* Can't be a directory if it's a subdirectory. */
|
||||
if (strchr(entry->name, '/') != NULL)
|
||||
return 0;
|
||||
|
||||
/* !!! FIXME: this isn't really something we should do. */
|
||||
/* !!! FIXME: I probably broke enumeration up there, too. */
|
||||
/* Check if it matches "MAP??" or "E?M?" ... */
|
||||
n = entry->name;
|
||||
if ((n[0] == 'E' && n[2] == 'M') ||
|
||||
|
@ -388,13 +364,9 @@ static int WAD_isDirectory(dvoid *opaque, const char *name, int *fileExists)
|
|||
{
|
||||
return 1;
|
||||
} /* if */
|
||||
return 0;
|
||||
} /* if */
|
||||
else
|
||||
{
|
||||
*fileExists = 0;
|
||||
return 0;
|
||||
} /* else */
|
||||
|
||||
return 0;
|
||||
} /* WAD_isDirectory */
|
||||
|
||||
|
||||
|
@ -405,40 +377,58 @@ static int WAD_isSymLink(dvoid *opaque, const char *name, int *fileExists)
|
|||
} /* WAD_isSymLink */
|
||||
|
||||
|
||||
static fvoid *WAD_openRead(dvoid *opaque, const char *fnm, int *fileExists)
|
||||
static PHYSFS_Io *WAD_openRead(dvoid *opaque, const char *fnm, int *fileExists)
|
||||
{
|
||||
WADinfo *info = ((WADinfo *) opaque);
|
||||
PHYSFS_Io *retval = NULL;
|
||||
WADinfo *info = (WADinfo *) opaque;
|
||||
WADfileinfo *finfo;
|
||||
WADentry *entry;
|
||||
|
||||
entry = wad_find_entry(info, fnm);
|
||||
*fileExists = (entry != NULL);
|
||||
BAIL_IF_MACRO(entry == NULL, NULL, 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));
|
||||
BAIL_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, NULL);
|
||||
GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, WAD_openRead_failed);
|
||||
|
||||
finfo->handle = __PHYSFS_platformOpenRead(info->filename);
|
||||
if ( (finfo->handle == NULL) ||
|
||||
(!__PHYSFS_platformSeek(finfo->handle, entry->startPos)) )
|
||||
{
|
||||
allocator.Free(finfo);
|
||||
return NULL;
|
||||
} /* if */
|
||||
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;
|
||||
return finfo;
|
||||
|
||||
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 fvoid *WAD_openWrite(dvoid *opaque, const char *name)
|
||||
static PHYSFS_Io *WAD_openWrite(dvoid *opaque, const char *name)
|
||||
{
|
||||
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
|
||||
} /* WAD_openWrite */
|
||||
|
||||
|
||||
static fvoid *WAD_openAppend(dvoid *opaque, const char *name)
|
||||
static PHYSFS_Io *WAD_openAppend(dvoid *opaque, const char *name)
|
||||
{
|
||||
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
|
||||
} /* WAD_openAppend */
|
||||
|
@ -468,10 +458,10 @@ static int WAD_stat(dvoid *opaque, const char *filename, int *exists,
|
|||
|
||||
stat->filesize = entry->size;
|
||||
stat->filetype = PHYSFS_FILETYPE_REGULAR;
|
||||
stat->accesstime = -1;
|
||||
stat->modtime = -1;
|
||||
stat->createtime = -1;
|
||||
stat->readonly = 1; /* WADs are always readonly */
|
||||
stat->accesstime = -1;
|
||||
stat->readonly = 1;
|
||||
|
||||
return 1;
|
||||
} /* WAD_stat */
|
||||
|
@ -500,14 +490,7 @@ const PHYSFS_Archiver __PHYSFS_Archiver_WAD =
|
|||
WAD_remove, /* remove() method */
|
||||
WAD_mkdir, /* mkdir() method */
|
||||
WAD_dirClose, /* dirClose() method */
|
||||
WAD_stat, /* stat() method */
|
||||
WAD_read, /* read() method */
|
||||
WAD_write, /* write() method */
|
||||
WAD_eof, /* eof() method */
|
||||
WAD_tell, /* tell() method */
|
||||
WAD_seek, /* seek() method */
|
||||
WAD_fileLength, /* fileLength() method */
|
||||
WAD_fileClose /* fileClose() method */
|
||||
WAD_stat /* stat() method */
|
||||
};
|
||||
|
||||
#endif /* defined PHYSFS_SUPPORTS_WAD */
|
||||
|
|
|
@ -79,7 +79,7 @@ typedef struct _ZIPentry
|
|||
*/
|
||||
typedef struct
|
||||
{
|
||||
char *archiveName; /* path to ZIP in platform-dependent notation. */
|
||||
PHYSFS_Io *io;
|
||||
PHYSFS_uint16 entryCount; /* Number of files in ZIP. */
|
||||
ZIPentry *entries; /* info on all files in ZIP. */
|
||||
} ZIPinfo;
|
||||
|
@ -90,7 +90,7 @@ typedef struct
|
|||
typedef struct
|
||||
{
|
||||
ZIPentry *entry; /* Info on file. */
|
||||
void *handle; /* physical file handle. */
|
||||
PHYSFS_Io *io; /* physical file handle. */
|
||||
PHYSFS_uint32 compressed_position; /* offset in compressed data. */
|
||||
PHYSFS_uint32 uncompressed_position; /* tell() position. */
|
||||
PHYSFS_uint8 *buffer; /* decompression buffer. */
|
||||
|
@ -172,18 +172,18 @@ static int zlib_err(int rc)
|
|||
} /* zlib_err */
|
||||
|
||||
|
||||
static inline int readAll(void *fh, void *buf, const PHYSFS_uint64 len)
|
||||
static inline int readAll(PHYSFS_Io *io, void *buf, const PHYSFS_uint64 len)
|
||||
{
|
||||
return (__PHYSFS_platformRead(fh, buf, len) == len);
|
||||
return (io->read(io, buf, len) == len);
|
||||
} /* readAll */
|
||||
|
||||
/*
|
||||
* Read an unsigned 32-bit int and swap to native byte order.
|
||||
*/
|
||||
static int readui32(void *in, PHYSFS_uint32 *val)
|
||||
static int readui32(PHYSFS_Io *io, PHYSFS_uint32 *val)
|
||||
{
|
||||
PHYSFS_uint32 v;
|
||||
BAIL_IF_MACRO(!readAll(in, &v, sizeof (v)), NULL, 0);
|
||||
BAIL_IF_MACRO(!readAll(io, &v, sizeof (v)), NULL, 0);
|
||||
*val = PHYSFS_swapULE32(v);
|
||||
return 1;
|
||||
} /* readui32 */
|
||||
|
@ -192,18 +192,19 @@ static int readui32(void *in, PHYSFS_uint32 *val)
|
|||
/*
|
||||
* Read an unsigned 16-bit int and swap to native byte order.
|
||||
*/
|
||||
static int readui16(void *in, PHYSFS_uint16 *val)
|
||||
static int readui16(PHYSFS_Io *io, PHYSFS_uint16 *val)
|
||||
{
|
||||
PHYSFS_uint16 v;
|
||||
BAIL_IF_MACRO(!readAll(in, &v, sizeof (v)), NULL, 0);
|
||||
BAIL_IF_MACRO(!readAll(io, &v, sizeof (v)), NULL, 0);
|
||||
*val = PHYSFS_swapULE16(v);
|
||||
return 1;
|
||||
} /* readui16 */
|
||||
|
||||
|
||||
static PHYSFS_sint64 ZIP_read(fvoid *opaque, void *buf, PHYSFS_uint64 len)
|
||||
static PHYSFS_sint64 ZIP_read(PHYSFS_Io *_io, void *buf, PHYSFS_uint64 len)
|
||||
{
|
||||
ZIPfileinfo *finfo = (ZIPfileinfo *) opaque;
|
||||
ZIPfileinfo *finfo = (ZIPfileinfo *) _io->opaque;
|
||||
PHYSFS_Io *io = finfo->io;
|
||||
ZIPentry *entry = finfo->entry;
|
||||
PHYSFS_sint64 retval = 0;
|
||||
PHYSFS_sint64 maxread = (PHYSFS_sint64) len;
|
||||
|
@ -216,7 +217,7 @@ static PHYSFS_sint64 ZIP_read(fvoid *opaque, void *buf, PHYSFS_uint64 len)
|
|||
BAIL_IF_MACRO(maxread == 0, NULL, 0); /* quick rejection. */
|
||||
|
||||
if (entry->compression_method == COMPMETH_NONE)
|
||||
retval = __PHYSFS_platformRead(finfo->handle, buf, maxread);
|
||||
retval = io->read(io, buf, maxread);
|
||||
else
|
||||
{
|
||||
finfo->stream.next_out = buf;
|
||||
|
@ -237,8 +238,7 @@ static PHYSFS_sint64 ZIP_read(fvoid *opaque, void *buf, PHYSFS_uint64 len)
|
|||
if (br > ZIP_READBUFSIZE)
|
||||
br = ZIP_READBUFSIZE;
|
||||
|
||||
br = __PHYSFS_platformRead(finfo->handle, finfo->buffer,
|
||||
(PHYSFS_uint64) br);
|
||||
br = io->read(io, finfo->buffer, (PHYSFS_uint64) br);
|
||||
if (br <= 0)
|
||||
break;
|
||||
|
||||
|
@ -263,37 +263,30 @@ static PHYSFS_sint64 ZIP_read(fvoid *opaque, void *buf, PHYSFS_uint64 len)
|
|||
} /* ZIP_read */
|
||||
|
||||
|
||||
static PHYSFS_sint64 ZIP_write(fvoid *f, const void *buf, PHYSFS_uint64 len)
|
||||
static PHYSFS_sint64 ZIP_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
|
||||
{
|
||||
BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
|
||||
} /* ZIP_write */
|
||||
|
||||
|
||||
static int ZIP_eof(fvoid *opaque)
|
||||
static PHYSFS_sint64 ZIP_tell(PHYSFS_Io *io)
|
||||
{
|
||||
ZIPfileinfo *finfo = (ZIPfileinfo *) opaque;
|
||||
return (finfo->uncompressed_position >= finfo->entry->uncompressed_size);
|
||||
} /* ZIP_eof */
|
||||
|
||||
|
||||
static PHYSFS_sint64 ZIP_tell(fvoid *opaque)
|
||||
{
|
||||
return ((ZIPfileinfo *) opaque)->uncompressed_position;
|
||||
return ((ZIPfileinfo *) io->opaque)->uncompressed_position;
|
||||
} /* ZIP_tell */
|
||||
|
||||
|
||||
static int ZIP_seek(fvoid *opaque, PHYSFS_uint64 offset)
|
||||
static int ZIP_seek(PHYSFS_Io *_io, PHYSFS_uint64 offset)
|
||||
{
|
||||
ZIPfileinfo *finfo = (ZIPfileinfo *) opaque;
|
||||
ZIPfileinfo *finfo = (ZIPfileinfo *) _io->opaque;
|
||||
ZIPentry *entry = finfo->entry;
|
||||
void *in = finfo->handle;
|
||||
PHYSFS_Io *io = finfo->io;
|
||||
|
||||
BAIL_IF_MACRO(offset > entry->uncompressed_size, ERR_PAST_EOF, 0);
|
||||
|
||||
if (entry->compression_method == COMPMETH_NONE)
|
||||
{
|
||||
PHYSFS_sint64 newpos = offset + entry->offset;
|
||||
BAIL_IF_MACRO(!__PHYSFS_platformSeek(in, newpos), NULL, 0);
|
||||
const PHYSFS_sint64 newpos = offset + entry->offset;
|
||||
BAIL_IF_MACRO(!io->seek(io, newpos), NULL, 0);
|
||||
finfo->uncompressed_position = (PHYSFS_uint32) offset;
|
||||
} /* if */
|
||||
|
||||
|
@ -313,7 +306,7 @@ static int ZIP_seek(fvoid *opaque, PHYSFS_uint64 offset)
|
|||
if (zlib_err(inflateInit2(&str, -MAX_WBITS)) != Z_OK)
|
||||
return 0;
|
||||
|
||||
if (!__PHYSFS_platformSeek(in, entry->offset))
|
||||
if (!io->seek(io, entry->offset))
|
||||
return 0;
|
||||
|
||||
inflateEnd(&finfo->stream);
|
||||
|
@ -330,7 +323,7 @@ static int ZIP_seek(fvoid *opaque, PHYSFS_uint64 offset)
|
|||
if (maxread > sizeof (buf))
|
||||
maxread = sizeof (buf);
|
||||
|
||||
if (ZIP_read(finfo, buf, maxread) != maxread)
|
||||
if (ZIP_read(_io, buf, maxread) != maxread)
|
||||
return 0;
|
||||
} /* while */
|
||||
} /* else */
|
||||
|
@ -339,17 +332,67 @@ static int ZIP_seek(fvoid *opaque, PHYSFS_uint64 offset)
|
|||
} /* ZIP_seek */
|
||||
|
||||
|
||||
static PHYSFS_sint64 ZIP_fileLength(fvoid *opaque)
|
||||
static PHYSFS_sint64 ZIP_length(PHYSFS_Io *io)
|
||||
{
|
||||
ZIPfileinfo *finfo = (ZIPfileinfo *) opaque;
|
||||
const ZIPfileinfo *finfo = (ZIPfileinfo *) io->opaque;
|
||||
return finfo->entry->uncompressed_size;
|
||||
} /* ZIP_fileLength */
|
||||
} /* ZIP_length */
|
||||
|
||||
|
||||
static int ZIP_fileClose(fvoid *opaque)
|
||||
static PHYSFS_Io *zip_get_io(PHYSFS_Io *io, ZIPinfo *inf, ZIPentry *entry);
|
||||
|
||||
static PHYSFS_Io *ZIP_duplicate(PHYSFS_Io *io)
|
||||
{
|
||||
ZIPfileinfo *finfo = (ZIPfileinfo *) opaque;
|
||||
BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0);
|
||||
ZIPfileinfo *origfinfo = (ZIPfileinfo *) io->opaque;
|
||||
PHYSFS_Io *retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
|
||||
ZIPfileinfo *finfo = (ZIPfileinfo *) allocator.Malloc(sizeof (ZIPfileinfo));
|
||||
GOTO_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, ZIP_duplicate_failed);
|
||||
GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, ZIP_duplicate_failed);
|
||||
memset(finfo, '\0', sizeof (*finfo));
|
||||
|
||||
finfo->entry = origfinfo->entry;
|
||||
finfo->io = zip_get_io(origfinfo->io, NULL, finfo->entry);
|
||||
GOTO_IF_MACRO(finfo->io == NULL, NULL, ZIP_duplicate_failed);
|
||||
|
||||
if (finfo->entry->compression_method != COMPMETH_NONE)
|
||||
{
|
||||
finfo->buffer = (PHYSFS_uint8 *) allocator.Malloc(ZIP_READBUFSIZE);
|
||||
GOTO_IF_MACRO(!finfo->buffer, ERR_OUT_OF_MEMORY, ZIP_duplicate_failed);
|
||||
if (zlib_err(inflateInit2(&finfo->stream, -MAX_WBITS)) != Z_OK)
|
||||
goto ZIP_duplicate_failed;
|
||||
} /* if */
|
||||
|
||||
memcpy(retval, io, sizeof (PHYSFS_Io));
|
||||
retval->opaque = finfo;
|
||||
return retval;
|
||||
|
||||
ZIP_duplicate_failed:
|
||||
if (finfo != NULL)
|
||||
{
|
||||
if (finfo->io != NULL)
|
||||
finfo->io->destroy(finfo->io);
|
||||
|
||||
if (finfo->buffer != NULL)
|
||||
{
|
||||
allocator.Free(finfo->buffer);
|
||||
inflateEnd(&finfo->stream);
|
||||
} /* if */
|
||||
|
||||
allocator.Free(finfo);
|
||||
} /* if */
|
||||
|
||||
if (retval != NULL)
|
||||
allocator.Free(retval);
|
||||
|
||||
return NULL;
|
||||
} /* ZIP_duplicate */
|
||||
|
||||
static int ZIP_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
|
||||
|
||||
static void ZIP_destroy(PHYSFS_Io *io)
|
||||
{
|
||||
ZIPfileinfo *finfo = (ZIPfileinfo *) io->opaque;
|
||||
finfo->io->destroy(finfo->io);
|
||||
|
||||
if (finfo->entry->compression_method != COMPMETH_NONE)
|
||||
inflateEnd(&finfo->stream);
|
||||
|
@ -358,11 +401,26 @@ static int ZIP_fileClose(fvoid *opaque)
|
|||
allocator.Free(finfo->buffer);
|
||||
|
||||
allocator.Free(finfo);
|
||||
return 1;
|
||||
} /* ZIP_fileClose */
|
||||
allocator.Free(io);
|
||||
} /* ZIP_destroy */
|
||||
|
||||
|
||||
static PHYSFS_sint64 zip_find_end_of_central_dir(void *in, PHYSFS_sint64 *len)
|
||||
static const PHYSFS_Io ZIP_Io =
|
||||
{
|
||||
ZIP_read,
|
||||
ZIP_write,
|
||||
ZIP_seek,
|
||||
ZIP_tell,
|
||||
ZIP_length,
|
||||
ZIP_duplicate,
|
||||
ZIP_flush,
|
||||
ZIP_destroy,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
|
||||
static PHYSFS_sint64 zip_find_end_of_central_dir(PHYSFS_Io *io, PHYSFS_sint64 *len)
|
||||
{
|
||||
PHYSFS_uint8 buf[256];
|
||||
PHYSFS_uint8 extra[4] = { 0, 0, 0, 0 };
|
||||
|
@ -373,7 +431,7 @@ static PHYSFS_sint64 zip_find_end_of_central_dir(void *in, PHYSFS_sint64 *len)
|
|||
PHYSFS_sint32 totalread = 0;
|
||||
int found = 0;
|
||||
|
||||
filelen = __PHYSFS_platformFileLength(in);
|
||||
filelen = io->length(io);
|
||||
BAIL_IF_MACRO(filelen == -1, NULL, 0); /* !!! FIXME: unlocalized string */
|
||||
BAIL_IF_MACRO(filelen > 0xFFFFFFFF, "ZIP bigger than 4 gigs?!", 0);
|
||||
|
||||
|
@ -402,19 +460,19 @@ static PHYSFS_sint64 zip_find_end_of_central_dir(void *in, PHYSFS_sint64 *len)
|
|||
|
||||
while ((totalread < filelen) && (totalread < 65557))
|
||||
{
|
||||
BAIL_IF_MACRO(!__PHYSFS_platformSeek(in, filepos), NULL, -1);
|
||||
BAIL_IF_MACRO(!io->seek(io, filepos), NULL, -1);
|
||||
|
||||
/* make sure we catch a signature between buffers. */
|
||||
if (totalread != 0)
|
||||
{
|
||||
if (!readAll(in, buf, maxread - 4))
|
||||
if (!readAll(io, buf, maxread - 4))
|
||||
return -1;
|
||||
memcpy(&buf[maxread - 4], &extra, sizeof (extra));
|
||||
totalread += maxread - 4;
|
||||
} /* if */
|
||||
else
|
||||
{
|
||||
if (!readAll(in, buf, maxread))
|
||||
if (!readAll(io, buf, maxread))
|
||||
return -1;
|
||||
totalread += maxread;
|
||||
} /* else */
|
||||
|
@ -450,21 +508,16 @@ static PHYSFS_sint64 zip_find_end_of_central_dir(void *in, PHYSFS_sint64 *len)
|
|||
} /* zip_find_end_of_central_dir */
|
||||
|
||||
|
||||
/* !!! FIXME: don't open/close file here, merge with openArchive(). */
|
||||
static int isZip(const char *filename)
|
||||
static int isZip(PHYSFS_Io *io)
|
||||
{
|
||||
PHYSFS_uint32 sig;
|
||||
PHYSFS_uint32 sig = 0;
|
||||
int retval = 0;
|
||||
void *in;
|
||||
|
||||
in = __PHYSFS_platformOpenRead(filename);
|
||||
BAIL_IF_MACRO(in == NULL, NULL, 0);
|
||||
|
||||
/*
|
||||
* The first thing in a zip file might be the signature of the
|
||||
* first local file record, so it makes for a quick determination.
|
||||
*/
|
||||
if (readui32(in, &sig))
|
||||
if (readui32(io, &sig))
|
||||
{
|
||||
retval = (sig == ZIP_LOCAL_FILE_SIG);
|
||||
if (!retval)
|
||||
|
@ -474,11 +527,10 @@ static int isZip(const char *filename)
|
|||
* (a self-extracting executable, etc), so we'll have to do
|
||||
* it the hard way...
|
||||
*/
|
||||
retval = (zip_find_end_of_central_dir(in, NULL) != -1);
|
||||
retval = (zip_find_end_of_central_dir(io, NULL) != -1);
|
||||
} /* if */
|
||||
} /* if */
|
||||
|
||||
__PHYSFS_platformClose(in);
|
||||
return retval;
|
||||
} /* isZip */
|
||||
|
||||
|
@ -622,7 +674,7 @@ static void zip_expand_symlink_path(char *path)
|
|||
} /* zip_expand_symlink_path */
|
||||
|
||||
/* (forward reference: zip_follow_symlink and zip_resolve call each other.) */
|
||||
static int zip_resolve(void *in, ZIPinfo *info, ZIPentry *entry);
|
||||
static int zip_resolve(PHYSFS_Io *io, ZIPinfo *info, ZIPentry *entry);
|
||||
|
||||
/*
|
||||
* Look for the entry named by (path). If it exists, resolve it, and return
|
||||
|
@ -631,7 +683,7 @@ static int zip_resolve(void *in, ZIPinfo *info, ZIPentry *entry);
|
|||
* If there's a problem, return NULL. (path) is always free()'d by this
|
||||
* function.
|
||||
*/
|
||||
static ZIPentry *zip_follow_symlink(void *in, ZIPinfo *info, char *path)
|
||||
static ZIPentry *zip_follow_symlink(PHYSFS_Io *io, ZIPinfo *info, char *path)
|
||||
{
|
||||
ZIPentry *entry;
|
||||
|
||||
|
@ -639,7 +691,7 @@ static ZIPentry *zip_follow_symlink(void *in, ZIPinfo *info, char *path)
|
|||
entry = zip_find_entry(info, path, NULL);
|
||||
if (entry != NULL)
|
||||
{
|
||||
if (!zip_resolve(in, info, entry)) /* recursive! */
|
||||
if (!zip_resolve(io, info, entry)) /* recursive! */
|
||||
entry = NULL;
|
||||
else
|
||||
{
|
||||
|
@ -653,10 +705,10 @@ static ZIPentry *zip_follow_symlink(void *in, ZIPinfo *info, char *path)
|
|||
} /* zip_follow_symlink */
|
||||
|
||||
|
||||
static int zip_resolve_symlink(void *in, ZIPinfo *info, ZIPentry *entry)
|
||||
static int zip_resolve_symlink(PHYSFS_Io *io, ZIPinfo *info, ZIPentry *entry)
|
||||
{
|
||||
char *path;
|
||||
PHYSFS_uint32 size = entry->uncompressed_size;
|
||||
const PHYSFS_uint32 size = entry->uncompressed_size;
|
||||
int rc = 0;
|
||||
|
||||
/*
|
||||
|
@ -665,22 +717,22 @@ static int zip_resolve_symlink(void *in, ZIPinfo *info, ZIPentry *entry)
|
|||
* follow it.
|
||||
*/
|
||||
|
||||
BAIL_IF_MACRO(!__PHYSFS_platformSeek(in, entry->offset), NULL, 0);
|
||||
BAIL_IF_MACRO(!io->seek(io, entry->offset), NULL, 0);
|
||||
|
||||
path = (char *) allocator.Malloc(size + 1);
|
||||
BAIL_IF_MACRO(path == NULL, ERR_OUT_OF_MEMORY, 0);
|
||||
|
||||
if (entry->compression_method == COMPMETH_NONE)
|
||||
rc = readAll(in, path, size);
|
||||
rc = readAll(io, path, size);
|
||||
|
||||
else /* symlink target path is compressed... */
|
||||
{
|
||||
z_stream stream;
|
||||
PHYSFS_uint32 complen = entry->compressed_size;
|
||||
const PHYSFS_uint32 complen = entry->compressed_size;
|
||||
PHYSFS_uint8 *compressed = (PHYSFS_uint8*) __PHYSFS_smallAlloc(complen);
|
||||
if (compressed != NULL)
|
||||
{
|
||||
if (readAll(in, compressed, complen))
|
||||
if (readAll(io, compressed, complen))
|
||||
{
|
||||
initializeZStream(&stream);
|
||||
stream.next_in = compressed;
|
||||
|
@ -706,7 +758,7 @@ static int zip_resolve_symlink(void *in, ZIPinfo *info, ZIPentry *entry)
|
|||
{
|
||||
path[entry->uncompressed_size] = '\0'; /* null-terminate it. */
|
||||
zip_convert_dos_path(entry, path);
|
||||
entry->symlink = zip_follow_symlink(in, info, path);
|
||||
entry->symlink = zip_follow_symlink(io, info, path);
|
||||
} /* else */
|
||||
|
||||
return (entry->symlink != NULL);
|
||||
|
@ -716,7 +768,7 @@ static int zip_resolve_symlink(void *in, ZIPinfo *info, ZIPentry *entry)
|
|||
/*
|
||||
* Parse the local file header of an entry, and update entry->offset.
|
||||
*/
|
||||
static int zip_parse_local(void *in, ZIPentry *entry)
|
||||
static int zip_parse_local(PHYSFS_Io *io, ZIPentry *entry)
|
||||
{
|
||||
PHYSFS_uint32 ui32;
|
||||
PHYSFS_uint16 ui16;
|
||||
|
@ -730,30 +782,30 @@ static int zip_parse_local(void *in, ZIPentry *entry)
|
|||
* aren't zero. That seems to work well.
|
||||
*/
|
||||
|
||||
BAIL_IF_MACRO(!__PHYSFS_platformSeek(in, entry->offset), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0);
|
||||
BAIL_IF_MACRO(!io->seek(io, entry->offset), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui32(io, &ui32), NULL, 0);
|
||||
BAIL_IF_MACRO(ui32 != ZIP_LOCAL_FILE_SIG, ERR_CORRUPTED, 0);
|
||||
BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui16(io, &ui16), NULL, 0);
|
||||
BAIL_IF_MACRO(ui16 != entry->version_needed, ERR_CORRUPTED, 0);
|
||||
BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0); /* general bits. */
|
||||
BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui16(io, &ui16), NULL, 0); /* general bits. */
|
||||
BAIL_IF_MACRO(!readui16(io, &ui16), NULL, 0);
|
||||
BAIL_IF_MACRO(ui16 != entry->compression_method, ERR_CORRUPTED, 0);
|
||||
BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0); /* date/time */
|
||||
BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui32(io, &ui32), NULL, 0); /* date/time */
|
||||
BAIL_IF_MACRO(!readui32(io, &ui32), NULL, 0);
|
||||
BAIL_IF_MACRO(ui32 && (ui32 != entry->crc), ERR_CORRUPTED, 0);
|
||||
BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui32(io, &ui32), NULL, 0);
|
||||
BAIL_IF_MACRO(ui32 && (ui32 != entry->compressed_size), ERR_CORRUPTED, 0);
|
||||
BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui32(io, &ui32), NULL, 0);
|
||||
BAIL_IF_MACRO(ui32 && (ui32 != entry->uncompressed_size),ERR_CORRUPTED,0);
|
||||
BAIL_IF_MACRO(!readui16(in, &fnamelen), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui16(in, &extralen), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui16(io, &fnamelen), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui16(io, &extralen), NULL, 0);
|
||||
|
||||
entry->offset += fnamelen + extralen + 30;
|
||||
return 1;
|
||||
} /* zip_parse_local */
|
||||
|
||||
|
||||
static int zip_resolve(void *in, ZIPinfo *info, ZIPentry *entry)
|
||||
static int zip_resolve(PHYSFS_Io *io, ZIPinfo *info, ZIPentry *entry)
|
||||
{
|
||||
int retval = 1;
|
||||
ZipResolveType resolve_type = entry->resolved;
|
||||
|
@ -776,7 +828,7 @@ static int zip_resolve(void *in, ZIPinfo *info, ZIPentry *entry)
|
|||
{
|
||||
entry->resolved = ZIP_RESOLVING;
|
||||
|
||||
retval = zip_parse_local(in, entry);
|
||||
retval = zip_parse_local(io, entry);
|
||||
if (retval)
|
||||
{
|
||||
/*
|
||||
|
@ -785,7 +837,7 @@ static int zip_resolve(void *in, ZIPinfo *info, ZIPentry *entry)
|
|||
* the real file) if all goes well.
|
||||
*/
|
||||
if (resolve_type == ZIP_UNRESOLVED_SYMLINK)
|
||||
retval = zip_resolve_symlink(in, info, entry);
|
||||
retval = zip_resolve_symlink(io, info, entry);
|
||||
} /* if */
|
||||
|
||||
if (resolve_type == ZIP_UNRESOLVED_SYMLINK)
|
||||
|
@ -880,7 +932,7 @@ static PHYSFS_sint64 zip_dos_time_to_physfs_time(PHYSFS_uint32 dostime)
|
|||
} /* zip_dos_time_to_physfs_time */
|
||||
|
||||
|
||||
static int zip_load_entry(void *in, ZIPentry *entry, PHYSFS_uint32 ofs_fixup)
|
||||
static int zip_load_entry(PHYSFS_Io *io, ZIPentry *entry, PHYSFS_uint32 ofs_fixup)
|
||||
{
|
||||
PHYSFS_uint16 fnamelen, extralen, commentlen;
|
||||
PHYSFS_uint32 external_attr;
|
||||
|
@ -889,26 +941,26 @@ static int zip_load_entry(void *in, ZIPentry *entry, PHYSFS_uint32 ofs_fixup)
|
|||
PHYSFS_sint64 si64;
|
||||
|
||||
/* sanity check with central directory signature... */
|
||||
BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui32(io, &ui32), NULL, 0);
|
||||
BAIL_IF_MACRO(ui32 != ZIP_CENTRAL_DIR_SIG, ERR_CORRUPTED, 0);
|
||||
|
||||
/* Get the pertinent parts of the record... */
|
||||
BAIL_IF_MACRO(!readui16(in, &entry->version), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui16(in, &entry->version_needed), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0); /* general bits */
|
||||
BAIL_IF_MACRO(!readui16(in, &entry->compression_method), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui16(io, &entry->version), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui16(io, &entry->version_needed), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui16(io, &ui16), NULL, 0); /* general bits */
|
||||
BAIL_IF_MACRO(!readui16(io, &entry->compression_method), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui32(io, &ui32), NULL, 0);
|
||||
entry->last_mod_time = zip_dos_time_to_physfs_time(ui32);
|
||||
BAIL_IF_MACRO(!readui32(in, &entry->crc), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui32(in, &entry->compressed_size), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui32(in, &entry->uncompressed_size), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui16(in, &fnamelen), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui16(in, &extralen), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui16(in, &commentlen), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0); /* disk number start */
|
||||
BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0); /* internal file attribs */
|
||||
BAIL_IF_MACRO(!readui32(in, &external_attr), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui32(in, &entry->offset), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui32(io, &entry->crc), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui32(io, &entry->compressed_size), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui32(io, &entry->uncompressed_size), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui16(io, &fnamelen), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui16(io, &extralen), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui16(io, &commentlen), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui16(io, &ui16), NULL, 0); /* disk number start */
|
||||
BAIL_IF_MACRO(!readui16(io, &ui16), NULL, 0); /* internal file attribs */
|
||||
BAIL_IF_MACRO(!readui32(io, &external_attr), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui32(io, &entry->offset), NULL, 0);
|
||||
entry->offset += ofs_fixup;
|
||||
|
||||
entry->symlink = NULL; /* will be resolved later, if necessary. */
|
||||
|
@ -917,18 +969,18 @@ static int zip_load_entry(void *in, ZIPentry *entry, PHYSFS_uint32 ofs_fixup)
|
|||
|
||||
entry->name = (char *) allocator.Malloc(fnamelen + 1);
|
||||
BAIL_IF_MACRO(entry->name == NULL, ERR_OUT_OF_MEMORY, 0);
|
||||
if (!readAll(in, entry->name, fnamelen))
|
||||
if (!readAll(io, entry->name, fnamelen))
|
||||
goto zip_load_entry_puked;
|
||||
|
||||
entry->name[fnamelen] = '\0'; /* null-terminate the filename. */
|
||||
zip_convert_dos_path(entry, entry->name);
|
||||
|
||||
si64 = __PHYSFS_platformTell(in);
|
||||
si64 = io->tell(io);
|
||||
if (si64 == -1)
|
||||
goto zip_load_entry_puked;
|
||||
|
||||
/* seek to the start of the next entry in the central directory... */
|
||||
if (!__PHYSFS_platformSeek(in, si64 + extralen + commentlen))
|
||||
if (!io->seek(io, si64 + extralen + commentlen))
|
||||
goto zip_load_entry_puked;
|
||||
|
||||
return 1; /* success. */
|
||||
|
@ -965,20 +1017,20 @@ static void zip_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
|
|||
} /* zip_entry_swap */
|
||||
|
||||
|
||||
static int zip_load_entries(void *in, ZIPinfo *info,
|
||||
static int zip_load_entries(PHYSFS_Io *io, ZIPinfo *info,
|
||||
PHYSFS_uint32 data_ofs, PHYSFS_uint32 central_ofs)
|
||||
{
|
||||
PHYSFS_uint32 max = info->entryCount;
|
||||
PHYSFS_uint32 i;
|
||||
|
||||
BAIL_IF_MACRO(!__PHYSFS_platformSeek(in, central_ofs), NULL, 0);
|
||||
BAIL_IF_MACRO(!io->seek(io, central_ofs), NULL, 0);
|
||||
|
||||
info->entries = (ZIPentry *) allocator.Malloc(sizeof (ZIPentry) * max);
|
||||
BAIL_IF_MACRO(info->entries == NULL, ERR_OUT_OF_MEMORY, 0);
|
||||
|
||||
for (i = 0; i < max; i++)
|
||||
{
|
||||
if (!zip_load_entry(in, &info->entries[i], data_ofs))
|
||||
if (!zip_load_entry(io, &info->entries[i], data_ofs))
|
||||
{
|
||||
zip_free_entries(info->entries, i);
|
||||
return 0;
|
||||
|
@ -990,7 +1042,7 @@ static int zip_load_entries(void *in, ZIPinfo *info,
|
|||
} /* zip_load_entries */
|
||||
|
||||
|
||||
static int zip_parse_end_of_central_dir(void *in, ZIPinfo *info,
|
||||
static int zip_parse_end_of_central_dir(PHYSFS_Io *io, ZIPinfo *info,
|
||||
PHYSFS_uint32 *data_start,
|
||||
PHYSFS_uint32 *central_dir_ofs)
|
||||
{
|
||||
|
@ -1000,34 +1052,34 @@ static int zip_parse_end_of_central_dir(void *in, ZIPinfo *info,
|
|||
PHYSFS_sint64 pos;
|
||||
|
||||
/* find the end-of-central-dir record, and seek to it. */
|
||||
pos = zip_find_end_of_central_dir(in, &len);
|
||||
pos = zip_find_end_of_central_dir(io, &len);
|
||||
BAIL_IF_MACRO(pos == -1, NULL, 0);
|
||||
BAIL_IF_MACRO(!__PHYSFS_platformSeek(in, pos), NULL, 0);
|
||||
BAIL_IF_MACRO(!io->seek(io, pos), NULL, 0);
|
||||
|
||||
/* check signature again, just in case. */
|
||||
BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui32(io, &ui32), NULL, 0);
|
||||
BAIL_IF_MACRO(ui32 != ZIP_END_OF_CENTRAL_DIR_SIG, ERR_NOT_AN_ARCHIVE, 0);
|
||||
|
||||
/* number of this disk */
|
||||
BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui16(io, &ui16), NULL, 0);
|
||||
BAIL_IF_MACRO(ui16 != 0, ERR_UNSUPPORTED_ARCHIVE, 0);
|
||||
|
||||
/* number of the disk with the start of the central directory */
|
||||
BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui16(io, &ui16), NULL, 0);
|
||||
BAIL_IF_MACRO(ui16 != 0, ERR_UNSUPPORTED_ARCHIVE, 0);
|
||||
|
||||
/* total number of entries in the central dir on this disk */
|
||||
BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui16(io, &ui16), NULL, 0);
|
||||
|
||||
/* total number of entries in the central dir */
|
||||
BAIL_IF_MACRO(!readui16(in, &info->entryCount), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui16(io, &info->entryCount), NULL, 0);
|
||||
BAIL_IF_MACRO(ui16 != info->entryCount, ERR_UNSUPPORTED_ARCHIVE, 0);
|
||||
|
||||
/* size of the central directory */
|
||||
BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui32(io, &ui32), NULL, 0);
|
||||
|
||||
/* offset of central directory */
|
||||
BAIL_IF_MACRO(!readui32(in, central_dir_ofs), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui32(io, central_dir_ofs), NULL, 0);
|
||||
BAIL_IF_MACRO(pos < *central_dir_ofs + ui32, ERR_UNSUPPORTED_ARCHIVE, 0);
|
||||
|
||||
/*
|
||||
|
@ -1044,7 +1096,7 @@ static int zip_parse_end_of_central_dir(void *in, ZIPinfo *info,
|
|||
*central_dir_ofs += *data_start;
|
||||
|
||||
/* zipfile comment length */
|
||||
BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);
|
||||
BAIL_IF_MACRO(!readui16(io, &ui16), NULL, 0);
|
||||
|
||||
/*
|
||||
* Make sure that the comment length matches to the end of file...
|
||||
|
@ -1057,61 +1109,33 @@ static int zip_parse_end_of_central_dir(void *in, ZIPinfo *info,
|
|||
} /* zip_parse_end_of_central_dir */
|
||||
|
||||
|
||||
static ZIPinfo *zip_create_zipinfo(const char *name)
|
||||
static void *ZIP_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
|
||||
{
|
||||
char *ptr;
|
||||
ZIPinfo *info = (ZIPinfo *) allocator.Malloc(sizeof (ZIPinfo));
|
||||
BAIL_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, 0);
|
||||
memset(info, '\0', sizeof (ZIPinfo));
|
||||
|
||||
ptr = (char *) allocator.Malloc(strlen(name) + 1);
|
||||
if (ptr == NULL)
|
||||
{
|
||||
allocator.Free(info);
|
||||
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
|
||||
} /* if */
|
||||
|
||||
info->archiveName = ptr;
|
||||
strcpy(info->archiveName, name);
|
||||
return info;
|
||||
} /* zip_create_zipinfo */
|
||||
|
||||
|
||||
static void *ZIP_openArchive(const char *name, int forWriting)
|
||||
{
|
||||
void *in = NULL;
|
||||
ZIPinfo *info = NULL;
|
||||
PHYSFS_uint32 data_start;
|
||||
PHYSFS_uint32 cent_dir_ofs;
|
||||
|
||||
assert(io != NULL); /* shouldn't ever happen. */
|
||||
|
||||
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, NULL);
|
||||
BAIL_IF_MACRO(!isZip(name), NULL, NULL);
|
||||
BAIL_IF_MACRO(!isZip(io), NULL, NULL);
|
||||
|
||||
if ((in = __PHYSFS_platformOpenRead(name)) == NULL)
|
||||
goto zip_openarchive_failed;
|
||||
|
||||
if ((info = zip_create_zipinfo(name)) == NULL)
|
||||
goto zip_openarchive_failed;
|
||||
info = (ZIPinfo *) allocator.Malloc(sizeof (ZIPinfo));
|
||||
BAIL_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, NULL);
|
||||
memset(info, '\0', sizeof (ZIPinfo));
|
||||
info->io = io;
|
||||
|
||||
if (!zip_parse_end_of_central_dir(in, info, &data_start, ¢_dir_ofs))
|
||||
goto zip_openarchive_failed;
|
||||
if (!zip_parse_end_of_central_dir(io, info, &data_start, ¢_dir_ofs))
|
||||
goto ZIP_openarchive_failed;
|
||||
|
||||
if (!zip_load_entries(in, info, data_start, cent_dir_ofs))
|
||||
goto zip_openarchive_failed;
|
||||
if (!zip_load_entries(io, info, data_start, cent_dir_ofs))
|
||||
goto ZIP_openarchive_failed;
|
||||
|
||||
__PHYSFS_platformClose(in);
|
||||
return info;
|
||||
|
||||
zip_openarchive_failed:
|
||||
ZIP_openarchive_failed:
|
||||
if (info != NULL)
|
||||
{
|
||||
if (info->archiveName != NULL)
|
||||
allocator.Free(info->archiveName);
|
||||
allocator.Free(info);
|
||||
} /* if */
|
||||
|
||||
if (in != NULL)
|
||||
__PHYSFS_platformClose(in);
|
||||
|
||||
return NULL;
|
||||
} /* ZIP_openArchive */
|
||||
|
@ -1257,12 +1281,7 @@ static int ZIP_isDirectory(dvoid *opaque, const char *name, int *fileExists)
|
|||
|
||||
if (entry->resolved == ZIP_UNRESOLVED_SYMLINK) /* gotta resolve it. */
|
||||
{
|
||||
int rc;
|
||||
void *in = __PHYSFS_platformOpenRead(info->archiveName);
|
||||
BAIL_IF_MACRO(in == NULL, NULL, 0);
|
||||
rc = zip_resolve(in, info, entry);
|
||||
__PHYSFS_platformClose(in);
|
||||
if (!rc)
|
||||
if (!zip_resolve(info->io, info, entry))
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
|
@ -1283,81 +1302,95 @@ static int ZIP_isSymLink(dvoid *opaque, const char *name, int *fileExists)
|
|||
} /* ZIP_isSymLink */
|
||||
|
||||
|
||||
static void *zip_get_file_handle(const char *fn, ZIPinfo *inf, ZIPentry *entry)
|
||||
static PHYSFS_Io *zip_get_io(PHYSFS_Io *io, ZIPinfo *inf, ZIPentry *entry)
|
||||
{
|
||||
int success;
|
||||
void *retval = __PHYSFS_platformOpenRead(fn);
|
||||
PHYSFS_Io *retval = io->duplicate(io);
|
||||
BAIL_IF_MACRO(retval == NULL, NULL, NULL);
|
||||
|
||||
success = zip_resolve(retval, inf, entry);
|
||||
/* (inf) can be NULL if we already resolved. */
|
||||
success = (inf == NULL) || zip_resolve(retval, inf, entry);
|
||||
if (success)
|
||||
{
|
||||
PHYSFS_sint64 offset;
|
||||
offset = ((entry->symlink) ? entry->symlink->offset : entry->offset);
|
||||
success = __PHYSFS_platformSeek(retval, offset);
|
||||
success = retval->seek(retval, offset);
|
||||
} /* if */
|
||||
|
||||
if (!success)
|
||||
{
|
||||
__PHYSFS_platformClose(retval);
|
||||
retval->destroy(retval);
|
||||
retval = NULL;
|
||||
} /* if */
|
||||
|
||||
return retval;
|
||||
} /* zip_get_file_handle */
|
||||
} /* zip_get_io */
|
||||
|
||||
|
||||
static fvoid *ZIP_openRead(dvoid *opaque, const char *fnm, int *fileExists)
|
||||
static PHYSFS_Io *ZIP_openRead(dvoid *opaque, const char *fnm, int *fileExists)
|
||||
{
|
||||
PHYSFS_Io *retval = NULL;
|
||||
ZIPinfo *info = (ZIPinfo *) opaque;
|
||||
ZIPentry *entry = zip_find_entry(info, fnm, NULL);
|
||||
ZIPfileinfo *finfo = NULL;
|
||||
void *in;
|
||||
|
||||
*fileExists = (entry != NULL);
|
||||
BAIL_IF_MACRO(entry == NULL, NULL, NULL);
|
||||
|
||||
in = zip_get_file_handle(info->archiveName, info, entry);
|
||||
BAIL_IF_MACRO(in == NULL, NULL, NULL);
|
||||
retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
|
||||
GOTO_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
|
||||
|
||||
finfo = (ZIPfileinfo *) allocator.Malloc(sizeof (ZIPfileinfo));
|
||||
if (finfo == NULL)
|
||||
{
|
||||
__PHYSFS_platformClose(in);
|
||||
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
|
||||
} /* if */
|
||||
|
||||
GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
|
||||
memset(finfo, '\0', sizeof (ZIPfileinfo));
|
||||
finfo->handle = in;
|
||||
|
||||
finfo->io = zip_get_io(info->io, info, entry);
|
||||
GOTO_IF_MACRO(finfo->io == NULL, NULL, ZIP_openRead_failed);
|
||||
finfo->entry = ((entry->symlink != NULL) ? entry->symlink : entry);
|
||||
initializeZStream(&finfo->stream);
|
||||
|
||||
if (finfo->entry->compression_method != COMPMETH_NONE)
|
||||
{
|
||||
if (zlib_err(inflateInit2(&finfo->stream, -MAX_WBITS)) != Z_OK)
|
||||
{
|
||||
ZIP_fileClose(finfo);
|
||||
return NULL;
|
||||
} /* if */
|
||||
|
||||
finfo->buffer = (PHYSFS_uint8 *) allocator.Malloc(ZIP_READBUFSIZE);
|
||||
if (finfo->buffer == NULL)
|
||||
{
|
||||
ZIP_fileClose(finfo);
|
||||
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
|
||||
} /* if */
|
||||
GOTO_IF_MACRO(!finfo->buffer, ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
|
||||
if (zlib_err(inflateInit2(&finfo->stream, -MAX_WBITS)) != Z_OK)
|
||||
goto ZIP_openRead_failed;
|
||||
} /* if */
|
||||
|
||||
return finfo;
|
||||
memcpy(retval, &ZIP_Io, sizeof (PHYSFS_Io));
|
||||
retval->opaque = finfo;
|
||||
|
||||
return retval;
|
||||
|
||||
ZIP_openRead_failed:
|
||||
if (finfo != NULL)
|
||||
{
|
||||
if (finfo->io != NULL)
|
||||
finfo->io->destroy(finfo->io);
|
||||
|
||||
if (finfo->buffer != NULL)
|
||||
{
|
||||
allocator.Free(finfo->buffer);
|
||||
inflateEnd(&finfo->stream);
|
||||
} /* if */
|
||||
|
||||
allocator.Free(finfo);
|
||||
} /* if */
|
||||
|
||||
if (retval != NULL)
|
||||
allocator.Free(retval);
|
||||
|
||||
return NULL;
|
||||
} /* ZIP_openRead */
|
||||
|
||||
|
||||
static fvoid *ZIP_openWrite(dvoid *opaque, const char *filename)
|
||||
static PHYSFS_Io *ZIP_openWrite(dvoid *opaque, const char *filename)
|
||||
{
|
||||
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
|
||||
} /* ZIP_openWrite */
|
||||
|
||||
|
||||
static fvoid *ZIP_openAppend(dvoid *opaque, const char *filename)
|
||||
static PHYSFS_Io *ZIP_openAppend(dvoid *opaque, const char *filename)
|
||||
{
|
||||
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
|
||||
} /* ZIP_openAppend */
|
||||
|
@ -1366,8 +1399,8 @@ static fvoid *ZIP_openAppend(dvoid *opaque, const char *filename)
|
|||
static void ZIP_dirClose(dvoid *opaque)
|
||||
{
|
||||
ZIPinfo *zi = (ZIPinfo *) (opaque);
|
||||
zi->io->destroy(zi->io);
|
||||
zip_free_entries(zi->entries, zi->entryCount);
|
||||
allocator.Free(zi->archiveName);
|
||||
allocator.Free(zi);
|
||||
} /* ZIP_dirClose */
|
||||
|
||||
|
@ -1445,14 +1478,7 @@ const PHYSFS_Archiver __PHYSFS_Archiver_ZIP =
|
|||
ZIP_remove, /* remove() method */
|
||||
ZIP_mkdir, /* mkdir() method */
|
||||
ZIP_dirClose, /* dirClose() method */
|
||||
ZIP_stat, /* stat() method */
|
||||
ZIP_read, /* read() method */
|
||||
ZIP_write, /* write() method */
|
||||
ZIP_eof, /* eof() method */
|
||||
ZIP_tell, /* tell() method */
|
||||
ZIP_seek, /* seek() method */
|
||||
ZIP_fileLength, /* fileLength() method */
|
||||
ZIP_fileClose /* fileClose() method */
|
||||
ZIP_stat /* stat() method */
|
||||
};
|
||||
|
||||
#endif /* defined PHYSFS_SUPPORTS_ZIP */
|
||||
|
|
289
src/physfs.c
289
src/physfs.c
|
@ -31,10 +31,9 @@ typedef struct __PHYSFS_DIRHANDLE__
|
|||
|
||||
typedef struct __PHYSFS_FILEHANDLE__
|
||||
{
|
||||
void *opaque; /* Instance data unique to the archiver for this file. */
|
||||
PHYSFS_Io *io; /* Instance data unique to the archiver for this file. */
|
||||
PHYSFS_uint8 forReading; /* Non-zero if reading, zero if write/append */
|
||||
const DirHandle *dirHandle; /* Archiver instance that created this */
|
||||
const PHYSFS_Archiver *funcs; /* Ptr to archiver info for this handle. */
|
||||
PHYSFS_uint8 *buffer; /* Buffer, if set (NULL otherwise). Don't touch! */
|
||||
PHYSFS_uint32 bufsize; /* Bufsize, if set (0 otherwise). Don't touch! */
|
||||
PHYSFS_uint32 buffill; /* Buffer fill size. Don't touch! */
|
||||
|
@ -152,6 +151,122 @@ static int externalAllocator = 0;
|
|||
PHYSFS_Allocator allocator;
|
||||
|
||||
|
||||
/* PHYSFS_Io implementation for i/o to physical filesystem... */
|
||||
|
||||
/* !!! FIXME: maybe refcount the paths in a string pool? */
|
||||
typedef struct __PHYSFS_NativeIoInfo
|
||||
{
|
||||
void *handle;
|
||||
const char *path;
|
||||
int mode; /* 'r', 'w', or 'a' */
|
||||
} NativeIoInfo;
|
||||
|
||||
static PHYSFS_sint64 nativeIo_read(PHYSFS_Io *io, void *buf, PHYSFS_uint64 len)
|
||||
{
|
||||
NativeIoInfo *info = (NativeIoInfo *) io->opaque;
|
||||
return __PHYSFS_platformRead(info->handle, buf, len);
|
||||
} /* nativeIo_read */
|
||||
|
||||
static PHYSFS_sint64 nativeIo_write(PHYSFS_Io *io, const void *buffer,
|
||||
PHYSFS_uint64 len)
|
||||
{
|
||||
NativeIoInfo *info = (NativeIoInfo *) io->opaque;
|
||||
return __PHYSFS_platformWrite(info->handle, buffer, len);
|
||||
} /* nativeIo_write */
|
||||
|
||||
static int nativeIo_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
|
||||
{
|
||||
NativeIoInfo *info = (NativeIoInfo *) io->opaque;
|
||||
return __PHYSFS_platformSeek(info->handle, offset);
|
||||
} /* nativeIo_seek */
|
||||
|
||||
static PHYSFS_sint64 nativeIo_tell(PHYSFS_Io *io)
|
||||
{
|
||||
NativeIoInfo *info = (NativeIoInfo *) io->opaque;
|
||||
return __PHYSFS_platformTell(info->handle);
|
||||
} /* nativeIo_tell */
|
||||
|
||||
static PHYSFS_sint64 nativeIo_length(PHYSFS_Io *io)
|
||||
{
|
||||
NativeIoInfo *info = (NativeIoInfo *) io->opaque;
|
||||
return __PHYSFS_platformFileLength(info->handle);
|
||||
} /* nativeIo_length */
|
||||
|
||||
static PHYSFS_Io *nativeIo_duplicate(PHYSFS_Io *io)
|
||||
{
|
||||
NativeIoInfo *info = (NativeIoInfo *) io->opaque;
|
||||
return __PHYSFS_createNativeIo(info->path, info->mode);
|
||||
} /* nativeIo_duplicate */
|
||||
|
||||
static int nativeIo_flush(PHYSFS_Io *io)
|
||||
{
|
||||
return __PHYSFS_platformFlush(io->opaque);
|
||||
} /* nativeIo_flush */
|
||||
|
||||
static void nativeIo_destroy(PHYSFS_Io *io)
|
||||
{
|
||||
NativeIoInfo *info = (NativeIoInfo *) io->opaque;
|
||||
__PHYSFS_platformClose(info->handle);
|
||||
allocator.Free((void *) info->path);
|
||||
allocator.Free(info);
|
||||
allocator.Free(io);
|
||||
} /* nativeIo_destroy */
|
||||
|
||||
static const PHYSFS_Io __PHYSFS_nativeIoInterface =
|
||||
{
|
||||
nativeIo_read,
|
||||
nativeIo_write,
|
||||
nativeIo_seek,
|
||||
nativeIo_tell,
|
||||
nativeIo_length,
|
||||
nativeIo_duplicate,
|
||||
nativeIo_flush,
|
||||
nativeIo_destroy,
|
||||
NULL
|
||||
};
|
||||
|
||||
PHYSFS_Io *__PHYSFS_createNativeIo(const char *path, const int mode)
|
||||
{
|
||||
PHYSFS_Io *io = NULL;
|
||||
NativeIoInfo *info = NULL;
|
||||
void *handle = NULL;
|
||||
char *pathdup = NULL;
|
||||
|
||||
assert((mode == 'r') || (mode == 'w') || (mode == 'a'));
|
||||
|
||||
io = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
|
||||
GOTO_IF_MACRO(io == NULL, ERR_OUT_OF_MEMORY, createNativeIo_failed);
|
||||
info = (NativeIoInfo *) allocator.Malloc(sizeof (NativeIoInfo));
|
||||
GOTO_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, createNativeIo_failed);
|
||||
pathdup = (char *) allocator.Malloc(strlen(path) + 1);
|
||||
GOTO_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, createNativeIo_failed);
|
||||
|
||||
if (mode == 'r')
|
||||
handle = __PHYSFS_platformOpenRead(path);
|
||||
else if (mode == 'w')
|
||||
handle = __PHYSFS_platformOpenWrite(path);
|
||||
else if (mode == 'a')
|
||||
handle = __PHYSFS_platformOpenAppend(path);
|
||||
|
||||
GOTO_IF_MACRO(handle == NULL, NULL, createNativeIo_failed);
|
||||
|
||||
strcpy(pathdup, path);
|
||||
info->handle = handle;
|
||||
info->path = pathdup;
|
||||
info->mode = mode;
|
||||
memcpy(io, &__PHYSFS_nativeIoInterface, sizeof (*io));
|
||||
io->opaque = info;
|
||||
return io;
|
||||
|
||||
createNativeIo_failed:
|
||||
if (handle != NULL) __PHYSFS_platformClose(handle);
|
||||
if (pathdup != NULL) allocator.Free(pathdup);
|
||||
if (info != NULL) allocator.Free(info);
|
||||
if (io != NULL) allocator.Free(io);
|
||||
return NULL;
|
||||
} /* __PHYSFS_createNativeIo */
|
||||
|
||||
|
||||
/* functions ... */
|
||||
|
||||
typedef struct
|
||||
|
@ -379,28 +494,37 @@ void PHYSFS_getLinkedVersion(PHYSFS_Version *ver)
|
|||
|
||||
static const char *find_filename_extension(const char *fname)
|
||||
{
|
||||
const char *retval = strchr(fname, '.');
|
||||
const char *p = retval;
|
||||
|
||||
while (p != NULL)
|
||||
const char *retval = NULL;
|
||||
if (fname != NULL)
|
||||
{
|
||||
p = strchr(p + 1, '.');
|
||||
if (p != NULL)
|
||||
retval = p;
|
||||
} /* while */
|
||||
retval = strchr(fname, '.');
|
||||
const char *p = retval;
|
||||
|
||||
if (retval != NULL)
|
||||
retval++; /* skip '.' */
|
||||
while (p != NULL)
|
||||
{
|
||||
p = strchr(p + 1, '.');
|
||||
if (p != NULL)
|
||||
retval = p;
|
||||
} /* while */
|
||||
|
||||
if (retval != NULL)
|
||||
retval++; /* skip '.' */
|
||||
} /* if */
|
||||
|
||||
return retval;
|
||||
} /* find_filename_extension */
|
||||
|
||||
|
||||
static DirHandle *tryOpenDir(const PHYSFS_Archiver *funcs,
|
||||
static DirHandle *tryOpenDir(PHYSFS_Io *io, const PHYSFS_Archiver *funcs,
|
||||
const char *d, int forWriting)
|
||||
{
|
||||
DirHandle *retval = NULL;
|
||||
void *opaque = funcs->openArchive(d, forWriting);
|
||||
void *opaque = NULL;
|
||||
|
||||
if (io != NULL)
|
||||
BAIL_IF_MACRO(!io->seek(io, 0), NULL, NULL);
|
||||
|
||||
opaque = funcs->openArchive(io, d, forWriting);
|
||||
if (opaque != NULL)
|
||||
{
|
||||
retval = (DirHandle *) allocator.Malloc(sizeof (DirHandle));
|
||||
|
@ -419,18 +543,26 @@ static DirHandle *tryOpenDir(const PHYSFS_Archiver *funcs,
|
|||
} /* tryOpenDir */
|
||||
|
||||
|
||||
static DirHandle *openDirectory(const char *d, int forWriting)
|
||||
static DirHandle *openDirectory(PHYSFS_Io *io, const char *d, int forWriting)
|
||||
{
|
||||
DirHandle *retval = NULL;
|
||||
const PHYSFS_Archiver **i;
|
||||
const char *ext;
|
||||
|
||||
BAIL_IF_MACRO(!__PHYSFS_platformExists(d), ERR_NO_SUCH_FILE, NULL);
|
||||
assert((io != NULL) || (d != NULL));
|
||||
|
||||
/* DIR gets first shot (unlike the rest, it doesn't deal with files). */
|
||||
retval = tryOpenDir(&__PHYSFS_Archiver_DIR, d, forWriting);
|
||||
if (retval != NULL)
|
||||
return retval;
|
||||
if (io == NULL)
|
||||
{
|
||||
BAIL_IF_MACRO(!__PHYSFS_platformExists(d), ERR_NO_SUCH_FILE, NULL);
|
||||
|
||||
/* DIR gets first shot (unlike the rest, it doesn't deal with files). */
|
||||
retval = tryOpenDir(io, &__PHYSFS_Archiver_DIR, d, forWriting);
|
||||
if (retval != NULL)
|
||||
return retval;
|
||||
|
||||
io = __PHYSFS_createNativeIo(d, forWriting ? 'w' : 'r');
|
||||
BAIL_IF_MACRO_MUTEX(io == NULL, NULL, stateLock, 0);
|
||||
} /* if */
|
||||
|
||||
ext = find_filename_extension(d);
|
||||
if (ext != NULL)
|
||||
|
@ -439,21 +571,21 @@ static DirHandle *openDirectory(const char *d, int forWriting)
|
|||
for (i = archivers; (*i != NULL) && (retval == NULL); i++)
|
||||
{
|
||||
if (__PHYSFS_stricmpASCII(ext, (*i)->info->extension) == 0)
|
||||
retval = tryOpenDir(*i, d, forWriting);
|
||||
retval = tryOpenDir(io, *i, d, forWriting);
|
||||
} /* for */
|
||||
|
||||
/* failing an exact file extension match, try all the others... */
|
||||
for (i = archivers; (*i != NULL) && (retval == NULL); i++)
|
||||
{
|
||||
if (__PHYSFS_stricmpASCII(ext, (*i)->info->extension) != 0)
|
||||
retval = tryOpenDir(*i, d, forWriting);
|
||||
retval = tryOpenDir(io, *i, d, forWriting);
|
||||
} /* for */
|
||||
} /* if */
|
||||
|
||||
else /* no extension? Try them all. */
|
||||
{
|
||||
for (i = archivers; (*i != NULL) && (retval == NULL); i++)
|
||||
retval = tryOpenDir(*i, d, forWriting);
|
||||
retval = tryOpenDir(io, *i, d, forWriting);
|
||||
} /* else */
|
||||
|
||||
BAIL_IF_MACRO(retval == NULL, ERR_UNSUPPORTED_ARCHIVE, NULL);
|
||||
|
@ -545,14 +677,12 @@ static int partOfMountPoint(DirHandle *h, char *fname)
|
|||
} /* partOfMountPoint */
|
||||
|
||||
|
||||
static DirHandle *createDirHandle(const char *newDir,
|
||||
const char *mountPoint,
|
||||
int forWriting)
|
||||
static DirHandle *createDirHandle(PHYSFS_Io *io, const char *newDir,
|
||||
const char *mountPoint, int forWriting)
|
||||
{
|
||||
DirHandle *dirHandle = NULL;
|
||||
char *tmpmntpnt = NULL;
|
||||
|
||||
GOTO_IF_MACRO(!newDir, ERR_INVALID_ARGUMENT, badDirHandle);
|
||||
if (mountPoint != NULL)
|
||||
{
|
||||
const size_t len = strlen(mountPoint) + 1;
|
||||
|
@ -563,12 +693,17 @@ static DirHandle *createDirHandle(const char *newDir,
|
|||
mountPoint = tmpmntpnt; /* sanitized version. */
|
||||
} /* if */
|
||||
|
||||
dirHandle = openDirectory(newDir, forWriting);
|
||||
dirHandle = openDirectory(io, newDir, forWriting);
|
||||
GOTO_IF_MACRO(!dirHandle, NULL, badDirHandle);
|
||||
|
||||
dirHandle->dirName = (char *) allocator.Malloc(strlen(newDir) + 1);
|
||||
GOTO_IF_MACRO(!dirHandle->dirName, ERR_OUT_OF_MEMORY, badDirHandle);
|
||||
strcpy(dirHandle->dirName, newDir);
|
||||
if (newDir == NULL)
|
||||
dirHandle->dirName = NULL;
|
||||
else
|
||||
{
|
||||
dirHandle->dirName = (char *) allocator.Malloc(strlen(newDir) + 1);
|
||||
GOTO_IF_MACRO(!dirHandle->dirName, ERR_OUT_OF_MEMORY, badDirHandle);
|
||||
strcpy(dirHandle->dirName, newDir);
|
||||
} /* else */
|
||||
|
||||
if ((mountPoint != NULL) && (*mountPoint != '\0'))
|
||||
{
|
||||
|
@ -791,13 +926,16 @@ static int closeFileHandleList(FileHandle **list)
|
|||
|
||||
for (i = *list; i != NULL; i = next)
|
||||
{
|
||||
PHYSFS_Io *io = i->io;
|
||||
next = i->next;
|
||||
if (!i->funcs->fileClose(i->opaque))
|
||||
|
||||
if (!io->flush(io))
|
||||
{
|
||||
*list = i;
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
io->destroy(io);
|
||||
allocator.Free(i);
|
||||
} /* for */
|
||||
|
||||
|
@ -946,7 +1084,8 @@ int PHYSFS_setWriteDir(const char *newDir)
|
|||
|
||||
if (newDir != NULL)
|
||||
{
|
||||
writeDir = createDirHandle(newDir, NULL, 1);
|
||||
/* !!! FIXME: PHYSFS_Io shouldn't be NULL */
|
||||
writeDir = createDirHandle(NULL, newDir, NULL, 1);
|
||||
retval = (writeDir != NULL);
|
||||
} /* if */
|
||||
|
||||
|
@ -976,7 +1115,7 @@ int PHYSFS_mount(const char *newDir, const char *mountPoint, int appendToPath)
|
|||
prev = i;
|
||||
} /* for */
|
||||
|
||||
dh = createDirHandle(newDir, mountPoint, 0);
|
||||
dh = createDirHandle(NULL, newDir, mountPoint, 0);
|
||||
BAIL_IF_MACRO_MUTEX(dh == NULL, NULL, stateLock, 0);
|
||||
|
||||
if (appendToPath)
|
||||
|
@ -1735,7 +1874,7 @@ static PHYSFS_File *doOpenWrite(const char *_fname, int appending)
|
|||
|
||||
if (sanitizePlatformIndependentPath(_fname, fname))
|
||||
{
|
||||
void *opaque = NULL;
|
||||
PHYSFS_Io *io = NULL;
|
||||
DirHandle *h = NULL;
|
||||
const PHYSFS_Archiver *f;
|
||||
|
||||
|
@ -1748,24 +1887,23 @@ static PHYSFS_File *doOpenWrite(const char *_fname, int appending)
|
|||
|
||||
f = h->funcs;
|
||||
if (appending)
|
||||
opaque = f->openAppend(h->opaque, fname);
|
||||
io = f->openAppend(h->opaque, fname);
|
||||
else
|
||||
opaque = f->openWrite(h->opaque, fname);
|
||||
io = f->openWrite(h->opaque, fname);
|
||||
|
||||
GOTO_IF_MACRO(opaque == NULL, NULL, doOpenWriteEnd);
|
||||
GOTO_IF_MACRO(io == NULL, NULL, doOpenWriteEnd);
|
||||
|
||||
fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle));
|
||||
if (fh == NULL)
|
||||
{
|
||||
f->fileClose(opaque);
|
||||
io->destroy(io);
|
||||
GOTO_MACRO(ERR_OUT_OF_MEMORY, doOpenWriteEnd);
|
||||
} /* if */
|
||||
else
|
||||
{
|
||||
memset(fh, '\0', sizeof (FileHandle));
|
||||
fh->opaque = opaque;
|
||||
fh->io = io;
|
||||
fh->dirHandle = h;
|
||||
fh->funcs = h->funcs;
|
||||
fh->next = openWriteList;
|
||||
openWriteList = fh;
|
||||
} /* else */
|
||||
|
@ -1806,7 +1944,7 @@ PHYSFS_File *PHYSFS_openRead(const char *_fname)
|
|||
{
|
||||
int fileExists = 0;
|
||||
DirHandle *i = NULL;
|
||||
fvoid *opaque = NULL;
|
||||
PHYSFS_Io *io = NULL;
|
||||
|
||||
__PHYSFS_platformGrabMutex(stateLock);
|
||||
|
||||
|
@ -1820,28 +1958,27 @@ PHYSFS_File *PHYSFS_openRead(const char *_fname)
|
|||
char *arcfname = fname;
|
||||
if (verifyPath(i, &arcfname, 0))
|
||||
{
|
||||
opaque = i->funcs->openRead(i->opaque, arcfname, &fileExists);
|
||||
if (opaque)
|
||||
io = i->funcs->openRead(i->opaque, arcfname, &fileExists);
|
||||
if (io)
|
||||
break;
|
||||
} /* if */
|
||||
i = i->next;
|
||||
} while ((i != NULL) && (!fileExists));
|
||||
|
||||
/* !!! FIXME: may not set an error if openRead didn't fail. */
|
||||
GOTO_IF_MACRO(opaque == NULL, NULL, openReadEnd);
|
||||
GOTO_IF_MACRO(io == NULL, NULL, openReadEnd);
|
||||
|
||||
fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle));
|
||||
if (fh == NULL)
|
||||
{
|
||||
i->funcs->fileClose(opaque);
|
||||
io->destroy(io);
|
||||
GOTO_MACRO(ERR_OUT_OF_MEMORY, openReadEnd);
|
||||
} /* if */
|
||||
|
||||
memset(fh, '\0', sizeof (FileHandle));
|
||||
fh->opaque = opaque;
|
||||
fh->io = io;
|
||||
fh->forReading = 1;
|
||||
fh->dirHandle = i;
|
||||
fh->funcs = i->funcs;
|
||||
fh->next = openReadList;
|
||||
openReadList = fh;
|
||||
|
||||
|
@ -1864,12 +2001,12 @@ static int closeHandleInOpenList(FileHandle **list, FileHandle *handle)
|
|||
{
|
||||
if (i == handle) /* handle is in this list? */
|
||||
{
|
||||
PHYSFS_Io *io = handle->io;
|
||||
PHYSFS_uint8 *tmp = handle->buffer;
|
||||
rc = PHYSFS_flush((PHYSFS_File *) handle);
|
||||
if (rc)
|
||||
rc = handle->funcs->fileClose(handle->opaque);
|
||||
if (!rc)
|
||||
return -1;
|
||||
io->destroy(io);
|
||||
|
||||
if (tmp != NULL) /* free any associated buffer. */
|
||||
allocator.Free(tmp);
|
||||
|
@ -1914,6 +2051,7 @@ int PHYSFS_close(PHYSFS_File *_handle)
|
|||
static PHYSFS_sint64 doBufferedRead(FileHandle *fh, void *buffer,
|
||||
PHYSFS_uint64 len)
|
||||
{
|
||||
PHYSFS_Io *io = NULL;
|
||||
PHYSFS_sint64 retval = 0;
|
||||
PHYSFS_uint32 buffered = 0;
|
||||
PHYSFS_sint64 rc = 0;
|
||||
|
@ -1942,17 +2080,18 @@ static PHYSFS_sint64 doBufferedRead(FileHandle *fh, void *buffer,
|
|||
assert(buffered == 0);
|
||||
assert(len > 0);
|
||||
|
||||
io = fh->io;
|
||||
if (len >= fh->bufsize) /* need more than the buffer takes. */
|
||||
{
|
||||
/* leave buffer empty, go right to output instead. */
|
||||
rc = fh->funcs->read(fh->opaque, buffer, len);
|
||||
rc = io->read(io, buffer, len);
|
||||
if (rc < 0)
|
||||
return ((retval == 0) ? rc : retval);
|
||||
return retval + rc;
|
||||
} /* if */
|
||||
|
||||
/* need less than buffer can take. Fill buffer. */
|
||||
rc = fh->funcs->read(fh->opaque, fh->buffer, fh->bufsize);
|
||||
rc = io->read(io, fh->buffer, fh->bufsize);
|
||||
if (rc < 0)
|
||||
return ((retval == 0) ? rc : retval);
|
||||
|
||||
|
@ -1993,7 +2132,7 @@ PHYSFS_sint64 PHYSFS_readBytes(PHYSFS_File *handle, void *buffer,
|
|||
if (fh->buffer != NULL)
|
||||
return doBufferedRead(fh, buffer, len);
|
||||
|
||||
return fh->funcs->read(fh->opaque, buffer, len);
|
||||
return fh->io->read(fh->io, buffer, len);
|
||||
} /* PHYSFS_readBytes */
|
||||
|
||||
|
||||
|
@ -2012,7 +2151,7 @@ static PHYSFS_sint64 doBufferedWrite(PHYSFS_File *handle, const void *buffer,
|
|||
|
||||
/* would overflow buffer. Flush and then write the new objects, too. */
|
||||
BAIL_IF_MACRO(!PHYSFS_flush(handle), NULL, -1);
|
||||
return fh->funcs->write(fh->opaque, buffer, len);
|
||||
return fh->io->write(fh->io, buffer, len);
|
||||
} /* doBufferedWrite */
|
||||
|
||||
|
||||
|
@ -2043,7 +2182,7 @@ PHYSFS_sint64 PHYSFS_writeBytes(PHYSFS_File *handle, const void *buffer,
|
|||
if (fh->buffer != NULL)
|
||||
return doBufferedWrite(handle, buffer, len);
|
||||
|
||||
return fh->funcs->write(fh->opaque, buffer, len);
|
||||
return fh->io->write(fh->io, buffer, len);
|
||||
} /* PHYSFS_write */
|
||||
|
||||
|
||||
|
@ -2054,18 +2193,29 @@ int PHYSFS_eof(PHYSFS_File *handle)
|
|||
if (!fh->forReading) /* never EOF on files opened for write/append. */
|
||||
return 0;
|
||||
|
||||
/* eof if buffer is empty and archiver says so. */
|
||||
return (fh->bufpos == fh->buffill && (fh->funcs->eof(fh->opaque)));
|
||||
/* can't be eof if buffer isn't empty */
|
||||
if (fh->bufpos == fh->buffill)
|
||||
{
|
||||
/* check the Io. */
|
||||
PHYSFS_Io *io = fh->io;
|
||||
const PHYSFS_sint64 pos = io->tell(io);
|
||||
const PHYSFS_sint64 len = io->length(io);
|
||||
if ((pos < 0) || (len < 0))
|
||||
return 0; /* beats me. */
|
||||
return (pos >= len);
|
||||
} /* if */
|
||||
|
||||
return 0;
|
||||
} /* PHYSFS_eof */
|
||||
|
||||
|
||||
PHYSFS_sint64 PHYSFS_tell(PHYSFS_File *handle)
|
||||
{
|
||||
FileHandle *fh = (FileHandle *) handle;
|
||||
PHYSFS_sint64 pos = fh->funcs->tell(fh->opaque);
|
||||
PHYSFS_sint64 retval = fh->forReading ?
|
||||
(pos - fh->buffill) + fh->bufpos :
|
||||
(pos + fh->buffill);
|
||||
const PHYSFS_sint64 pos = fh->io->tell(fh->io);
|
||||
const PHYSFS_sint64 retval = fh->forReading ?
|
||||
(pos - fh->buffill) + fh->bufpos :
|
||||
(pos + fh->buffill);
|
||||
return retval;
|
||||
} /* PHYSFS_tell */
|
||||
|
||||
|
@ -2090,14 +2240,14 @@ int PHYSFS_seek(PHYSFS_File *handle, PHYSFS_uint64 pos)
|
|||
|
||||
/* we have to fall back to a 'raw' seek. */
|
||||
fh->buffill = fh->bufpos = 0;
|
||||
return fh->funcs->seek(fh->opaque, pos);
|
||||
return fh->io->seek(fh->io, pos);
|
||||
} /* PHYSFS_seek */
|
||||
|
||||
|
||||
PHYSFS_sint64 PHYSFS_fileLength(PHYSFS_File *handle)
|
||||
{
|
||||
FileHandle *fh = (FileHandle *) handle;
|
||||
return fh->funcs->fileLength(fh->opaque);
|
||||
PHYSFS_Io *io = ((FileHandle *) handle)->io;
|
||||
return io->length(io);
|
||||
} /* PHYSFS_filelength */
|
||||
|
||||
|
||||
|
@ -2121,10 +2271,10 @@ int PHYSFS_setBuffer(PHYSFS_File *handle, PHYSFS_uint64 _bufsize)
|
|||
if ((fh->forReading) && (fh->buffill != fh->bufpos))
|
||||
{
|
||||
PHYSFS_uint64 pos;
|
||||
PHYSFS_sint64 curpos = fh->funcs->tell(fh->opaque);
|
||||
const PHYSFS_sint64 curpos = fh->io->tell(fh->io);
|
||||
BAIL_IF_MACRO(curpos == -1, NULL, 0);
|
||||
pos = ((curpos - fh->buffill) + fh->bufpos);
|
||||
BAIL_IF_MACRO(!fh->funcs->seek(fh->opaque, pos), NULL, 0);
|
||||
BAIL_IF_MACRO(!fh->io->seek(fh->io, pos), NULL, 0);
|
||||
} /* if */
|
||||
|
||||
if (bufsize == 0) /* delete existing buffer. */
|
||||
|
@ -2153,17 +2303,18 @@ int PHYSFS_setBuffer(PHYSFS_File *handle, PHYSFS_uint64 _bufsize)
|
|||
int PHYSFS_flush(PHYSFS_File *handle)
|
||||
{
|
||||
FileHandle *fh = (FileHandle *) handle;
|
||||
PHYSFS_Io *io;
|
||||
PHYSFS_sint64 rc;
|
||||
|
||||
if ((fh->forReading) || (fh->bufpos == fh->buffill))
|
||||
return 1; /* open for read or buffer empty are successful no-ops. */
|
||||
|
||||
/* dump buffer to disk. */
|
||||
rc = fh->funcs->write(fh->opaque, fh->buffer + fh->bufpos,
|
||||
fh->buffill - fh->bufpos);
|
||||
io = fh->io;
|
||||
rc = io->write(io, fh->buffer + fh->bufpos, fh->buffill - fh->bufpos);
|
||||
BAIL_IF_MACRO(rc <= 0, NULL, 0);
|
||||
fh->bufpos = fh->buffill = 0;
|
||||
return 1;
|
||||
return io->flush(io);
|
||||
} /* PHYSFS_flush */
|
||||
|
||||
|
||||
|
|
191
src/physfs.h
191
src/physfs.h
|
@ -1262,7 +1262,7 @@ PHYSFS_DECL int PHYSFS_close(PHYSFS_File *handle);
|
|||
* function just wraps it anyhow. This function never clarified
|
||||
* what would happen if you managed to read a partial object, so
|
||||
* working at the byte level makes this cleaner for everyone,
|
||||
* especially now that data streams can be supplied by the
|
||||
* especially now that PHYSFS_Io interfaces can be supplied by the
|
||||
* application.
|
||||
*
|
||||
* \param handle handle returned from PHYSFS_openRead().
|
||||
|
@ -1292,7 +1292,7 @@ PHYSFS_DECL PHYSFS_sint64 PHYSFS_read(PHYSFS_File *handle,
|
|||
* function just wraps it anyhow. This function never clarified
|
||||
* what would happen if you managed to write a partial object, so
|
||||
* working at the byte level makes this cleaner for everyone,
|
||||
* especially now that data streams can be supplied by the
|
||||
* especially now that PHYSFS_Io interfaces can be supplied by the
|
||||
* application.
|
||||
*
|
||||
* \param handle retval from PHYSFS_openWrite() or PHYSFS_openAppend().
|
||||
|
@ -1362,11 +1362,9 @@ PHYSFS_DECL int PHYSFS_seek(PHYSFS_File *handle, PHYSFS_uint64 pos);
|
|||
* \fn PHYSFS_sint64 PHYSFS_fileLength(PHYSFS_File *handle)
|
||||
* \brief Get total length of a file in bytes.
|
||||
*
|
||||
* Note that if the file size can't be determined (since the archive is
|
||||
* "streamed" or whatnot) than this will report (-1). Also note that if
|
||||
* another process/thread is writing to this file at the same time, then
|
||||
* the information this function supplies could be incorrect before you
|
||||
* get it. Use with caution, or better yet, don't use at all.
|
||||
* Note that if another process/thread is writing to this file at the same
|
||||
* time, then the information this function supplies could be incorrect
|
||||
* before you get it. Use with caution, or better yet, don't use at all.
|
||||
*
|
||||
* \param handle handle returned from PHYSFS_open*().
|
||||
* \return size in bytes of the file. -1 if can't be determined.
|
||||
|
@ -2149,6 +2147,7 @@ PHYSFS_DECL int PHYSFS_setAllocator(const PHYSFS_Allocator *allocator);
|
|||
* \sa PHYSFS_removeFromSearchPath
|
||||
* \sa PHYSFS_getSearchPath
|
||||
* \sa PHYSFS_getMountPoint
|
||||
* \sa PHYSFS_mountIo
|
||||
*/
|
||||
PHYSFS_DECL int PHYSFS_mount(const char *newDir,
|
||||
const char *mountPoint,
|
||||
|
@ -2719,6 +2718,184 @@ PHYSFS_DECL PHYSFS_sint64 PHYSFS_writeBytes(PHYSFS_File *handle,
|
|||
PHYSFS_uint64 len);
|
||||
|
||||
|
||||
/**
|
||||
* \struct PHYSFS_Io
|
||||
* \brief An abstract i/o interface.
|
||||
*
|
||||
* \warning This is advanced, hardcore stuff. You don't need this unless you
|
||||
* really know what you're doing. Most apps will not need this.
|
||||
*
|
||||
* Historically, PhysicsFS provided access to the physical filesystem and
|
||||
* archives within that filesystem. However, sometimes you need more power
|
||||
* than this. Perhaps you need to provide an archive that is entirely
|
||||
* contained in RAM, or you need to brige some other file i/o API to
|
||||
* PhysicsFS, or you need to translate the bits (perhaps you have a
|
||||
* a standard .zip file that's encrypted, and you need to decrypt on the fly
|
||||
* for the unsuspecting zip archiver).
|
||||
*
|
||||
* A PHYSFS_Io is the interface that Archivers use to get archive data.
|
||||
* Historically, this has mapped to file i/o to the physical filesystem, but
|
||||
* as of PhysicsFS 2.1, applications can provide their own i/o implementations
|
||||
* at runtime.
|
||||
*
|
||||
* This interface isn't necessarily a good universal fit for i/o. There are a
|
||||
* few requirements of note:
|
||||
*
|
||||
* - They only do blocking i/o (at least, for now).
|
||||
* - They need to be able to duplicate. If you have a file handle from
|
||||
* fopen(), you need to be able to create a unique clone of it (so we
|
||||
* have two handles to the same file that can both seek/read/etc without
|
||||
* stepping on each other).
|
||||
* - They need to know the size of their entire data set.
|
||||
* - They need to be able to seek and rewind on demand.
|
||||
*
|
||||
* ...in short, you're probably not going to write an HTTP implementation.
|
||||
*
|
||||
* Thread safety: TO BE DECIDED. !!! FIXME
|
||||
*
|
||||
* \sa PHYSFS_mountIo
|
||||
*/
|
||||
typedef struct PHYSFS_Io
|
||||
{
|
||||
/**
|
||||
* \brief Read more data.
|
||||
*
|
||||
* Read (len) bytes from the interface, at the current i/o position, and
|
||||
* store them in (buffer). The current i/o position should move ahead
|
||||
* by the number of bytes successfully read.
|
||||
*
|
||||
* You don't have to implement this; set it to NULL if not implemented.
|
||||
* This will only be used if the file is opened for reading. If set to
|
||||
* NULL, a default implementation that immediately reports failure will
|
||||
* be used.
|
||||
*
|
||||
* \param io The i/o instance to read from.
|
||||
* \param buf The buffer to store data into. It must be at least
|
||||
* (len) bytes long and can't be NULL.
|
||||
* \param len The number of bytes to read from the interface.
|
||||
* \return number of bytes read from file, 0 on EOF, -1 if complete
|
||||
* failure.
|
||||
*/
|
||||
PHYSFS_sint64 (*read)(struct PHYSFS_Io *io, void *buf, PHYSFS_uint64 len);
|
||||
|
||||
/**
|
||||
* \brief Write more data.
|
||||
*
|
||||
* Write (len) bytes from (buffer) to the interface at the current i/o
|
||||
* position. The current i/o position should move ahead by the number of
|
||||
* bytes successfully written.
|
||||
*
|
||||
* You don't have to implement this; set it to NULL if not implemented.
|
||||
* This will only be used if the file is opened for writing. If set to
|
||||
* NULL, a default implementation that immediately reports failure will
|
||||
* be used.
|
||||
*
|
||||
* You are allowed to buffer; a write can succeed here and then later
|
||||
* fail when flushing. Note that PHYSFS_setBuffer() may be operating a
|
||||
* level above your i/o, so you should usually not implement your
|
||||
* own buffering routines.
|
||||
*
|
||||
* \param io The i/o instance to write to.
|
||||
* \param buffer The buffer to read data from. It must be at least
|
||||
* (len) bytes long and can't be NULL.
|
||||
* \param len The number of bytes to read from (buffer).
|
||||
* \return number of bytes written to file, -1 if complete failure.
|
||||
*/
|
||||
PHYSFS_sint64 (*write)(struct PHYSFS_Io *io, const void *buffer,
|
||||
PHYSFS_uint64 len);
|
||||
|
||||
/**
|
||||
* \brief Move i/o position to a given byte offset from start.
|
||||
*
|
||||
* This method moves the i/o position, so the next read/write will
|
||||
* be of the byte at (offset) offset. Seeks past the end of file should
|
||||
* be treated as an error condition.
|
||||
*
|
||||
* \param io The i/o instance to seek.
|
||||
* \param offset The new byte offset for the i/o position.
|
||||
* \return non-zero on success, zero on error.
|
||||
*/
|
||||
int (*seek)(struct PHYSFS_Io *io, PHYSFS_uint64 offset);
|
||||
|
||||
/**
|
||||
* \brief Report current i/o position.
|
||||
*
|
||||
* Return bytes offset, or -1 if you aren't able to determine. A failure
|
||||
* will almost certainly be fatal to further use of this stream, so you
|
||||
* may not leave this unimplemented.
|
||||
*
|
||||
* \param io The i/o instance to query.
|
||||
* \return The current byte offset for the i/o position, -1 if unknown.
|
||||
*/
|
||||
PHYSFS_sint64 (*tell)(struct PHYSFS_Io *io);
|
||||
|
||||
/**
|
||||
* \brief Determine size of the i/o instance's dataset.
|
||||
*
|
||||
* Return number of bytes available in the file, or -1 if you
|
||||
* aren't able to determine. A failure will almost certainly be fatal
|
||||
* to further use of this stream, so you may not leave this unimplemented.
|
||||
*
|
||||
* \param io The i/o instance to query.
|
||||
* \return Total size, in bytes, of the dataset.
|
||||
*/
|
||||
PHYSFS_sint64 (*length)(struct PHYSFS_Io *io);
|
||||
|
||||
/**
|
||||
* \brief Duplicate this i/o instance.
|
||||
*
|
||||
* // !!! FIXME: write me.
|
||||
*
|
||||
* \param io The i/o instance to duplicate.
|
||||
* \return A new value for a stream's (opaque) field, or NULL on error.
|
||||
*/
|
||||
struct PHYSFS_Io *(*duplicate)(struct PHYSFS_Io *io);
|
||||
|
||||
/**
|
||||
* \brief Flush resources to media, or wherever.
|
||||
*
|
||||
* This is the chance to report failure for writes that had claimed
|
||||
* success earlier, but still had a chance to actually fail. This method
|
||||
* can be NULL if flushing isn't necessary.
|
||||
*
|
||||
* This function may be called before destroy(), as it can report failure
|
||||
* and destroy() can not. It may be called at other times, too.
|
||||
*
|
||||
* \param io The i/o instance to flush.
|
||||
* \return Zero on error, non-zero on success.
|
||||
*/
|
||||
int (*flush)(struct PHYSFS_Io *io);
|
||||
|
||||
/**
|
||||
* \brief Cleanup and deallocate i/o instance.
|
||||
*
|
||||
* Free associated resources, including (opaque) if applicable.
|
||||
*
|
||||
* This function must always succeed: as such, it returns void. The
|
||||
* system may call your flush() method before this. You may report
|
||||
* failure there if necessary. This method may still be called if
|
||||
* flush() fails, in which case you'll have to abandon unflushed data
|
||||
* and other failing conditions and clean up.
|
||||
*
|
||||
* Once this method is called for a given instance, the system will assume
|
||||
* it is unsafe to touch that instance again and will discard any
|
||||
* references to it.
|
||||
*
|
||||
* \param s The i/o instance to destroy.
|
||||
*/
|
||||
void (*destroy)(struct PHYSFS_Io *io);
|
||||
|
||||
/**
|
||||
* \brief Instance data for this struct.
|
||||
*
|
||||
* Each instance has a pointer associated with it that can be used to
|
||||
* store anything it likes. This pointer is per-instance of the stream,
|
||||
* so presumably it will change when calling duplicate(). This can be
|
||||
* deallocated during the destroy() method.
|
||||
*/
|
||||
void *opaque;
|
||||
} PHYSFS_Io;
|
||||
|
||||
/* Everything above this line is part of the PhysicsFS 2.1 API. */
|
||||
|
||||
|
||||
|
|
|
@ -711,14 +711,10 @@ void __PHYSFS_smallFree(void *ptr);
|
|||
|
||||
/* end LANG section. */
|
||||
|
||||
struct __PHYSFS_DIRHANDLE__;
|
||||
struct __PHYSFS_FILEFUNCTIONS__;
|
||||
|
||||
|
||||
/* !!! FIXME: find something better than "dvoid" and "fvoid" ... */
|
||||
/* Opaque data for file and dir handlers... */
|
||||
typedef void dvoid;
|
||||
typedef void fvoid;
|
||||
|
||||
|
||||
typedef struct
|
||||
|
@ -741,16 +737,18 @@ typedef struct
|
|||
*/
|
||||
|
||||
/*
|
||||
* Open a dirhandle for dir/archive (name).
|
||||
* This filename is in platform-dependent notation.
|
||||
* forWriting is non-zero if this is to be used for
|
||||
* Open a dirhandle for dir/archive data provided by (io).
|
||||
* (name) is a filename associated with (io), but doesn't necessarily
|
||||
* map to anything, let alone a real filename. This possibly-
|
||||
* meaningless name is in platform-dependent notation.
|
||||
* (forWriting) is non-zero if this is to be used for
|
||||
* the write directory, and zero if this is to be used for an
|
||||
* element of the search path.
|
||||
* Returns NULL on failure, and calls __PHYSFS_setError().
|
||||
* Returns non-NULL on success. The pointer returned will be
|
||||
* passed as the "opaque" parameter for later calls.
|
||||
*/
|
||||
void *(*openArchive)(const char *name, int forWriting);
|
||||
dvoid *(*openArchive)(PHYSFS_Io *io, const char *name, int forWriting);
|
||||
|
||||
/*
|
||||
* List all files in (dirname). Each file is passed to (callback),
|
||||
|
@ -810,7 +808,7 @@ typedef struct
|
|||
* non-zero if the file existed (even if it's a broken symlink!),
|
||||
* zero if it did not.
|
||||
*/
|
||||
fvoid *(*openRead)(dvoid *opaque, const char *fname, int *fileExists);
|
||||
PHYSFS_Io *(*openRead)(dvoid *opaque, const char *fname, int *fileExists);
|
||||
|
||||
/*
|
||||
* Open file for writing.
|
||||
|
@ -824,7 +822,7 @@ typedef struct
|
|||
* Returns non-NULL on success. The pointer returned will be
|
||||
* passed as the "opaque" parameter for later file calls.
|
||||
*/
|
||||
fvoid *(*openWrite)(dvoid *opaque, const char *filename);
|
||||
PHYSFS_Io *(*openWrite)(dvoid *opaque, const char *filename);
|
||||
|
||||
/*
|
||||
* Open file for appending.
|
||||
|
@ -837,7 +835,7 @@ typedef struct
|
|||
* Returns non-NULL on success. The pointer returned will be
|
||||
* passed as the "opaque" parameter for later file calls.
|
||||
*/
|
||||
fvoid *(*openAppend)(dvoid *opaque, const char *filename);
|
||||
PHYSFS_Io *(*openAppend)(dvoid *opaque, const char *filename);
|
||||
|
||||
/*
|
||||
* Delete a file in the archive/directory.
|
||||
|
@ -862,9 +860,9 @@ typedef struct
|
|||
|
||||
/*
|
||||
* Close directories/archives, and free any associated memory,
|
||||
* including (opaque) itself if applicable. Implementation can assume
|
||||
* that it won't be called if there are still files open from
|
||||
* this archive.
|
||||
* including the original PHYSFS_Io and (opaque) itself, if
|
||||
* applicable. Implementation can assume that it won't be called if
|
||||
* there are still files open from this archive.
|
||||
*/
|
||||
void (*dirClose)(dvoid *opaque);
|
||||
|
||||
|
@ -874,60 +872,6 @@ typedef struct
|
|||
* On failure, call __PHYSFS_setError().
|
||||
*/
|
||||
int (*stat)(dvoid *opaque, const char *fn, int *exists, PHYSFS_Stat *stat);
|
||||
|
||||
|
||||
/*
|
||||
* FILE ROUTINES:
|
||||
* These functions are for file handles generated by the open*() methods.
|
||||
* They are distinguished by taking a "fvoid" instead of a "dvoid" for
|
||||
* the opaque handle.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Read (len) bytes from the file.
|
||||
* Returns number of bytes read from file, -1 if complete failure.
|
||||
* On failure, call __PHYSFS_setError().
|
||||
*/
|
||||
PHYSFS_sint64 (*read)(fvoid *opaque, void *buffer, PHYSFS_uint64 len);
|
||||
|
||||
/*
|
||||
* Write (len) bytes to the file. Archives don't have to implement
|
||||
* this; set it to NULL if not implemented.
|
||||
* Returns number of bytes written to file, -1 if complete failure.
|
||||
* On failure, call __PHYSFS_setError().
|
||||
*/
|
||||
PHYSFS_sint64 (*write)(fvoid *opaque, const void *buf, PHYSFS_uint64 len);
|
||||
|
||||
/*
|
||||
* Returns non-zero if at end of file.
|
||||
*/
|
||||
int (*eof)(fvoid *opaque);
|
||||
|
||||
/*
|
||||
* Returns byte offset from start of file.
|
||||
*/
|
||||
PHYSFS_sint64 (*tell)(fvoid *opaque);
|
||||
|
||||
/*
|
||||
* Move read/write pointer to byte offset from start of file.
|
||||
* Returns non-zero on success, zero on error.
|
||||
* On failure, call __PHYSFS_setError().
|
||||
*/
|
||||
int (*seek)(fvoid *opaque, PHYSFS_uint64 offset);
|
||||
|
||||
/*
|
||||
* Return number of bytes available in the file, or -1 if you
|
||||
* aren't able to determine.
|
||||
* On failure, call __PHYSFS_setError().
|
||||
*/
|
||||
PHYSFS_sint64 (*fileLength)(fvoid *opaque);
|
||||
|
||||
/*
|
||||
* Close the file, and free associated resources, including (opaque)
|
||||
* if applicable. Returns non-zero on success, zero if can't close
|
||||
* file. On failure, call __PHYSFS_setError().
|
||||
*/
|
||||
int (*fileClose)(fvoid *opaque);
|
||||
} PHYSFS_Archiver;
|
||||
|
||||
|
||||
|
@ -1082,6 +1026,14 @@ extern PHYSFS_Allocator __PHYSFS_AllocatorHooks;
|
|||
/* convenience macro to make this less cumbersome internally... */
|
||||
#define allocator __PHYSFS_AllocatorHooks
|
||||
|
||||
/*
|
||||
* Create a PHYSFS_Io for a file in the physical filesystem.
|
||||
* This path is in platform-dependent notation. (mode) must be 'r', 'w', or
|
||||
* 'a' for Read, Write, or Append.
|
||||
*/
|
||||
PHYSFS_Io *__PHYSFS_createNativeIo(const char *path, const int mode);
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/*------------ ----------------*/
|
||||
|
@ -1172,7 +1124,6 @@ void *__PHYSFS_platformOpenWrite(const char *filename);
|
|||
*/
|
||||
void *__PHYSFS_platformOpenAppend(const char *filename);
|
||||
|
||||
|
||||
/*
|
||||
* Read more data from a platform-specific file handle. (opaque) should be
|
||||
* cast to whatever data type your platform uses. Read a maximum of (len)
|
||||
|
@ -1267,16 +1218,14 @@ int __PHYSFS_platformEOF(void *opaque);
|
|||
int __PHYSFS_platformFlush(void *opaque);
|
||||
|
||||
/*
|
||||
* Flush and close a file. (opaque) should be cast to whatever data type
|
||||
* your platform uses. Be sure to check for errors when closing; the
|
||||
* caller expects that this function can fail if there was a flushing
|
||||
* error, etc.
|
||||
* Close file and deallocate resources. (opaque) should be cast to whatever
|
||||
* data type your platform uses. This should close the file in any scenario:
|
||||
* flushing is a separate function call, and this function should never fail.
|
||||
*
|
||||
* You should clean up all resources associated with (opaque).
|
||||
*
|
||||
* Return zero on failure, non-zero on success.
|
||||
* You should clean up all resources associated with (opaque); the pointer
|
||||
* will be considered invalid after this call.
|
||||
*/
|
||||
int __PHYSFS_platformClose(void *opaque);
|
||||
void __PHYSFS_platformClose(void *opaque);
|
||||
|
||||
/*
|
||||
* Platform implementation of PHYSFS_getCdRomDirsCallback()...
|
||||
|
@ -1331,7 +1280,6 @@ int __PHYSFS_platformExists(const char *fname);
|
|||
*/
|
||||
int __PHYSFS_platformIsSymLink(const char *fname);
|
||||
|
||||
|
||||
/*
|
||||
* Return non-zero if filename (in platform-dependent notation) is a symlink.
|
||||
* Symlinks should be followed; if what the symlink points to is missing,
|
||||
|
|
|
@ -590,9 +590,9 @@ int __PHYSFS_platformFlush(void *opaque)
|
|||
} /* __PHYSFS_platformFlush */
|
||||
|
||||
|
||||
int __PHYSFS_platformClose(void *opaque)
|
||||
void __PHYSFS_platformClose(void *opaque)
|
||||
{
|
||||
return (os2err(DosClose((HFILE) opaque)) == NO_ERROR);
|
||||
DosClose((HFILE) opaque); /* ignore errors. You should have flushed! */
|
||||
} /* __PHYSFS_platformClose */
|
||||
|
||||
|
||||
|
|
|
@ -506,12 +506,11 @@ int __PHYSFS_platformFlush(void *opaque)
|
|||
} /* __PHYSFS_platformFlush */
|
||||
|
||||
|
||||
int __PHYSFS_platformClose(void *opaque)
|
||||
void __PHYSFS_platformClose(void *opaque)
|
||||
{
|
||||
HANDLE Handle = ((winCEfile *) opaque)->handle;
|
||||
BAIL_IF_MACRO(!CloseHandle(Handle), win32strerror(), 0);
|
||||
(void) CloseHandle(Handle); /* ignore errors. You should have flushed! */
|
||||
allocator.Free(opaque);
|
||||
return 1;
|
||||
} /* __PHYSFS_platformClose */
|
||||
|
||||
|
||||
|
|
|
@ -393,12 +393,11 @@ int __PHYSFS_platformFlush(void *opaque)
|
|||
} /* __PHYSFS_platformFlush */
|
||||
|
||||
|
||||
int __PHYSFS_platformClose(void *opaque)
|
||||
void __PHYSFS_platformClose(void *opaque)
|
||||
{
|
||||
int fd = *((int *) opaque);
|
||||
BAIL_IF_MACRO(close(fd) == -1, strerror(errno), 0);
|
||||
const int fd = *((int *) opaque);
|
||||
(void) close(fd); /* we don't check this. You should have used flush! */
|
||||
allocator.Free(opaque);
|
||||
return 1;
|
||||
} /* __PHYSFS_platformClose */
|
||||
|
||||
|
||||
|
|
|
@ -1182,12 +1182,11 @@ int __PHYSFS_platformFlush(void *opaque)
|
|||
} /* __PHYSFS_platformFlush */
|
||||
|
||||
|
||||
int __PHYSFS_platformClose(void *opaque)
|
||||
void __PHYSFS_platformClose(void *opaque)
|
||||
{
|
||||
HANDLE Handle = ((WinApiFile *) opaque)->handle;
|
||||
BAIL_IF_MACRO(!CloseHandle(Handle), winApiStrError(), 0);
|
||||
(void) CloseHandle(Handle); /* ignore errors. You should have flushed! */
|
||||
allocator.Free(opaque);
|
||||
return 1;
|
||||
} /* __PHYSFS_platformClose */
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue