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:
Ryan C. Gordon 2010-08-30 03:01:57 -04:00
parent c2e77d7e35
commit 4bc5ed1725
16 changed files with 1577 additions and 1388 deletions

View File

@ -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 ... */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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, &cent_dir_ofs))
goto zip_openarchive_failed;
if (!zip_parse_end_of_central_dir(io, info, &data_start, &cent_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 */

View File

@ -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 */

View File

@ -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. */

View File

@ -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,

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */