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__ #define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h" #include "physfs_internal.h"
static PHYSFS_sint64 DIR_read(fvoid *opaque, void *buffer, PHYSFS_uint64 len) /* There's no PHYSFS_Io interface here. Use __PHYSFS_createNativeIo(). */
{
return __PHYSFS_platformRead(opaque, buffer, len);
} /* DIR_read */
static void *DIR_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
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)
{ {
const char *dirsep = PHYSFS_getDirSeparator(); const char *dirsep = PHYSFS_getDirSeparator();
char *retval = NULL; char *retval = NULL;
size_t namelen = strlen(name); const size_t namelen = strlen(name);
size_t seplen = strlen(dirsep); 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); BAIL_IF_MACRO(!__PHYSFS_platformIsDirectory(name), ERR_NOT_AN_ARCHIVE, NULL);
retval = allocator.Malloc(namelen + seplen + 1); retval = allocator.Malloc(namelen + seplen + 1);
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL); 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); strcpy(retval, name);
if (strcmp((name + namelen) - seplen, dirsep) != 0) if (strcmp((name + namelen) - seplen, dirsep) != 0)
strcat(retval, dirsep); strcat(retval, dirsep);
@ -84,11 +39,13 @@ static void *DIR_openArchive(const char *name, int forWriting)
} /* DIR_openArchive */ } /* DIR_openArchive */
/* !!! FIXME: I would like to smallAlloc() all these conversions somehow. */
static void DIR_enumerateFiles(dvoid *opaque, const char *dname, static void DIR_enumerateFiles(dvoid *opaque, const char *dname,
int omitSymLinks, PHYSFS_EnumFilesCallback cb, int omitSymLinks, PHYSFS_EnumFilesCallback cb,
const char *origdir, void *callbackdata) const char *origdir, void *callbackdata)
{ {
char *d = __PHYSFS_platformCvtToDependent((char *)opaque, dname, NULL); char *d = __PHYSFS_platformCvtToDependent((char *) opaque, dname, NULL);
if (d != NULL) if (d != NULL)
{ {
__PHYSFS_platformEnumerateFiles(d, omitSymLinks, cb, __PHYSFS_platformEnumerateFiles(d, omitSymLinks, cb,
@ -138,47 +95,48 @@ static int DIR_isSymLink(dvoid *opaque, const char *name, int *fileExists)
} /* DIR_isSymLink */ } /* DIR_isSymLink */
static fvoid *doOpen(dvoid *opaque, const char *name, static PHYSFS_Io *doOpen(dvoid *opaque, const char *name,
void *(*openFunc)(const char *filename), const int mode, int *fileExists)
int *fileExists)
{ {
char *f = __PHYSFS_platformCvtToDependent((char *) opaque, name, NULL); 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); 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); *fileExists = __PHYSFS_platformExists(f);
if (!(*fileExists)) return NULL;
{
allocator.Free(f);
return NULL;
} /* if */
} /* if */ } /* if */
rc = openFunc(f); *fileExists = 1;
allocator.Free(f); return io;
return ((fvoid *) rc);
} /* doOpen */ } /* 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 */ } /* 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 */ } /* 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 */ } /* DIR_openAppend */
@ -248,14 +206,7 @@ const PHYSFS_Archiver __PHYSFS_Archiver_DIR =
DIR_remove, /* remove() method */ DIR_remove, /* remove() method */
DIR_mkdir, /* mkdir() method */ DIR_mkdir, /* mkdir() method */
DIR_dirClose, /* dirClose() method */ DIR_dirClose, /* dirClose() method */
DIR_stat, /* stat() 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 */
}; };
/* end of dir.c ... */ /* end of dir.c ... */

View File

@ -43,37 +43,37 @@ typedef struct
typedef struct typedef struct
{ {
char *filename; PHYSFS_Io *io;
PHYSFS_uint32 entryCount; PHYSFS_uint32 entryCount;
GRPentry *entries; GRPentry *entries;
} GRPinfo; } GRPinfo;
typedef struct typedef struct
{ {
void *handle; PHYSFS_Io *io;
GRPentry *entry; GRPentry *entry;
PHYSFS_uint32 curPos; PHYSFS_uint32 curPos;
} GRPfileinfo; } 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 */ } /* readAll */
static void GRP_dirClose(dvoid *opaque) static void GRP_dirClose(dvoid *opaque)
{ {
GRPinfo *info = ((GRPinfo *) opaque); GRPinfo *info = ((GRPinfo *) opaque);
allocator.Free(info->filename); info->io->destroy(info->io);
allocator.Free(info->entries); allocator.Free(info->entries);
allocator.Free(info); allocator.Free(info);
} /* GRP_dirClose */ } /* 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 GRPentry *entry = finfo->entry;
const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos); const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos);
PHYSFS_sint64 rc; PHYSFS_sint64 rc;
@ -81,7 +81,7 @@ static PHYSFS_sint64 GRP_read(fvoid *opaque, void *buffer, PHYSFS_uint64 len)
if (bytesLeft < len) if (bytesLeft < len)
len = bytesLeft; len = bytesLeft;
rc = __PHYSFS_platformRead(finfo->handle, buffer, len); rc = finfo->io->read(finfo->io, buffer, len);
if (rc > 0) if (rc > 0)
finfo->curPos += (PHYSFS_uint32) rc; finfo->curPos += (PHYSFS_uint32) rc;
@ -89,35 +89,26 @@ static PHYSFS_sint64 GRP_read(fvoid *opaque, void *buffer, PHYSFS_uint64 len)
} /* GRP_read */ } /* 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); BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
} /* GRP_write */ } /* GRP_write */
static int GRP_eof(fvoid *opaque) static PHYSFS_sint64 GRP_tell(PHYSFS_Io *io)
{ {
GRPfileinfo *finfo = (GRPfileinfo *) opaque; return ((GRPfileinfo *) io->opaque)->curPos;
GRPentry *entry = finfo->entry;
return (finfo->curPos >= entry->size);
} /* GRP_eof */
static PHYSFS_sint64 GRP_tell(fvoid *opaque)
{
return ((GRPfileinfo *) opaque)->curPos;
} /* GRP_tell */ } /* 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; GRPfileinfo *finfo = (GRPfileinfo *) io->opaque;
GRPentry *entry = finfo->entry; const GRPentry *entry = finfo->entry;
int rc; int rc;
BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 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) if (rc)
finfo->curPos = (PHYSFS_uint32) offset; finfo->curPos = (PHYSFS_uint32) offset;
@ -125,72 +116,77 @@ static int GRP_seek(fvoid *opaque, PHYSFS_uint64 offset)
} /* GRP_seek */ } /* 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); 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; GRPfileinfo *origfinfo = (GRPfileinfo *) _io->opaque;
BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0); PHYSFS_Io *io = NULL;
PHYSFS_Io *retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
GRPfileinfo *finfo = (GRPfileinfo *) allocator.Malloc(sizeof (GRPfileinfo));
GOTO_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, GRP_duplicate_failed);
GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, GRP_duplicate_failed);
io = origfinfo->io->duplicate(origfinfo->io);
GOTO_IF_MACRO(io == NULL, NULL, GRP_duplicate_failed);
finfo->io = io;
finfo->entry = origfinfo->entry;
finfo->curPos = 0;
memcpy(retval, _io, sizeof (PHYSFS_Io));
retval->opaque = finfo;
return retval;
GRP_duplicate_failed:
if (finfo != NULL) allocator.Free(finfo);
if (retval != NULL) allocator.Free(retval);
if (io != NULL) io->destroy(io);
return NULL;
} /* GRP_duplicate */
static int GRP_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
static void GRP_destroy(PHYSFS_Io *io)
{
GRPfileinfo *finfo = (GRPfileinfo *) io->opaque;
finfo->io->destroy(finfo->io);
allocator.Free(finfo); allocator.Free(finfo);
return 1; allocator.Free(io);
} /* GRP_fileClose */ } /* GRP_destroy */
static int grp_open(const char *filename, int forWriting, static const PHYSFS_Io GRP_Io =
void **fh, PHYSFS_uint32 *count)
{ {
PHYSFS_uint8 buf[12]; GRP_read,
GRP_write,
*fh = NULL; GRP_seek,
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0); GRP_tell,
GRP_length,
*fh = __PHYSFS_platformOpenRead(filename); GRP_duplicate,
BAIL_IF_MACRO(*fh == NULL, NULL, 0); GRP_flush,
GRP_destroy,
if (!readAll(*fh, buf, 12)) NULL
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 */
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) if (one != two)
{ {
const GRPentry *a = (const GRPentry *) _a; const GRPentry *a = (const GRPentry *) _a;
return (strcmp(a[one].name, a[two].name)); return __PHYSFS_stricmpASCII(a[one].name, a[two].name);
} /* if */ } /* if */
return 0; 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) 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(first, second, sizeof (GRPentry));
memcpy(second, &tmp, sizeof (GRPentry)); memcpy(second, &tmp, sizeof (GRPentry));
} /* if */ } /* 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 = info->entryCount;
PHYSFS_uint32 fileCount;
PHYSFS_uint32 location = 16; /* sizeof sig. */ PHYSFS_uint32 location = 16; /* sizeof sig. */
GRPentry *entry; GRPentry *entry;
char *ptr; char *ptr;
BAIL_IF_MACRO(!grp_open(name, forWriting, &fh, &fileCount), NULL, 0);
info->entryCount = fileCount;
info->entries = (GRPentry *) allocator.Malloc(sizeof(GRPentry)*fileCount); info->entries = (GRPentry *) allocator.Malloc(sizeof(GRPentry)*fileCount);
if (info->entries == NULL) BAIL_IF_MACRO(info->entries == NULL, ERR_OUT_OF_MEMORY, 0);
{
__PHYSFS_platformClose(fh);
BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
} /* if */
location += (16 * fileCount); location += (16 * fileCount);
for (entry = info->entries; fileCount > 0; fileCount--, entry++) for (entry = info->entries; fileCount > 0; fileCount--, entry++)
{ {
if ( (!readAll(fh, &entry->name, 12)) || BAIL_IF_MACRO(!readAll(io, &entry->name, 12), NULL, 0);
(!readAll(fh, &entry->size, sizeof (PHYSFS_uint32))) ) BAIL_IF_MACRO(!readAll(io, &entry->size, 4), NULL, 0);
{
__PHYSFS_platformClose(fh);
return 0;
} /* if */
entry->name[12] = '\0'; /* name isn't null-terminated in file. */ entry->name[12] = '\0'; /* name isn't null-terminated in file. */
if ((ptr = strchr(entry->name, ' ')) != NULL) if ((ptr = strchr(entry->name, ' ')) != NULL)
*ptr = '\0'; /* trim extra spaces. */ *ptr = '\0'; /* trim extra spaces. */
@ -241,36 +225,40 @@ static int grp_load_entries(const char *name, int forWriting, GRPinfo *info)
location += entry->size; location += entry->size;
} /* for */ } /* for */
__PHYSFS_platformClose(fh); __PHYSFS_sort(info->entries, info->entryCount, grpEntryCmp, grpEntrySwap);
__PHYSFS_sort(info->entries, info->entryCount,
grp_entry_cmp, grp_entry_swap);
return 1; return 1;
} /* grp_load_entries */ } /* 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)); memset(info, '\0', sizeof (GRPinfo));
info->filename = (char *) allocator.Malloc(strlen(name) + 1); info->io = io;
GOTO_IF_MACRO(!info->filename, ERR_OUT_OF_MEMORY, GRP_openArchive_failed);
if (!grp_load_entries(name, forWriting, info)) GOTO_IF_MACRO(!readAll(io,&val,sizeof(val)), NULL, GRP_openArchive_failed);
goto 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; return info;
GRP_openArchive_failed: GRP_openArchive_failed:
if (info != NULL) if (info != NULL)
{ {
if (info->filename != NULL)
allocator.Free(info->filename);
if (info->entries != NULL) if (info->entries != NULL)
allocator.Free(info->entries); allocator.Free(info->entries);
allocator.Free(info); allocator.Free(info);
@ -318,7 +306,7 @@ static GRPentry *grp_find_entry(const GRPinfo *info, const char *name)
while (lo <= hi) while (lo <= hi)
{ {
middle = lo + ((hi - lo) / 2); middle = lo + ((hi - lo) / 2);
rc = strcmp(name, a[middle].name); rc = __PHYSFS_stricmpASCII(name, a[middle].name);
if (rc == 0) /* found it! */ if (rc == 0) /* found it! */
return &a[middle]; return &a[middle];
else if (rc > 0) else if (rc > 0)
@ -351,40 +339,58 @@ static int GRP_isSymLink(dvoid *opaque, const char *name, int *fileExists)
} /* GRP_isSymLink */ } /* 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; GRPinfo *info = (GRPinfo *) opaque;
GRPfileinfo *finfo; GRPfileinfo *finfo;
GRPentry *entry; GRPentry *entry;
entry = grp_find_entry(info, fnm); entry = grp_find_entry(info, fnm);
*fileExists = (entry != NULL); *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)); 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); finfo->io = info->io->duplicate(info->io);
if ( (finfo->handle == NULL) || GOTO_IF_MACRO(finfo->io == NULL, NULL, GRP_openRead_failed);
(!__PHYSFS_platformSeek(finfo->handle, entry->startPos)) )
{ if (!finfo->io->seek(finfo->io, entry->startPos))
allocator.Free(finfo); GOTO_MACRO(NULL, GRP_openRead_failed);
return NULL;
} /* if */
finfo->curPos = 0; finfo->curPos = 0;
finfo->entry = entry; 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 */ } /* 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); BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* GRP_openWrite */ } /* 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); BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* GRP_openAppend */ } /* GRP_openAppend */
@ -446,14 +452,7 @@ const PHYSFS_Archiver __PHYSFS_Archiver_GRP =
GRP_remove, /* remove() method */ GRP_remove, /* remove() method */
GRP_mkdir, /* mkdir() method */ GRP_mkdir, /* mkdir() method */
GRP_dirClose, /* dirClose() method */ GRP_dirClose, /* dirClose() method */
GRP_stat, /* stat() 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 */
}; };
#endif /* defined PHYSFS_SUPPORTS_GRP */ #endif /* defined PHYSFS_SUPPORTS_GRP */

View File

@ -54,7 +54,7 @@ typedef struct
*/ */
typedef struct typedef struct
{ {
char *filename; PHYSFS_Io *io;
PHYSFS_uint32 entryCount; PHYSFS_uint32 entryCount;
HOGentry *entries; HOGentry *entries;
} HOGinfo; } HOGinfo;
@ -64,30 +64,30 @@ typedef struct
*/ */
typedef struct typedef struct
{ {
void *handle; PHYSFS_Io *io;
HOGentry *entry; HOGentry *entry;
PHYSFS_uint32 curPos; PHYSFS_uint32 curPos;
} HOGfileinfo; } 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 */ } /* readAll */
static void HOG_dirClose(dvoid *opaque) static void HOG_dirClose(dvoid *opaque)
{ {
HOGinfo *info = ((HOGinfo *) opaque); HOGinfo *info = ((HOGinfo *) opaque);
allocator.Free(info->filename); info->io->destroy(info->io);
allocator.Free(info->entries); allocator.Free(info->entries);
allocator.Free(info); allocator.Free(info);
} /* HOG_dirClose */ } /* 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 HOGentry *entry = finfo->entry;
const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos); const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos);
PHYSFS_sint64 rc; PHYSFS_sint64 rc;
@ -95,7 +95,7 @@ static PHYSFS_sint64 HOG_read(fvoid *opaque, void *buffer, PHYSFS_uint64 len)
if (bytesLeft < len) if (bytesLeft < len)
len = bytesLeft; len = bytesLeft;
rc = __PHYSFS_platformRead(finfo->handle, buffer, len); rc = finfo->io->read(finfo->io, buffer, len);
if (rc > 0) if (rc > 0)
finfo->curPos += (PHYSFS_uint32) rc; finfo->curPos += (PHYSFS_uint32) rc;
@ -103,35 +103,26 @@ static PHYSFS_sint64 HOG_read(fvoid *opaque, void *buffer, PHYSFS_uint64 len)
} /* HOG_read */ } /* 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); BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
} /* HOG_write */ } /* HOG_write */
static int HOG_eof(fvoid *opaque) static PHYSFS_sint64 HOG_tell(PHYSFS_Io *io)
{ {
HOGfileinfo *finfo = (HOGfileinfo *) opaque; return ((HOGfileinfo *) io->opaque)->curPos;
HOGentry *entry = finfo->entry;
return (finfo->curPos >= entry->size);
} /* HOG_eof */
static PHYSFS_sint64 HOG_tell(fvoid *opaque)
{
return ((HOGfileinfo *) opaque)->curPos;
} /* HOG_tell */ } /* 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; HOGfileinfo *finfo = (HOGfileinfo *) io->opaque;
HOGentry *entry = finfo->entry; const HOGentry *entry = finfo->entry;
int rc; int rc;
BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 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) if (rc)
finfo->curPos = (PHYSFS_uint32) offset; finfo->curPos = (PHYSFS_uint32) offset;
@ -139,83 +130,65 @@ static int HOG_seek(fvoid *opaque, PHYSFS_uint64 offset)
} /* HOG_seek */ } /* 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); 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; HOGfileinfo *origfinfo = (HOGfileinfo *) _io->opaque;
BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0); PHYSFS_Io *io = NULL;
PHYSFS_Io *retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
HOGfileinfo *finfo = (HOGfileinfo *) allocator.Malloc(sizeof (HOGfileinfo));
GOTO_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, HOG_duplicate_failed);
GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, HOG_duplicate_failed);
io = origfinfo->io->duplicate(origfinfo->io);
GOTO_IF_MACRO(io == NULL, NULL, HOG_duplicate_failed);
finfo->io = io;
finfo->entry = origfinfo->entry;
finfo->curPos = 0;
memcpy(retval, _io, sizeof (PHYSFS_Io));
retval->opaque = finfo;
return retval;
HOG_duplicate_failed:
if (finfo != NULL) allocator.Free(finfo);
if (retval != NULL) allocator.Free(retval);
if (io != NULL) io->destroy(io);
return NULL;
} /* HOG_duplicate */
static int HOG_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
static void HOG_destroy(PHYSFS_Io *io)
{
HOGfileinfo *finfo = (HOGfileinfo *) io->opaque;
finfo->io->destroy(finfo->io);
allocator.Free(finfo); allocator.Free(finfo);
return 1; allocator.Free(io);
} /* HOG_fileClose */ } /* HOG_destroy */
static int hog_open(const char *filename, int forWriting, static const PHYSFS_Io HOG_Io =
void **fh, PHYSFS_uint32 *count)
{ {
PHYSFS_uint8 buf[13]; HOG_read,
PHYSFS_uint32 size; HOG_write,
PHYSFS_sint64 pos; HOG_seek,
HOG_tell,
*count = 0; HOG_length,
HOG_duplicate,
*fh = NULL; HOG_flush,
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0); HOG_destroy,
NULL
*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 */
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) if (one != two)
{ {
@ -224,10 +197,10 @@ static int hog_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
} /* if */ } /* if */
return 0; 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) 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(first, second, sizeof (HOGentry));
memcpy(second, &tmp, sizeof (HOGentry)); memcpy(second, &tmp, sizeof (HOGentry));
} /* if */ } /* 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; const PHYSFS_uint64 iolen = io->length(io);
PHYSFS_uint32 fileCount; PHYSFS_uint32 entCount = 0;
HOGentry *entry; 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); while (pos < iolen)
info->entryCount = fileCount;
info->entries = (HOGentry *) allocator.Malloc(sizeof(HOGentry)*fileCount);
if (info->entries == NULL)
{ {
__PHYSFS_platformClose(fh); entCount++;
BAIL_MACRO(ERR_OUT_OF_MEMORY, 0); ptr = allocator.Realloc(ptr, sizeof (HOGentry) * entCount);
} /* if */ 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++) BAIL_IF_MACRO(!readAll(io, &entry->name, 13), NULL, 0);
{ pos += 13;
if ( (!readAll(fh, &entry->name, 13)) || BAIL_IF_MACRO(!readAll(io, &size, 4), NULL, 0);
(!readAll(fh, &entry->size, sizeof (PHYSFS_uint32))) ) pos += 4;
{
__PHYSFS_platformClose(fh);
return 0;
} /* if */
entry->size = PHYSFS_swapULE32(entry->size); entry->size = PHYSFS_swapULE32(size);
entry->startPos = (unsigned int) __PHYSFS_platformTell(fh); entry->startPos = pos;
pos += size;
/* Skip over entry */ BAIL_IF_MACRO(!io->seek(io, pos), NULL, 0); /* skip over entry */
if ( (entry->startPos == -1) ||
(!__PHYSFS_platformSeek(fh, entry->startPos + entry->size)) )
{
__PHYSFS_platformClose(fh);
return 0;
} /* if */
} /* for */ } /* for */
__PHYSFS_platformClose(fh); info->entryCount = entCount;
__PHYSFS_sort(info->entries, info->entryCount, __PHYSFS_sort(info->entries, entCount, hogEntryCmp, hogEntrySwap);
hog_entry_cmp, hog_entry_swap);
return 1; return 1;
} /* hog_load_entries */ } /* 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)); memset(info, '\0', sizeof (HOGinfo));
info->filename = (char *) allocator.Malloc(strlen(name) + 1); info->io = io;
GOTO_IF_MACRO(!info->filename, ERR_OUT_OF_MEMORY, HOG_openArchive_failed);
if (!hog_load_entries(name, forWriting, info)) GOTO_IF_MACRO(!hog_load_entries(io, info), NULL, HOG_openArchive_failed);
goto HOG_openArchive_failed;
strcpy(info->filename, name);
return info; return info;
HOG_openArchive_failed: HOG_openArchive_failed:
if (info != NULL) if (info != NULL)
{ {
if (info->filename != NULL)
allocator.Free(info->filename);
if (info->entries != NULL) if (info->entries != NULL)
allocator.Free(info->entries); allocator.Free(info->entries);
allocator.Free(info); 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) 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 */ } /* HOG_exists */
@ -386,40 +355,58 @@ static int HOG_isSymLink(dvoid *opaque, const char *name, int *fileExists)
} /* HOG_isSymLink */ } /* 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; HOGfileinfo *finfo;
HOGentry *entry; HOGentry *entry;
entry = hog_find_entry(info, fnm); entry = hog_find_entry(info, fnm);
*fileExists = (entry != NULL); *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)); 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); finfo->io = info->io->duplicate(info->io);
if ( (finfo->handle == NULL) || GOTO_IF_MACRO(finfo->io == NULL, NULL, HOG_openRead_failed);
(!__PHYSFS_platformSeek(finfo->handle, entry->startPos)) )
{ if (!finfo->io->seek(finfo->io, entry->startPos))
allocator.Free(finfo); GOTO_MACRO(NULL, HOG_openRead_failed);
return NULL;
} /* if */
finfo->curPos = 0; finfo->curPos = 0;
finfo->entry = entry; 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 */ } /* 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); BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* HOG_openWrite */ } /* 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); BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* HOG_openAppend */ } /* HOG_openAppend */
@ -481,14 +468,7 @@ const PHYSFS_Archiver __PHYSFS_Archiver_HOG =
HOG_remove, /* remove() method */ HOG_remove, /* remove() method */
HOG_mkdir, /* mkdir() method */ HOG_mkdir, /* mkdir() method */
HOG_dirClose, /* dirClose() method */ HOG_dirClose, /* dirClose() method */
HOG_stat, /* stat() 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 */
}; };
#endif /* defined PHYSFS_SUPPORTS_HOG */ #endif /* defined PHYSFS_SUPPORTS_HOG */

View File

@ -200,7 +200,7 @@ typedef struct
typedef struct typedef struct
{ {
void *fhandle; PHYSFS_Io *io;
PHYSFS_uint32 rootdirstart; PHYSFS_uint32 rootdirstart;
PHYSFS_uint32 rootdirsize; PHYSFS_uint32 rootdirsize;
PHYSFS_uint64 currpos; PHYSFS_uint64 currpos;
@ -219,12 +219,13 @@ typedef struct __ISO9660FileHandle
PHYSFS_uint32 (*read) (struct __ISO9660FileHandle *filehandle, void *buffer, PHYSFS_uint32 (*read) (struct __ISO9660FileHandle *filehandle, void *buffer,
PHYSFS_uint64 len); PHYSFS_uint64 len);
int (*seek)(struct __ISO9660FileHandle *filehandle, PHYSFS_sint64 offset); 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. */ /* !!! FIXME: anonymouse union is going to cause problems. */
union union
{ {
/* !!! FIXME: just use a memory PHYSFS_Io here, unify all this code. */
char *cacheddata; /* data of file when cached */ char *cacheddata; /* data of file when cached */
void *filehandle; /* handle to separate opened file */ PHYSFS_Io *io; /* handle to separate opened file */
}; };
} ISO9660FileHandle; } ISO9660FileHandle;
@ -349,9 +350,8 @@ static int iso_readimage(ISO9660Handle *handle, PHYSFS_uint64 where,
ERR_LOCK_VIOLATION, -1); ERR_LOCK_VIOLATION, -1);
int rc = -1; int rc = -1;
if (where != handle->currpos) if (where != handle->currpos)
GOTO_IF_MACRO(!__PHYSFS_platformSeek(handle->fhandle,where), NULL, GOTO_IF_MACRO(!handle->io->seek(handle->io,where), NULL, unlockme);
unlockme); rc = handle->io->read(handle->io, buffer, len);
rc = __PHYSFS_platformRead(handle->fhandle, buffer, len);
if (rc == -1) if (rc == -1)
{ {
handle->currpos = (PHYSFS_uint64) -1; handle->currpos = (PHYSFS_uint64) -1;
@ -479,53 +479,94 @@ static int iso_read_ext_attributes(ISO9660Handle *handle, int block,
} /* iso_read_ext_attributes */ } /* 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 * Archive management functions
******************************************************************************/ ******************************************************************************/
/* !!! FIXME: don't open/close file here, merge with openArchive(). */ static void *ISO9660_openArchive(PHYSFS_Io *io, const char *filename, int forWriting)
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)
{ {
char magicnumber[6];
ISO9660Handle *handle; ISO9660Handle *handle;
int founddescriptor = 0; int founddescriptor = 0;
int foundjoliet = 0; int foundjoliet = 0;
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0); assert(io != NULL); /* shouldn't ever happen. */
BAIL_IF_MACRO(!isIso(filename), ERR_UNSUPPORTED_ARCHIVE, NULL);
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)); handle = allocator.Malloc(sizeof(ISO9660Handle));
GOTO_IF_MACRO(!handle, ERR_OUT_OF_MEMORY, errorcleanup); GOTO_IF_MACRO(!handle, ERR_OUT_OF_MEMORY, errorcleanup);
handle->path = 0; handle->path = 0;
handle->mutex= 0; handle->mutex= 0;
handle->fhandle = 0; handle->io = NULL;
handle->path = allocator.Malloc(strlen(filename) + 1); handle->path = allocator.Malloc(strlen(filename) + 1);
GOTO_IF_MACRO(!handle->path, ERR_OUT_OF_MEMORY, errorcleanup); 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(); handle->mutex = __PHYSFS_platformCreateMutex();
GOTO_IF_MACRO(!handle->mutex, "Cannot create Mutex", errorcleanup); GOTO_IF_MACRO(!handle->mutex, "Cannot create Mutex", errorcleanup);
handle->fhandle = __PHYSFS_platformOpenRead(filename); handle->io = io;
GOTO_IF_MACRO(!handle->fhandle, NULL, errorcleanup);
/* seek Primary Volume Descriptor */ /* 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) while (1)
{ {
ISO9660VolumeDescriptor descriptor; 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); GOTO_IF_MACRO(strncmp(descriptor.identifier, "CD001", 5) != 0, ERR_NOT_AN_ARCHIVE, errorcleanup);
if (descriptor.type == 255) if (descriptor.type == 255)
@ -556,7 +596,7 @@ static void *ISO9660_openArchive(const char *filename, int forWriting)
} /* if */ } /* if */
if (descriptor.type == 1 && !founddescriptor) if (descriptor.type == 1 && !founddescriptor)
{ {
handle->currpos = __PHYSFS_platformTell(handle->fhandle); handle->currpos = io->tell(io);
handle->rootdirstart = handle->rootdirstart =
descriptor.rootdirectory.extent_location * 2048; descriptor.rootdirectory.extent_location * 2048;
handle->rootdirsize = handle->rootdirsize =
@ -575,7 +615,7 @@ static void *ISO9660_openArchive(const char *filename, int forWriting)
if (!joliet) if (!joliet)
continue; continue;
handle->currpos = __PHYSFS_platformTell(handle->fhandle); handle->currpos = io->tell(io);
handle->rootdirstart = handle->rootdirstart =
descriptor.rootdirectory.extent_location * 2048; descriptor.rootdirectory.extent_location * 2048;
handle->rootdirsize = handle->rootdirsize =
@ -591,12 +631,11 @@ static void *ISO9660_openArchive(const char *filename, int forWriting)
errorcleanup: errorcleanup:
if (handle) if (handle)
{ {
if (handle->fhandle)
__PHYSFS_platformClose(handle->fhandle);
if (handle->path) if (handle->path)
allocator.Free(handle->path); allocator.Free(handle->path);
if (handle->mutex) if (handle->mutex)
__PHYSFS_platformDestroyMutex(handle->mutex); __PHYSFS_platformDestroyMutex(handle->mutex);
allocator.Free(handle);
} /* if */ } /* if */
return NULL; return NULL;
} /* ISO9660_openArchive */ } /* ISO9660_openArchive */
@ -605,7 +644,7 @@ errorcleanup:
static void ISO9660_dirClose(dvoid *opaque) static void ISO9660_dirClose(dvoid *opaque)
{ {
ISO9660Handle *handle = (ISO9660Handle*) opaque; ISO9660Handle *handle = (ISO9660Handle*) opaque;
__PHYSFS_platformClose(handle->fhandle); handle->io->destroy(handle->io);
__PHYSFS_platformDestroyMutex(handle->mutex); __PHYSFS_platformDestroyMutex(handle->mutex);
allocator.Free(handle->path); allocator.Free(handle->path);
allocator.Free(handle); allocator.Free(handle);
@ -645,12 +684,11 @@ static int iso_file_seek_mem(ISO9660FileHandle *fhandle, PHYSFS_sint64 offset)
} /* iso_file_seek_mem */ } /* 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->cacheddata);
allocator.Free(fhandle); allocator.Free(fhandle);
return -1; } /* iso_file_close_mem */
} /* iso_file_seek_mem */
static PHYSFS_uint32 iso_file_read_foreign(ISO9660FileHandle *filehandle, 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) if (bytesleft < len)
len = bytesleft; len = bytesleft;
PHYSFS_sint64 rc = __PHYSFS_platformRead(filehandle->filehandle, buffer, const PHYSFS_sint64 rc = filehandle->io->read(filehandle->io, buffer, len);
len);
BAIL_IF_MACRO(rc == -1, NULL, -1); BAIL_IF_MACRO(rc == -1, NULL, -1);
filehandle->currpos += rc; /* i trust my internal book keeping */ 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); BAIL_IF_MACRO(offset >= fhandle->filesize, ERR_PAST_EOF, 0);
PHYSFS_sint64 pos = fhandle->startblock * 2048 + offset; PHYSFS_sint64 pos = fhandle->startblock * 2048 + offset;
int rc = __PHYSFS_platformSeek(fhandle->filehandle, pos); BAIL_IF_MACRO(!fhandle->io->seek(fhandle->io, pos), NULL, -1);
BAIL_IF_MACRO(rc, NULL, -1);
fhandle->currpos = offset; fhandle->currpos = offset;
return 0; return 0;
} /* iso_file_seek_foreign */ } /* 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); allocator.Free(fhandle);
return __PHYSFS_platformClose(filehandle);
} /* iso_file_close_foreign */ } /* iso_file_close_foreign */
@ -717,10 +752,10 @@ freemem:
static int iso_file_open_foreign(ISO9660Handle *handle, static int iso_file_open_foreign(ISO9660Handle *handle,
ISO9660FileHandle *fhandle) ISO9660FileHandle *fhandle)
{ {
fhandle->filehandle = __PHYSFS_platformOpenRead(handle->path); int rc;
BAIL_IF_MACRO(!fhandle->filehandle, NULL, -1); fhandle->io = __PHYSFS_createNativeIo(handle->path, 'r');
int rc = __PHYSFS_platformSeek(fhandle->filehandle, BAIL_IF_MACRO(!fhandle->io, NULL, -1);
fhandle->startblock * 2048); rc = fhandle->io->seek(fhandle->io, fhandle->startblock * 2048);
GOTO_IF_MACRO(!rc, NULL, closefile); GOTO_IF_MACRO(!rc, NULL, closefile);
fhandle->read = iso_file_read_foreign; fhandle->read = iso_file_read_foreign;
@ -728,14 +763,15 @@ static int iso_file_open_foreign(ISO9660Handle *handle,
fhandle->close = iso_file_close_foreign; fhandle->close = iso_file_close_foreign;
return 0; return 0;
closefile: closefile:
__PHYSFS_platformClose(fhandle->filehandle); fhandle->io->destroy(fhandle->io);
return -1; return -1;
} /* iso_file_open_foreign */ } /* 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; ISO9660Handle *handle = (ISO9660Handle*) opaque;
ISO9660FileHandle *fhandle; ISO9660FileHandle *fhandle;
ISO9660FileDescriptor descriptor; 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); BAIL_IF_MACRO(fhandle == 0, ERR_OUT_OF_MEMORY, NULL);
fhandle->cacheddata = 0; fhandle->cacheddata = 0;
retval = allocator.Malloc(sizeof(PHYSFS_Io));
GOTO_IF_MACRO(retval == 0, ERR_OUT_OF_MEMORY, errorhandling);
/* find file descriptor */ /* find file descriptor */
rc = iso_find_dir_entry(handle, filename, &descriptor, exists); rc = iso_find_dir_entry(handle, filename, &descriptor, exists);
GOTO_IF_MACRO(rc, NULL, errorhandling); 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->currpos = 0;
fhandle->isohandle = handle; fhandle->isohandle = handle;
fhandle->cacheddata = NULL; fhandle->cacheddata = NULL;
fhandle->filehandle = NULL; fhandle->io = NULL;
if (descriptor.datalen <= ISO9660_FULLCACHEMAXSIZE) if (descriptor.datalen <= ISO9660_FULLCACHEMAXSIZE)
rc = iso_file_open_mem(handle, fhandle); 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); rc = iso_file_open_foreign(handle, fhandle);
GOTO_IF_MACRO(rc, NULL, errorhandling); GOTO_IF_MACRO(rc, NULL, errorhandling);
return fhandle; memcpy(retval, &ISO9660_Io, sizeof (PHYSFS_Io));
retval->opaque = fhandle;
return retval;
errorhandling: errorhandling:
if (!fhandle) if (retval) allocator.Free(retval);
return NULL; if (fhandle) allocator.Free(fhandle);
allocator.Free(fhandle);
return NULL; return NULL;
} /* ISO9660_openRead */ } /* 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 * Information gathering functions
@ -945,13 +948,13 @@ static int ISO9660_isSymLink(dvoid *opaque, const char *name, int *fileExists)
* Not supported functions * 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); BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* ISO9660_openWrite */ } /* 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); BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* ISO9660_openAppend */ } /* ISO9660_openAppend */
@ -969,11 +972,6 @@ static int ISO9660_mkdir(dvoid *opaque, const char *name)
} /* ISO9660_mkdir */ } /* 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 = const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_ISO9660 =
{ {
@ -997,14 +995,7 @@ const PHYSFS_Archiver __PHYSFS_Archiver_ISO9660 =
ISO9660_remove, /* remove() method */ ISO9660_remove, /* remove() method */
ISO9660_mkdir, /* mkdir() method */ ISO9660_mkdir, /* mkdir() method */
ISO9660_dirClose, /* dirClose() method */ ISO9660_dirClose, /* dirClose() method */
ISO9660_stat, /* stat() 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 */
}; };
#endif /* defined PHYSFS_SUPPORTS_ISO9660 */ #endif /* defined PHYSFS_SUPPORTS_ISO9660 */

View File

@ -40,7 +40,7 @@ typedef struct _FileInputStream
ISzAlloc allocImp; /* Allocation implementation, used by 7z */ ISzAlloc allocImp; /* Allocation implementation, used by 7z */
ISzAlloc allocTempImp; /* Temporary allocation implementation, used by 7z */ ISzAlloc allocTempImp; /* Temporary allocation implementation, used by 7z */
ISzInStream inStream; /* Input stream with read callbacks, 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 #ifdef _LZMA_IN_CB
Byte buffer[BUFFER_SIZE]; /* Buffer, used by read implementation */ Byte buffer[BUFFER_SIZE]; /* Buffer, used by read implementation */
#endif /* _LZMA_IN_CB */ #endif /* _LZMA_IN_CB */
@ -113,7 +113,7 @@ SZ_RESULT SzFileReadImp(void *object, void **buffer, size_t maxReqSize,
if (maxReqSize > BUFFER_SIZE) if (maxReqSize > BUFFER_SIZE)
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; *buffer = s->buffer;
if (processedSize != NULL) if (processedSize != NULL)
*processedSize = (size_t) processedSizeLoc; *processedSize = (size_t) processedSizeLoc;
@ -131,8 +131,8 @@ SZ_RESULT SzFileReadImp(void *object, void *buffer, size_t size,
size_t *processedSize) size_t *processedSize)
{ {
FileInputStream *s = (FileInputStream *)((unsigned long)object - offsetof(FileInputStream, inStream)); /* HACK! */ FileInputStream *s = (FileInputStream *)((unsigned long)object - offsetof(FileInputStream, inStream)); /* HACK! */
size_t processedSizeLoc = __PHYSFS_platformRead(s->file, buffer, size); const size_t processedSizeLoc = s->io->read(s->io, buffer, size);
if (processedSize != 0) if (processedSize != NULL)
*processedSize = processedSizeLoc; *processedSize = processedSizeLoc;
return SZ_OK; return SZ_OK;
} /* SzFileReadImp */ } /* SzFileReadImp */
@ -146,7 +146,7 @@ SZ_RESULT SzFileReadImp(void *object, void *buffer, size_t size,
SZ_RESULT SzFileSeekImp(void *object, CFileSize pos) SZ_RESULT SzFileSeekImp(void *object, CFileSize pos)
{ {
FileInputStream *s = (FileInputStream *)((unsigned long)object - offsetof(FileInputStream, inStream)); /* HACK! */ 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 SZ_OK;
return SZE_FAIL; return SZE_FAIL;
} /* SzFileSeekImp */ } /* SzFileSeekImp */
@ -322,12 +322,12 @@ static int lzma_err(SZ_RESULT rc)
} /* lzma_err */ } /* 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 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; size_t fileSize = 0;
BAIL_IF_MACRO(wantedSize == 0, NULL, 0); /* quick rejection. */ 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) if (wantedSize > remainingSize)
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) if (file->folder->cache == NULL)
{ {
int rc = lzma_err(SzExtract( const int rc = lzma_err(SzExtract(
&file->archive->stream.inStream, /* compressed data */ &file->archive->stream.inStream, /* compressed data */
&file->archive->db, /* 7z's database, containing everything */ &file->archive->db, /* 7z's database, containing everything */
file->index, /* Index into database arrays */ file->index, /* Index into database arrays */
@ -360,9 +360,7 @@ static PHYSFS_sint64 LZMA_read(fvoid *opaque, void *outBuf, PHYSFS_uint64 len)
} /* if */ } /* if */
/* Copy wanted bytes over from cache to outBuf */ /* Copy wanted bytes over from cache to outBuf */
memcpy(outBuf, memcpy(outBuf, (file->folder->cache + file->offset + file->position),
(file->folder->cache +
file->offset + file->position),
wantedSize); wantedSize);
file->position += wantedSize; /* Increase virtual position */ file->position += wantedSize; /* Increase virtual position */
@ -370,31 +368,23 @@ static PHYSFS_sint64 LZMA_read(fvoid *opaque, void *outBuf, PHYSFS_uint64 len)
} /* LZMA_read */ } /* 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); BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
} /* LZMA_write */ } /* LZMA_write */
static int LZMA_eof(fvoid *opaque) static PHYSFS_sint64 LZMA_tell(PHYSFS_Io *io)
{ {
LZMAfile *file = (LZMAfile *) opaque; LZMAfile *file = (LZMAfile *) io->opaque;
return (file->position >= file->item->Size); return file->position;
} /* LZMA_eof */
static PHYSFS_sint64 LZMA_tell(fvoid *opaque)
{
LZMAfile *file = (LZMAfile *) opaque;
return (file->position);
} /* LZMA_tell */ } /* 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); BAIL_IF_MACRO(offset > file->item->Size, ERR_PAST_EOF, 0);
file->position = offset; /* We only use a virtual position... */ file->position = offset; /* We only use a virtual position... */
@ -403,75 +393,78 @@ static int LZMA_seek(fvoid *opaque, PHYSFS_uint64 offset)
} /* LZMA_seek */ } /* 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); 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... */ static int LZMA_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
if (file->folder->references > 0)
file->folder->references--;
if (file->folder->references == 0) 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() */ /* Only decrease refcount if someone actually requested this file... Prevents from overflows and close-on-open... */
allocator.Free(file->folder->cache); if (file->folder->references > 0)
file->folder->cache = NULL; file->folder->references--;
} if (file->folder->references == 0)
{
return 1; /* Free the cache which might have been allocated by LZMA_read() */
} /* LZMA_fileClose */ 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 const PHYSFS_Io LZMA_Io =
static int isLzma(const char *filename) {
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]; 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; size_t len = 0;
LZMAarchive *archive = NULL; LZMAarchive *archive = NULL;
assert(io != NULL); /* shouldn't ever happen. */
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, NULL); 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)); archive = (LZMAarchive *) allocator.Malloc(sizeof (LZMAarchive));
BAIL_IF_MACRO(archive == NULL, ERR_OUT_OF_MEMORY, NULL); BAIL_IF_MACRO(archive == NULL, ERR_OUT_OF_MEMORY, NULL);
lzma_archive_init(archive); lzma_archive_init(archive);
archive->stream.io = io;
if ( (archive->stream.file = __PHYSFS_platformOpenRead(name)) == NULL )
{
__PHYSFS_platformClose(archive->stream.file);
lzma_archive_exit(archive);
return NULL; /* Error is set by platformOpenRead! */
}
CrcGenerateTable(); CrcGenerateTable();
SzArDbExInit(&archive->db); SzArDbExInit(&archive->db);
@ -481,7 +474,6 @@ static void *LZMA_openArchive(const char *name, int forWriting)
&archive->stream.allocTempImp)) != SZ_OK) &archive->stream.allocTempImp)) != SZ_OK)
{ {
SzArDbExFree(&archive->db, SzFreePhysicsFS); SzArDbExFree(&archive->db, SzFreePhysicsFS);
__PHYSFS_platformClose(archive->stream.file);
lzma_archive_exit(archive); lzma_archive_exit(archive);
return NULL; /* Error is set by lzma_err! */ return NULL; /* Error is set by lzma_err! */
} /* if */ } /* if */
@ -491,7 +483,6 @@ static void *LZMA_openArchive(const char *name, int forWriting)
if (archive->files == NULL) if (archive->files == NULL)
{ {
SzArDbExFree(&archive->db, SzFreePhysicsFS); SzArDbExFree(&archive->db, SzFreePhysicsFS);
__PHYSFS_platformClose(archive->stream.file);
lzma_archive_exit(archive); lzma_archive_exit(archive);
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL); BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
} }
@ -507,7 +498,6 @@ static void *LZMA_openArchive(const char *name, int forWriting)
if (archive->folders == NULL) if (archive->folders == NULL)
{ {
SzArDbExFree(&archive->db, SzFreePhysicsFS); SzArDbExFree(&archive->db, SzFreePhysicsFS);
__PHYSFS_platformClose(archive->stream.file);
lzma_archive_exit(archive); lzma_archive_exit(archive);
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL); 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)) if(!lzma_files_init(archive))
{ {
SzArDbExFree(&archive->db, SzFreePhysicsFS); SzArDbExFree(&archive->db, SzFreePhysicsFS);
__PHYSFS_platformClose(archive->stream.file);
lzma_archive_exit(archive); lzma_archive_exit(archive);
BAIL_MACRO(ERR_UNKNOWN_ERROR, NULL); BAIL_MACRO(ERR_UNKNOWN_ERROR, NULL);
} }
@ -616,10 +605,11 @@ static int LZMA_isSymLink(dvoid *opaque, const char *name, int *fileExists)
} /* LZMA_isSymLink */ } /* 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; LZMAarchive *archive = (LZMAarchive *) opaque;
LZMAfile *file = lzma_find_file(archive, name); LZMAfile *file = lzma_find_file(archive, name);
PHYSFS_Io *io = NULL;
*fileExists = (file != NULL); *fileExists = (file != NULL);
BAIL_IF_MACRO(file == NULL, ERR_NO_SUCH_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->position = 0;
file->folder->references++; /* Increase refcount for automatic cleanup... */ 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 */ } /* 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); BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* LZMA_openWrite */ } /* 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); BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* LZMA_openAppend */ } /* LZMA_openAppend */
@ -647,15 +642,17 @@ static fvoid *LZMA_openAppend(dvoid *opaque, const char *filename)
static void LZMA_dirClose(dvoid *opaque) static void LZMA_dirClose(dvoid *opaque)
{ {
LZMAarchive *archive = (LZMAarchive *) 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++) for (fileIndex = 0; fileIndex < numFiles; fileIndex++)
{ {
LZMA_fileClose(&archive->files[fileIndex]); LZMA_fileClose(&archive->files[fileIndex]);
} /* for */ } /* for */
#endif
SzArDbExFree(&archive->db, SzFreePhysicsFS); SzArDbExFree(&archive->db, SzFreePhysicsFS);
__PHYSFS_platformClose(archive->stream.file); archive->stream.io->destroy(archive->stream.io);
lzma_archive_exit(archive); lzma_archive_exit(archive);
} /* LZMA_dirClose */ } /* LZMA_dirClose */
@ -731,14 +728,7 @@ const PHYSFS_Archiver __PHYSFS_Archiver_LZMA =
LZMA_remove, /* remove() method */ LZMA_remove, /* remove() method */
LZMA_mkdir, /* mkdir() method */ LZMA_mkdir, /* mkdir() method */
LZMA_dirClose, /* dirClose() method */ LZMA_dirClose, /* dirClose() method */
LZMA_stat, /* stat() 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 */
}; };
#endif /* defined PHYSFS_SUPPORTS_7Z */ #endif /* defined PHYSFS_SUPPORTS_7Z */

View File

@ -46,31 +46,37 @@ typedef struct
typedef struct typedef struct
{ {
char *filename; PHYSFS_Io *io;
PHYSFS_uint32 entryCount; PHYSFS_uint32 entryCount;
MVLentry *entries; MVLentry *entries;
} MVLinfo; } MVLinfo;
typedef struct typedef struct
{ {
void *handle; PHYSFS_Io *io;
MVLentry *entry; MVLentry *entry;
PHYSFS_uint32 curPos; PHYSFS_uint32 curPos;
} MVLfileinfo; } 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) static void MVL_dirClose(dvoid *opaque)
{ {
MVLinfo *info = ((MVLinfo *) opaque); MVLinfo *info = ((MVLinfo *) opaque);
allocator.Free(info->filename); info->io->destroy(info->io);
allocator.Free(info->entries); allocator.Free(info->entries);
allocator.Free(info); allocator.Free(info);
} /* MVL_dirClose */ } /* 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 MVLentry *entry = finfo->entry;
const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos); const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos);
PHYSFS_sint64 rc; PHYSFS_sint64 rc;
@ -78,7 +84,7 @@ static PHYSFS_sint64 MVL_read(fvoid *opaque, void *buffer, PHYSFS_uint64 len)
if (bytesLeft < len) if (bytesLeft < len)
len = bytesLeft; len = bytesLeft;
rc = __PHYSFS_platformRead(finfo->handle, buffer, len); rc = finfo->io->read(finfo->io, buffer, len);
if (rc > 0) if (rc > 0)
finfo->curPos += (PHYSFS_uint32) rc; finfo->curPos += (PHYSFS_uint32) rc;
@ -86,35 +92,26 @@ static PHYSFS_sint64 MVL_read(fvoid *opaque, void *buffer, PHYSFS_uint64 len)
} /* MVL_read */ } /* 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); BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
} /* MVL_write */ } /* MVL_write */
static int MVL_eof(fvoid *opaque) static PHYSFS_sint64 MVL_tell(PHYSFS_Io *io)
{ {
MVLfileinfo *finfo = (MVLfileinfo *) opaque; return ((MVLfileinfo *) io->opaque)->curPos;
MVLentry *entry = finfo->entry;
return (finfo->curPos >= entry->size);
} /* MVL_eof */
static PHYSFS_sint64 MVL_tell(fvoid *opaque)
{
return ((MVLfileinfo *) opaque)->curPos;
} /* MVL_tell */ } /* 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; MVLfileinfo *finfo = (MVLfileinfo *) io->opaque;
MVLentry *entry = finfo->entry; const MVLentry *entry = finfo->entry;
int rc; int rc;
BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 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) if (rc)
finfo->curPos = (PHYSFS_uint32) offset; finfo->curPos = (PHYSFS_uint32) offset;
@ -122,72 +119,76 @@ static int MVL_seek(fvoid *opaque, PHYSFS_uint64 offset)
} /* MVL_seek */ } /* 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); 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; MVLfileinfo *origfinfo = (MVLfileinfo *) _io->opaque;
BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0); PHYSFS_Io *io = NULL;
PHYSFS_Io *retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
MVLfileinfo *finfo = (MVLfileinfo *) allocator.Malloc(sizeof (MVLfileinfo));
GOTO_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, MVL_duplicate_failed);
GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, MVL_duplicate_failed);
io = origfinfo->io->duplicate(origfinfo->io);
GOTO_IF_MACRO(io == NULL, NULL, MVL_duplicate_failed);
finfo->io = io;
finfo->entry = origfinfo->entry;
finfo->curPos = 0;
memcpy(retval, _io, sizeof (PHYSFS_Io));
retval->opaque = finfo;
return retval;
MVL_duplicate_failed:
if (finfo != NULL) allocator.Free(finfo);
if (retval != NULL) allocator.Free(retval);
if (io != NULL) io->destroy(io);
return NULL;
} /* MVL_duplicate */
static int MVL_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
static void MVL_destroy(PHYSFS_Io *io)
{
MVLfileinfo *finfo = (MVLfileinfo *) io->opaque;
finfo->io->destroy(finfo->io);
allocator.Free(finfo); allocator.Free(finfo);
return 1; allocator.Free(io);
} /* MVL_fileClose */ } /* MVL_destroy */
static int mvl_open(const char *filename, int forWriting, static const PHYSFS_Io MVL_Io =
void **fh, PHYSFS_uint32 *count)
{ {
PHYSFS_uint8 buf[4]; MVL_read,
MVL_write,
*fh = NULL; MVL_seek,
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0); MVL_tell,
MVL_length,
*fh = __PHYSFS_platformOpenRead(filename); MVL_duplicate,
BAIL_IF_MACRO(*fh == NULL, NULL, 0); MVL_flush,
MVL_destroy,
if (__PHYSFS_platformRead(*fh, buf, 4) != 4) NULL
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 */
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) if (one != two)
{ {
const MVLentry *a = (const MVLentry *) _a; const MVLentry *a = (const MVLentry *) _a;
return strcmp(a[one].name, a[two].name); return __PHYSFS_stricmpASCII(a[one].name, a[two].name);
} /* if */ } /* if */
return 0; 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) 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(first, second, sizeof (MVLentry));
memcpy(second, &tmp, sizeof (MVLentry)); memcpy(second, &tmp, sizeof (MVLentry));
} /* if */ } /* 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 = info->entryCount;
PHYSFS_uint32 fileCount;
PHYSFS_uint32 location = 8; /* sizeof sig. */ PHYSFS_uint32 location = 8; /* sizeof sig. */
MVLentry *entry; MVLentry *entry;
BAIL_IF_MACRO(!mvl_open(name, forWriting, &fh, &fileCount), NULL, 0);
info->entryCount = fileCount;
info->entries = (MVLentry *) allocator.Malloc(sizeof(MVLentry)*fileCount); info->entries = (MVLentry *) allocator.Malloc(sizeof(MVLentry)*fileCount);
if (info->entries == NULL) BAIL_IF_MACRO(info->entries == NULL, ERR_OUT_OF_MEMORY, 0);
{
__PHYSFS_platformClose(fh);
BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
} /* if */
location += (17 * fileCount); location += (17 * fileCount);
for (entry = info->entries; fileCount > 0; fileCount--, entry++) for (entry = info->entries; fileCount > 0; fileCount--, entry++)
{ {
if (__PHYSFS_platformRead(fh, &entry->name, 13) != 13) BAIL_IF_MACRO(!readAll(io, &entry->name, 13), NULL, 0);
{ BAIL_IF_MACRO(!readAll(io, &entry->size, 4), NULL, 0);
__PHYSFS_platformClose(fh);
return 0;
} /* if */
if (__PHYSFS_platformRead(fh, &entry->size, 4) != 4)
{
__PHYSFS_platformClose(fh);
return 0;
} /* if */
entry->size = PHYSFS_swapULE32(entry->size); entry->size = PHYSFS_swapULE32(entry->size);
entry->startPos = location; entry->startPos = location;
location += entry->size; location += entry->size;
} /* for */ } /* for */
__PHYSFS_platformClose(fh); __PHYSFS_sort(info->entries, info->entryCount, mvlEntryCmp, mvlEntrySwap);
__PHYSFS_sort(info->entries, info->entryCount,
mvl_entry_cmp, mvl_entry_swap);
return 1; return 1;
} /* mvl_load_entries */ } /* 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)); memset(info, '\0', sizeof (MVLinfo));
info->io = io;
info->filename = (char *) allocator.Malloc(strlen(name) + 1); GOTO_IF_MACRO(!readAll(io,&val,sizeof(val)), NULL, MVL_openArchive_failed);
GOTO_IF_MACRO(!info->filename, ERR_OUT_OF_MEMORY, MVL_openArchive_failed); info->entryCount = PHYSFS_swapULE32(val);
if (!mvl_load_entries(name, forWriting, info))
goto MVL_openArchive_failed; GOTO_IF_MACRO(!mvl_load_entries(io, info), NULL, MVL_openArchive_failed);
strcpy(info->filename, name);
return info; return info;
MVL_openArchive_failed: MVL_openArchive_failed:
if (info != NULL) if (info != NULL)
{ {
if (info->filename != NULL)
allocator.Free(info->filename);
if (info->entries != NULL) if (info->entries != NULL)
allocator.Free(info->entries); allocator.Free(info->entries);
allocator.Free(info); allocator.Free(info);
@ -346,40 +336,58 @@ static int MVL_isSymLink(dvoid *opaque, const char *name, int *fileExists)
} /* MVL_isSymLink */ } /* 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; MVLfileinfo *finfo;
MVLentry *entry; MVLentry *entry;
entry = mvl_find_entry(info, fnm); entry = mvl_find_entry(info, fnm);
*fileExists = (entry != NULL); *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)); 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); finfo->io = info->io->duplicate(info->io);
if ( (finfo->handle == NULL) || GOTO_IF_MACRO(finfo->io == NULL, NULL, MVL_openRead_failed);
(!__PHYSFS_platformSeek(finfo->handle, entry->startPos)) )
{ if (!finfo->io->seek(finfo->io, entry->startPos))
allocator.Free(finfo); GOTO_MACRO(NULL, MVL_openRead_failed);
return NULL;
} /* if */
finfo->curPos = 0; finfo->curPos = 0;
finfo->entry = entry; 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 */ } /* 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); BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* MVL_openWrite */ } /* 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); BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* MVL_openAppend */ } /* MVL_openAppend */
@ -441,14 +449,7 @@ const PHYSFS_Archiver __PHYSFS_Archiver_MVL =
MVL_remove, /* remove() method */ MVL_remove, /* remove() method */
MVL_mkdir, /* mkdir() method */ MVL_mkdir, /* mkdir() method */
MVL_dirClose, /* dirClose() method */ MVL_dirClose, /* dirClose() method */
MVL_stat, /* stat() 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 */
}; };
#endif /* defined PHYSFS_SUPPORTS_MVL */ #endif /* defined PHYSFS_SUPPORTS_MVL */

View File

@ -39,6 +39,7 @@
#define __PHYSICSFS_INTERNAL__ #define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h" #include "physfs_internal.h"
/* !!! FIXME: what is this here for? */
#if 1 /* Make this case insensitive? */ #if 1 /* Make this case insensitive? */
#define QPAK_strcmp(x, y) __PHYSFS_stricmpASCII(x, y) #define QPAK_strcmp(x, y) __PHYSFS_stricmpASCII(x, y)
#define QPAK_strncmp(x, y, z) __PHYSFS_strnicmpASCII(x, y, z) #define QPAK_strncmp(x, y, z) __PHYSFS_strnicmpASCII(x, y, z)
@ -57,14 +58,14 @@ typedef struct
typedef struct typedef struct
{ {
char *filename; PHYSFS_Io *io;
PHYSFS_uint32 entryCount; PHYSFS_uint32 entryCount;
QPAKentry *entries; QPAKentry *entries;
} QPAKinfo; } QPAKinfo;
typedef struct typedef struct
{ {
void *handle; PHYSFS_Io *io;
QPAKentry *entry; QPAKentry *entry;
PHYSFS_uint32 curPos; PHYSFS_uint32 curPos;
} QPAKfileinfo; } QPAKfileinfo;
@ -73,18 +74,24 @@ typedef struct
#define QPAK_SIG 0x4b434150 /* "PACK" in ASCII. */ #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) static void QPAK_dirClose(dvoid *opaque)
{ {
QPAKinfo *info = ((QPAKinfo *) opaque); QPAKinfo *info = ((QPAKinfo *) opaque);
allocator.Free(info->filename); info->io->destroy(info->io);
allocator.Free(info->entries); allocator.Free(info->entries);
allocator.Free(info); allocator.Free(info);
} /* QPAK_dirClose */ } /* 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 QPAKentry *entry = finfo->entry;
const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos); const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos);
PHYSFS_sint64 rc; PHYSFS_sint64 rc;
@ -92,7 +99,7 @@ static PHYSFS_sint64 QPAK_read(fvoid *opaque, void *buffer, PHYSFS_uint64 len)
if (bytesLeft < len) if (bytesLeft < len)
len = bytesLeft; len = bytesLeft;
rc = __PHYSFS_platformRead(finfo->handle, buffer, len); rc = finfo->io->read(finfo->io, buffer, len);
if (rc > 0) if (rc > 0)
finfo->curPos += (PHYSFS_uint32) rc; finfo->curPos += (PHYSFS_uint32) rc;
@ -100,35 +107,26 @@ static PHYSFS_sint64 QPAK_read(fvoid *opaque, void *buffer, PHYSFS_uint64 len)
} /* QPAK_read */ } /* 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); BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
} /* QPAK_write */ } /* QPAK_write */
static int QPAK_eof(fvoid *opaque) static PHYSFS_sint64 QPAK_tell(PHYSFS_Io *io)
{ {
QPAKfileinfo *finfo = (QPAKfileinfo *) opaque; return ((QPAKfileinfo *) io->opaque)->curPos;
QPAKentry *entry = finfo->entry;
return (finfo->curPos >= entry->size);
} /* QPAK_eof */
static PHYSFS_sint64 QPAK_tell(fvoid *opaque)
{
return ((QPAKfileinfo *) opaque)->curPos;
} /* QPAK_tell */ } /* 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; QPAKfileinfo *finfo = (QPAKfileinfo *) io->opaque;
QPAKentry *entry = finfo->entry; const QPAKentry *entry = finfo->entry;
int rc; int rc;
BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 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) if (rc)
finfo->curPos = (PHYSFS_uint32) offset; finfo->curPos = (PHYSFS_uint32) offset;
@ -136,74 +134,66 @@ static int QPAK_seek(fvoid *opaque, PHYSFS_uint64 offset)
} /* QPAK_seek */ } /* 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); 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; QPAKfileinfo *origfinfo = (QPAKfileinfo *) _io->opaque;
BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0); 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); allocator.Free(finfo);
return 1; allocator.Free(io);
} /* QPAK_fileClose */ } /* 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); QPAK_read,
} /* readAll */ QPAK_write,
QPAK_seek,
static int qpak_open(const char *filename, int forWriting, QPAK_tell,
void **fh, PHYSFS_uint32 *count) QPAK_length,
{ QPAK_duplicate,
PHYSFS_uint32 buf; QPAK_flush,
QPAK_destroy,
*fh = NULL; 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 */
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) if (one != two)
{ {
@ -212,10 +202,10 @@ static int qpak_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
} /* if */ } /* if */
return 0; 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) 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(first, second, sizeof (QPAKentry));
memcpy(second, &tmp, sizeof (QPAKentry)); memcpy(second, &tmp, sizeof (QPAKentry));
} /* if */ } /* 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_Io *io = info->io;
PHYSFS_uint32 fileCount; PHYSFS_uint32 fileCount = info->entryCount;
QPAKentry *entry; QPAKentry *entry;
BAIL_IF_MACRO(!qpak_open(name, forWriting, &fh, &fileCount), NULL, 0);
info->entryCount = fileCount;
info->entries = (QPAKentry*) allocator.Malloc(sizeof(QPAKentry)*fileCount); info->entries = (QPAKentry*) allocator.Malloc(sizeof(QPAKentry)*fileCount);
if (info->entries == NULL) BAIL_IF_MACRO(info->entries == NULL, ERR_OUT_OF_MEMORY, 0);
{
__PHYSFS_platformClose(fh);
BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
} /* if */
for (entry = info->entries; fileCount > 0; fileCount--, entry++) for (entry = info->entries; fileCount > 0; fileCount--, entry++)
{ {
if ( (!readAll(fh, &entry->name, sizeof (entry->name))) || BAIL_IF_MACRO(!readAll(io, &entry->name, 56), NULL, 0);
(!readAll(fh, &entry->startPos, sizeof (entry->startPos))) || BAIL_IF_MACRO(!readAll(io, &entry->startPos, 4), NULL, 0);
(!readAll(fh, &entry->size, sizeof(entry->size))) ) BAIL_IF_MACRO(!readAll(io, &entry->size, 4), NULL, 0);
{
__PHYSFS_platformClose(fh);
return 0;
} /* if */
entry->size = PHYSFS_swapULE32(entry->size); entry->size = PHYSFS_swapULE32(entry->size);
entry->startPos = PHYSFS_swapULE32(entry->startPos); entry->startPos = PHYSFS_swapULE32(entry->startPos);
} /* for */ } /* for */
__PHYSFS_platformClose(fh); __PHYSFS_sort(info->entries, info->entryCount, qpakEntryCmp, qpakEntrySwap);
__PHYSFS_sort(info->entries, info->entryCount,
qpak_entry_cmp, qpak_entry_swap);
return 1; return 1;
} /* qpak_load_entries */ } /* 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); BAIL_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, NULL);
memset(info, '\0', sizeof (QPAKinfo)); memset(info, '\0', sizeof (QPAKinfo));
info->io = io;
info->entryCount = count;
info->filename = (char *) allocator.Malloc(strlen(name) + 1); if (!qpak_load_entries(info))
if (info->filename == NULL)
{ {
__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) if (info->entries != NULL)
allocator.Free(info->entries); allocator.Free(info->entries);
allocator.Free(info); allocator.Free(info);
return NULL;
} /* if */ } /* if */
return NULL; return info;
} /* QPAK_openArchive */ } /* QPAK_openArchive */
@ -495,8 +481,9 @@ static int QPAK_isSymLink(dvoid *opaque, const char *name, int *fileExists)
} /* QPAK_isSymLink */ } /* 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); QPAKinfo *info = ((QPAKinfo *) opaque);
QPAKfileinfo *finfo; QPAKfileinfo *finfo;
QPAKentry *entry; QPAKentry *entry;
@ -510,27 +497,42 @@ static fvoid *QPAK_openRead(dvoid *opaque, const char *fnm, int *fileExists)
finfo = (QPAKfileinfo *) allocator.Malloc(sizeof (QPAKfileinfo)); finfo = (QPAKfileinfo *) allocator.Malloc(sizeof (QPAKfileinfo));
BAIL_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, NULL); BAIL_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, NULL);
finfo->handle = __PHYSFS_platformOpenRead(info->filename); finfo->io = info->io->duplicate(info->io);
if ( (finfo->handle == NULL) || GOTO_IF_MACRO(finfo->io == NULL, NULL, QPAK_openRead_failed);
(!__PHYSFS_platformSeek(finfo->handle, entry->startPos)) ) if (!finfo->io->seek(finfo->io, entry->startPos))
{ GOTO_MACRO(NULL, QPAK_openRead_failed);
allocator.Free(finfo);
return NULL;
} /* if */
finfo->curPos = 0; finfo->curPos = 0;
finfo->entry = entry; 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 */ } /* 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); BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* QPAK_openWrite */ } /* 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); BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* QPAK_openAppend */ } /* QPAK_openAppend */
@ -602,14 +604,7 @@ const PHYSFS_Archiver __PHYSFS_Archiver_QPAK =
QPAK_remove, /* remove() method */ QPAK_remove, /* remove() method */
QPAK_mkdir, /* mkdir() method */ QPAK_mkdir, /* mkdir() method */
QPAK_dirClose, /* dirClose() method */ QPAK_dirClose, /* dirClose() method */
QPAK_stat, /* stat() 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 */
}; };
#endif /* defined PHYSFS_SUPPORTS_QPAK */ #endif /* defined PHYSFS_SUPPORTS_QPAK */

View File

@ -61,32 +61,37 @@ typedef struct
typedef struct typedef struct
{ {
char *filename; PHYSFS_Io *io;
PHYSFS_uint32 entryCount; PHYSFS_uint32 entryCount;
PHYSFS_uint32 entryOffset;
WADentry *entries; WADentry *entries;
} WADinfo; } WADinfo;
typedef struct typedef struct
{ {
void *handle; PHYSFS_Io *io;
WADentry *entry; WADentry *entry;
PHYSFS_uint32 curPos; PHYSFS_uint32 curPos;
} WADfileinfo; } WADfileinfo;
static inline int readAll(PHYSFS_Io *io, void *buf, const PHYSFS_uint64 len)
{
return (io->read(io, buf, len) == len);
} /* readAll */
static void WAD_dirClose(dvoid *opaque) static void WAD_dirClose(dvoid *opaque)
{ {
WADinfo *info = ((WADinfo *) opaque); WADinfo *info = ((WADinfo *) opaque);
allocator.Free(info->filename); info->io->destroy(info->io);
allocator.Free(info->entries); allocator.Free(info->entries);
allocator.Free(info); allocator.Free(info);
} /* WAD_dirClose */ } /* 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 WADentry *entry = finfo->entry;
const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos); const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos);
PHYSFS_sint64 rc; PHYSFS_sint64 rc;
@ -94,7 +99,7 @@ static PHYSFS_sint64 WAD_read(fvoid *opaque, void *buffer, PHYSFS_uint64 len)
if (bytesLeft < len) if (bytesLeft < len)
len = bytesLeft; len = bytesLeft;
rc = __PHYSFS_platformRead(finfo->handle, buffer, len); rc = finfo->io->read(finfo->io, buffer, len);
if (rc > 0) if (rc > 0)
finfo->curPos += (PHYSFS_uint32) rc; finfo->curPos += (PHYSFS_uint32) rc;
@ -102,35 +107,26 @@ static PHYSFS_sint64 WAD_read(fvoid *opaque, void *buffer, PHYSFS_uint64 len)
} /* WAD_read */ } /* 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); BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
} /* WAD_write */ } /* WAD_write */
static int WAD_eof(fvoid *opaque) static PHYSFS_sint64 WAD_tell(PHYSFS_Io *io)
{ {
WADfileinfo *finfo = (WADfileinfo *) opaque; return ((WADfileinfo *) io->opaque)->curPos;
WADentry *entry = finfo->entry;
return (finfo->curPos >= entry->size);
} /* WAD_eof */
static PHYSFS_sint64 WAD_tell(fvoid *opaque)
{
return ((WADfileinfo *) opaque)->curPos;
} /* WAD_tell */ } /* 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; WADfileinfo *finfo = (WADfileinfo *) io->opaque;
WADentry *entry = finfo->entry; const WADentry *entry = finfo->entry;
int rc; int rc;
BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 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) if (rc)
finfo->curPos = (PHYSFS_uint32) offset; finfo->curPos = (PHYSFS_uint32) offset;
@ -138,83 +134,77 @@ static int WAD_seek(fvoid *opaque, PHYSFS_uint64 offset)
} /* WAD_seek */ } /* 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); 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; WADfileinfo *origfinfo = (WADfileinfo *) _io->opaque;
BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0); PHYSFS_Io *io = NULL;
PHYSFS_Io *retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
WADfileinfo *finfo = (WADfileinfo *) allocator.Malloc(sizeof (WADfileinfo));
GOTO_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, WAD_duplicate_failed);
GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, WAD_duplicate_failed);
io = origfinfo->io->duplicate(origfinfo->io);
GOTO_IF_MACRO(io == NULL, NULL, WAD_duplicate_failed);
finfo->io = io;
finfo->entry = origfinfo->entry;
finfo->curPos = 0;
memcpy(retval, _io, sizeof (PHYSFS_Io));
retval->opaque = finfo;
return retval;
WAD_duplicate_failed:
if (finfo != NULL) allocator.Free(finfo);
if (retval != NULL) allocator.Free(retval);
if (io != NULL) io->destroy(io);
return NULL;
} /* WAD_duplicate */
static int WAD_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
static void WAD_destroy(PHYSFS_Io *io)
{
WADfileinfo *finfo = (WADfileinfo *) io->opaque;
finfo->io->destroy(finfo->io);
allocator.Free(finfo); allocator.Free(finfo);
return 1; allocator.Free(io);
} /* WAD_fileClose */ } /* 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); WAD_read,
} /* readAll */ 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; static int wadEntryCmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
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)
{ {
if (one != two) if (one != two)
{ {
const WADentry *a = (const WADentry *) _a; const WADentry *a = (const WADentry *) _a;
return strcmp(a[one].name, a[two].name); return __PHYSFS_stricmpASCII(a[one].name, a[two].name);
} /* if */ } /* if */
return 0; 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) 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(first, second, sizeof (WADentry));
memcpy(second, &tmp, sizeof (WADentry)); memcpy(second, &tmp, sizeof (WADentry));
} /* if */ } /* 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 = info->entryCount;
PHYSFS_uint32 fileCount;
PHYSFS_uint32 directoryOffset; PHYSFS_uint32 directoryOffset;
WADentry *entry; 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); info->entries = (WADentry *) allocator.Malloc(sizeof(WADentry)*fileCount);
if (info->entries == NULL) BAIL_IF_MACRO(info->entries == NULL, ERR_OUT_OF_MEMORY, 0);
{ BAIL_IF_MACRO(!io->seek(io, directoryOffset), NULL, 0);
__PHYSFS_platformClose(fh);
BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
} /* if */
__PHYSFS_platformSeek(fh,directoryOffset);
for (entry = info->entries; fileCount > 0; fileCount--, entry++) for (entry = info->entries; fileCount > 0; fileCount--, entry++)
{ {
if ( (!readAll(fh, &entry->startPos, sizeof (PHYSFS_uint32))) || BAIL_IF_MACRO(!readAll(io, &entry->startPos, 4), NULL, 0);
(!readAll(fh, &entry->size, sizeof (PHYSFS_uint32))) || BAIL_IF_MACRO(!readAll(io, &entry->size, 4), NULL, 0);
(!readAll(fh, &entry->name, 8)) ) BAIL_IF_MACRO(!readAll(io, &entry->name, 8), NULL, 0);
{
__PHYSFS_platformClose(fh);
return 0;
} /* if */
entry->name[8] = '\0'; /* name might not be null-terminated in file. */ entry->name[8] = '\0'; /* name might not be null-terminated in file. */
entry->size = PHYSFS_swapULE32(entry->size); entry->size = PHYSFS_swapULE32(entry->size);
entry->startPos = PHYSFS_swapULE32(entry->startPos); entry->startPos = PHYSFS_swapULE32(entry->startPos);
} /* for */ } /* for */
__PHYSFS_platformClose(fh); __PHYSFS_sort(info->entries, info->entryCount, wadEntryCmp, wadEntrySwap);
__PHYSFS_sort(info->entries, info->entryCount,
wad_entry_cmp, wad_entry_swap);
return 1; return 1;
} /* wad_load_entries */ } /* 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)); memset(info, '\0', sizeof (WADinfo));
info->io = io;
info->filename = (char *) allocator.Malloc(strlen(name) + 1); GOTO_IF_MACRO(!readAll(io,&val,sizeof(val)), NULL, WAD_openArchive_failed);
GOTO_IF_MACRO(!info->filename, ERR_OUT_OF_MEMORY, WAD_openArchive_failed); info->entryCount = PHYSFS_swapULE32(val);
if (!wad_load_entries(name, forWriting, info)) GOTO_IF_MACRO(!wad_load_entries(io, info), NULL, WAD_openArchive_failed);
goto WAD_openArchive_failed;
strcpy(info->filename, name);
return info; return info;
WAD_openArchive_failed: WAD_openArchive_failed:
if (info != NULL) if (info != NULL)
{ {
if (info->filename != NULL)
allocator.Free(info->filename);
if (info->entries != NULL) if (info->entries != NULL)
allocator.Free(info->entries); allocator.Free(info->entries);
allocator.Free(info); allocator.Free(info);
@ -306,50 +289,41 @@ static void WAD_enumerateFiles(dvoid *opaque, const char *dname,
int omitSymLinks, PHYSFS_EnumFilesCallback cb, int omitSymLinks, PHYSFS_EnumFilesCallback cb,
const char *origdir, void *callbackdata) const char *origdir, void *callbackdata)
{ {
WADinfo *info = ((WADinfo *) opaque); /* no directories in WAD files. */
WADentry *entry = info->entries; if (*dname == '\0')
PHYSFS_uint32 max = info->entryCount; {
PHYSFS_uint32 i; WADinfo *info = (WADinfo *) opaque;
const char *name; WADentry *entry = info->entries;
char *sep; PHYSFS_uint32 max = info->entryCount;
PHYSFS_uint32 i;
if (*dname == '\0') /* root directory enumeration? */
{
for (i = 0; i < max; i++, entry++) for (i = 0; i < max; i++, entry++)
{ cb(callbackdata, origdir, entry->name);
name = entry->name;
if (strchr(name, '/') == NULL)
cb(callbackdata, origdir, name);
} /* for */
} /* if */ } /* 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 */ } /* WAD_enumerateFiles */
static WADentry *wad_find_entry(const WADinfo *info, const char *name) static WADentry *wad_find_entry(const WADinfo *info, const char *name)
{ {
char *ptr = strchr(name, '.');
WADentry *a = info->entries; WADentry *a = info->entries;
PHYSFS_sint32 lo = 0; PHYSFS_sint32 lo = 0;
PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1); PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
PHYSFS_sint32 middle; PHYSFS_sint32 middle;
int rc; 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) while (lo <= hi)
{ {
middle = lo + ((hi - lo) / 2); middle = lo + ((hi - lo) / 2);
rc = strcmp(name, a[middle].name); rc = __PHYSFS_stricmpASCII(name, a[middle].name);
if (rc == 0) /* found it! */ if (rc == 0) /* found it! */
return &a[middle]; return &a[middle];
else if (rc > 0) 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) static int WAD_isDirectory(dvoid *opaque, const char *name, int *fileExists)
{ {
WADentry *entry = wad_find_entry(((WADinfo *) opaque), name); WADentry *entry = wad_find_entry(((WADinfo *) opaque), name);
if (entry != NULL) const int exists = (entry != NULL);
*fileExists = exists;
if (exists)
{ {
char *n; char *n;
*fileExists = 1;
/* Can't be a directory if it's a subdirectory. */ /* Can't be a directory if it's a subdirectory. */
if (strchr(entry->name, '/') != NULL) if (strchr(entry->name, '/') != NULL)
return 0; 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?" ... */ /* Check if it matches "MAP??" or "E?M?" ... */
n = entry->name; n = entry->name;
if ((n[0] == 'E' && n[2] == 'M') || if ((n[0] == 'E' && n[2] == 'M') ||
@ -388,13 +364,9 @@ static int WAD_isDirectory(dvoid *opaque, const char *name, int *fileExists)
{ {
return 1; return 1;
} /* if */ } /* if */
return 0;
} /* if */ } /* if */
else
{ return 0;
*fileExists = 0;
return 0;
} /* else */
} /* WAD_isDirectory */ } /* WAD_isDirectory */
@ -405,40 +377,58 @@ static int WAD_isSymLink(dvoid *opaque, const char *name, int *fileExists)
} /* WAD_isSymLink */ } /* 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; WADfileinfo *finfo;
WADentry *entry; WADentry *entry;
entry = wad_find_entry(info, fnm); entry = wad_find_entry(info, fnm);
*fileExists = (entry != NULL); *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)); 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); finfo->io = info->io->duplicate(info->io);
if ( (finfo->handle == NULL) || GOTO_IF_MACRO(finfo->io == NULL, NULL, WAD_openRead_failed);
(!__PHYSFS_platformSeek(finfo->handle, entry->startPos)) )
{ if (!finfo->io->seek(finfo->io, entry->startPos))
allocator.Free(finfo); GOTO_MACRO(NULL, WAD_openRead_failed);
return NULL;
} /* if */
finfo->curPos = 0; finfo->curPos = 0;
finfo->entry = entry; 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 */ } /* 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); BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* WAD_openWrite */ } /* 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); BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* WAD_openAppend */ } /* WAD_openAppend */
@ -468,10 +458,10 @@ static int WAD_stat(dvoid *opaque, const char *filename, int *exists,
stat->filesize = entry->size; stat->filesize = entry->size;
stat->filetype = PHYSFS_FILETYPE_REGULAR; stat->filetype = PHYSFS_FILETYPE_REGULAR;
stat->accesstime = -1;
stat->modtime = -1; stat->modtime = -1;
stat->createtime = -1; stat->createtime = -1;
stat->readonly = 1; /* WADs are always readonly */ stat->accesstime = -1;
stat->readonly = 1;
return 1; return 1;
} /* WAD_stat */ } /* WAD_stat */
@ -500,14 +490,7 @@ const PHYSFS_Archiver __PHYSFS_Archiver_WAD =
WAD_remove, /* remove() method */ WAD_remove, /* remove() method */
WAD_mkdir, /* mkdir() method */ WAD_mkdir, /* mkdir() method */
WAD_dirClose, /* dirClose() method */ WAD_dirClose, /* dirClose() method */
WAD_stat, /* stat() 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 */
}; };
#endif /* defined PHYSFS_SUPPORTS_WAD */ #endif /* defined PHYSFS_SUPPORTS_WAD */

View File

@ -79,7 +79,7 @@ typedef struct _ZIPentry
*/ */
typedef struct typedef struct
{ {
char *archiveName; /* path to ZIP in platform-dependent notation. */ PHYSFS_Io *io;
PHYSFS_uint16 entryCount; /* Number of files in ZIP. */ PHYSFS_uint16 entryCount; /* Number of files in ZIP. */
ZIPentry *entries; /* info on all files in ZIP. */ ZIPentry *entries; /* info on all files in ZIP. */
} ZIPinfo; } ZIPinfo;
@ -90,7 +90,7 @@ typedef struct
typedef struct typedef struct
{ {
ZIPentry *entry; /* Info on file. */ 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 compressed_position; /* offset in compressed data. */
PHYSFS_uint32 uncompressed_position; /* tell() position. */ PHYSFS_uint32 uncompressed_position; /* tell() position. */
PHYSFS_uint8 *buffer; /* decompression buffer. */ PHYSFS_uint8 *buffer; /* decompression buffer. */
@ -172,18 +172,18 @@ static int zlib_err(int rc)
} /* zlib_err */ } /* 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 */ } /* readAll */
/* /*
* Read an unsigned 32-bit int and swap to native byte order. * 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; 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); *val = PHYSFS_swapULE32(v);
return 1; return 1;
} /* readui32 */ } /* 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. * 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; 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); *val = PHYSFS_swapULE16(v);
return 1; return 1;
} /* readui16 */ } /* 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; ZIPentry *entry = finfo->entry;
PHYSFS_sint64 retval = 0; PHYSFS_sint64 retval = 0;
PHYSFS_sint64 maxread = (PHYSFS_sint64) len; 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. */ BAIL_IF_MACRO(maxread == 0, NULL, 0); /* quick rejection. */
if (entry->compression_method == COMPMETH_NONE) if (entry->compression_method == COMPMETH_NONE)
retval = __PHYSFS_platformRead(finfo->handle, buf, maxread); retval = io->read(io, buf, maxread);
else else
{ {
finfo->stream.next_out = buf; 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) if (br > ZIP_READBUFSIZE)
br = ZIP_READBUFSIZE; br = ZIP_READBUFSIZE;
br = __PHYSFS_platformRead(finfo->handle, finfo->buffer, br = io->read(io, finfo->buffer, (PHYSFS_uint64) br);
(PHYSFS_uint64) br);
if (br <= 0) if (br <= 0)
break; break;
@ -263,37 +263,30 @@ static PHYSFS_sint64 ZIP_read(fvoid *opaque, void *buf, PHYSFS_uint64 len)
} /* ZIP_read */ } /* 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); BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
} /* ZIP_write */ } /* ZIP_write */
static int ZIP_eof(fvoid *opaque) static PHYSFS_sint64 ZIP_tell(PHYSFS_Io *io)
{ {
ZIPfileinfo *finfo = (ZIPfileinfo *) opaque; return ((ZIPfileinfo *) io->opaque)->uncompressed_position;
return (finfo->uncompressed_position >= finfo->entry->uncompressed_size);
} /* ZIP_eof */
static PHYSFS_sint64 ZIP_tell(fvoid *opaque)
{
return ((ZIPfileinfo *) opaque)->uncompressed_position;
} /* ZIP_tell */ } /* 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; ZIPentry *entry = finfo->entry;
void *in = finfo->handle; PHYSFS_Io *io = finfo->io;
BAIL_IF_MACRO(offset > entry->uncompressed_size, ERR_PAST_EOF, 0); BAIL_IF_MACRO(offset > entry->uncompressed_size, ERR_PAST_EOF, 0);
if (entry->compression_method == COMPMETH_NONE) if (entry->compression_method == COMPMETH_NONE)
{ {
PHYSFS_sint64 newpos = offset + entry->offset; const PHYSFS_sint64 newpos = offset + entry->offset;
BAIL_IF_MACRO(!__PHYSFS_platformSeek(in, newpos), NULL, 0); BAIL_IF_MACRO(!io->seek(io, newpos), NULL, 0);
finfo->uncompressed_position = (PHYSFS_uint32) offset; finfo->uncompressed_position = (PHYSFS_uint32) offset;
} /* if */ } /* if */
@ -313,7 +306,7 @@ static int ZIP_seek(fvoid *opaque, PHYSFS_uint64 offset)
if (zlib_err(inflateInit2(&str, -MAX_WBITS)) != Z_OK) if (zlib_err(inflateInit2(&str, -MAX_WBITS)) != Z_OK)
return 0; return 0;
if (!__PHYSFS_platformSeek(in, entry->offset)) if (!io->seek(io, entry->offset))
return 0; return 0;
inflateEnd(&finfo->stream); inflateEnd(&finfo->stream);
@ -330,7 +323,7 @@ static int ZIP_seek(fvoid *opaque, PHYSFS_uint64 offset)
if (maxread > sizeof (buf)) if (maxread > sizeof (buf))
maxread = sizeof (buf); maxread = sizeof (buf);
if (ZIP_read(finfo, buf, maxread) != maxread) if (ZIP_read(_io, buf, maxread) != maxread)
return 0; return 0;
} /* while */ } /* while */
} /* else */ } /* else */
@ -339,17 +332,67 @@ static int ZIP_seek(fvoid *opaque, PHYSFS_uint64 offset)
} /* ZIP_seek */ } /* 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; 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; ZIPfileinfo *origfinfo = (ZIPfileinfo *) io->opaque;
BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0); 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) if (finfo->entry->compression_method != COMPMETH_NONE)
inflateEnd(&finfo->stream); inflateEnd(&finfo->stream);
@ -358,11 +401,26 @@ static int ZIP_fileClose(fvoid *opaque)
allocator.Free(finfo->buffer); allocator.Free(finfo->buffer);
allocator.Free(finfo); allocator.Free(finfo);
return 1; allocator.Free(io);
} /* ZIP_fileClose */ } /* 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 buf[256];
PHYSFS_uint8 extra[4] = { 0, 0, 0, 0 }; 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; PHYSFS_sint32 totalread = 0;
int found = 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 == -1, NULL, 0); /* !!! FIXME: unlocalized string */
BAIL_IF_MACRO(filelen > 0xFFFFFFFF, "ZIP bigger than 4 gigs?!", 0); 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)) 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. */ /* make sure we catch a signature between buffers. */
if (totalread != 0) if (totalread != 0)
{ {
if (!readAll(in, buf, maxread - 4)) if (!readAll(io, buf, maxread - 4))
return -1; return -1;
memcpy(&buf[maxread - 4], &extra, sizeof (extra)); memcpy(&buf[maxread - 4], &extra, sizeof (extra));
totalread += maxread - 4; totalread += maxread - 4;
} /* if */ } /* if */
else else
{ {
if (!readAll(in, buf, maxread)) if (!readAll(io, buf, maxread))
return -1; return -1;
totalread += maxread; totalread += maxread;
} /* else */ } /* 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 */ } /* zip_find_end_of_central_dir */
/* !!! FIXME: don't open/close file here, merge with openArchive(). */ static int isZip(PHYSFS_Io *io)
static int isZip(const char *filename)
{ {
PHYSFS_uint32 sig; PHYSFS_uint32 sig = 0;
int retval = 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 * The first thing in a zip file might be the signature of the
* first local file record, so it makes for a quick determination. * 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); retval = (sig == ZIP_LOCAL_FILE_SIG);
if (!retval) if (!retval)
@ -474,11 +527,10 @@ static int isZip(const char *filename)
* (a self-extracting executable, etc), so we'll have to do * (a self-extracting executable, etc), so we'll have to do
* it the hard way... * 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 */
} /* if */ } /* if */
__PHYSFS_platformClose(in);
return retval; return retval;
} /* isZip */ } /* isZip */
@ -622,7 +674,7 @@ static void zip_expand_symlink_path(char *path)
} /* zip_expand_symlink_path */ } /* zip_expand_symlink_path */
/* (forward reference: zip_follow_symlink and zip_resolve call each other.) */ /* (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 * 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 * If there's a problem, return NULL. (path) is always free()'d by this
* function. * 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; ZIPentry *entry;
@ -639,7 +691,7 @@ static ZIPentry *zip_follow_symlink(void *in, ZIPinfo *info, char *path)
entry = zip_find_entry(info, path, NULL); entry = zip_find_entry(info, path, NULL);
if (entry != NULL) if (entry != NULL)
{ {
if (!zip_resolve(in, info, entry)) /* recursive! */ if (!zip_resolve(io, info, entry)) /* recursive! */
entry = NULL; entry = NULL;
else else
{ {
@ -653,10 +705,10 @@ static ZIPentry *zip_follow_symlink(void *in, ZIPinfo *info, char *path)
} /* zip_follow_symlink */ } /* 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; char *path;
PHYSFS_uint32 size = entry->uncompressed_size; const PHYSFS_uint32 size = entry->uncompressed_size;
int rc = 0; int rc = 0;
/* /*
@ -665,22 +717,22 @@ static int zip_resolve_symlink(void *in, ZIPinfo *info, ZIPentry *entry)
* follow it. * 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); path = (char *) allocator.Malloc(size + 1);
BAIL_IF_MACRO(path == NULL, ERR_OUT_OF_MEMORY, 0); BAIL_IF_MACRO(path == NULL, ERR_OUT_OF_MEMORY, 0);
if (entry->compression_method == COMPMETH_NONE) if (entry->compression_method == COMPMETH_NONE)
rc = readAll(in, path, size); rc = readAll(io, path, size);
else /* symlink target path is compressed... */ else /* symlink target path is compressed... */
{ {
z_stream stream; z_stream stream;
PHYSFS_uint32 complen = entry->compressed_size; const PHYSFS_uint32 complen = entry->compressed_size;
PHYSFS_uint8 *compressed = (PHYSFS_uint8*) __PHYSFS_smallAlloc(complen); PHYSFS_uint8 *compressed = (PHYSFS_uint8*) __PHYSFS_smallAlloc(complen);
if (compressed != NULL) if (compressed != NULL)
{ {
if (readAll(in, compressed, complen)) if (readAll(io, compressed, complen))
{ {
initializeZStream(&stream); initializeZStream(&stream);
stream.next_in = compressed; 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. */ path[entry->uncompressed_size] = '\0'; /* null-terminate it. */
zip_convert_dos_path(entry, path); zip_convert_dos_path(entry, path);
entry->symlink = zip_follow_symlink(in, info, path); entry->symlink = zip_follow_symlink(io, info, path);
} /* else */ } /* else */
return (entry->symlink != NULL); 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. * 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_uint32 ui32;
PHYSFS_uint16 ui16; PHYSFS_uint16 ui16;
@ -730,30 +782,30 @@ static int zip_parse_local(void *in, ZIPentry *entry)
* aren't zero. That seems to work well. * aren't zero. That seems to work well.
*/ */
BAIL_IF_MACRO(!__PHYSFS_platformSeek(in, entry->offset), NULL, 0); BAIL_IF_MACRO(!io->seek(io, entry->offset), NULL, 0);
BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0); BAIL_IF_MACRO(!readui32(io, &ui32), NULL, 0);
BAIL_IF_MACRO(ui32 != ZIP_LOCAL_FILE_SIG, ERR_CORRUPTED, 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(ui16 != entry->version_needed, ERR_CORRUPTED, 0);
BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0); /* general bits. */ BAIL_IF_MACRO(!readui16(io, &ui16), NULL, 0); /* general bits. */
BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0); BAIL_IF_MACRO(!readui16(io, &ui16), NULL, 0);
BAIL_IF_MACRO(ui16 != entry->compression_method, ERR_CORRUPTED, 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(io, &ui32), NULL, 0); /* date/time */
BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0); BAIL_IF_MACRO(!readui32(io, &ui32), NULL, 0);
BAIL_IF_MACRO(ui32 && (ui32 != entry->crc), ERR_CORRUPTED, 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(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(ui32 && (ui32 != entry->uncompressed_size),ERR_CORRUPTED,0);
BAIL_IF_MACRO(!readui16(in, &fnamelen), NULL, 0); BAIL_IF_MACRO(!readui16(io, &fnamelen), NULL, 0);
BAIL_IF_MACRO(!readui16(in, &extralen), NULL, 0); BAIL_IF_MACRO(!readui16(io, &extralen), NULL, 0);
entry->offset += fnamelen + extralen + 30; entry->offset += fnamelen + extralen + 30;
return 1; return 1;
} /* zip_parse_local */ } /* 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; int retval = 1;
ZipResolveType resolve_type = entry->resolved; ZipResolveType resolve_type = entry->resolved;
@ -776,7 +828,7 @@ static int zip_resolve(void *in, ZIPinfo *info, ZIPentry *entry)
{ {
entry->resolved = ZIP_RESOLVING; entry->resolved = ZIP_RESOLVING;
retval = zip_parse_local(in, entry); retval = zip_parse_local(io, entry);
if (retval) if (retval)
{ {
/* /*
@ -785,7 +837,7 @@ static int zip_resolve(void *in, ZIPinfo *info, ZIPentry *entry)
* the real file) if all goes well. * the real file) if all goes well.
*/ */
if (resolve_type == ZIP_UNRESOLVED_SYMLINK) if (resolve_type == ZIP_UNRESOLVED_SYMLINK)
retval = zip_resolve_symlink(in, info, entry); retval = zip_resolve_symlink(io, info, entry);
} /* if */ } /* if */
if (resolve_type == ZIP_UNRESOLVED_SYMLINK) 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 */ } /* 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_uint16 fnamelen, extralen, commentlen;
PHYSFS_uint32 external_attr; PHYSFS_uint32 external_attr;
@ -889,26 +941,26 @@ static int zip_load_entry(void *in, ZIPentry *entry, PHYSFS_uint32 ofs_fixup)
PHYSFS_sint64 si64; PHYSFS_sint64 si64;
/* sanity check with central directory signature... */ /* 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); BAIL_IF_MACRO(ui32 != ZIP_CENTRAL_DIR_SIG, ERR_CORRUPTED, 0);
/* Get the pertinent parts of the record... */ /* Get the pertinent parts of the record... */
BAIL_IF_MACRO(!readui16(in, &entry->version), NULL, 0); BAIL_IF_MACRO(!readui16(io, &entry->version), NULL, 0);
BAIL_IF_MACRO(!readui16(in, &entry->version_needed), NULL, 0); BAIL_IF_MACRO(!readui16(io, &entry->version_needed), NULL, 0);
BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0); /* general bits */ BAIL_IF_MACRO(!readui16(io, &ui16), NULL, 0); /* general bits */
BAIL_IF_MACRO(!readui16(in, &entry->compression_method), NULL, 0); BAIL_IF_MACRO(!readui16(io, &entry->compression_method), NULL, 0);
BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0); BAIL_IF_MACRO(!readui32(io, &ui32), NULL, 0);
entry->last_mod_time = zip_dos_time_to_physfs_time(ui32); entry->last_mod_time = zip_dos_time_to_physfs_time(ui32);
BAIL_IF_MACRO(!readui32(in, &entry->crc), NULL, 0); BAIL_IF_MACRO(!readui32(io, &entry->crc), NULL, 0);
BAIL_IF_MACRO(!readui32(in, &entry->compressed_size), NULL, 0); BAIL_IF_MACRO(!readui32(io, &entry->compressed_size), NULL, 0);
BAIL_IF_MACRO(!readui32(in, &entry->uncompressed_size), NULL, 0); BAIL_IF_MACRO(!readui32(io, &entry->uncompressed_size), NULL, 0);
BAIL_IF_MACRO(!readui16(in, &fnamelen), NULL, 0); BAIL_IF_MACRO(!readui16(io, &fnamelen), NULL, 0);
BAIL_IF_MACRO(!readui16(in, &extralen), NULL, 0); BAIL_IF_MACRO(!readui16(io, &extralen), NULL, 0);
BAIL_IF_MACRO(!readui16(in, &commentlen), NULL, 0); BAIL_IF_MACRO(!readui16(io, &commentlen), NULL, 0);
BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0); /* disk number start */ BAIL_IF_MACRO(!readui16(io, &ui16), NULL, 0); /* disk number start */
BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0); /* internal file attribs */ BAIL_IF_MACRO(!readui16(io, &ui16), NULL, 0); /* internal file attribs */
BAIL_IF_MACRO(!readui32(in, &external_attr), NULL, 0); BAIL_IF_MACRO(!readui32(io, &external_attr), NULL, 0);
BAIL_IF_MACRO(!readui32(in, &entry->offset), NULL, 0); BAIL_IF_MACRO(!readui32(io, &entry->offset), NULL, 0);
entry->offset += ofs_fixup; entry->offset += ofs_fixup;
entry->symlink = NULL; /* will be resolved later, if necessary. */ 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); entry->name = (char *) allocator.Malloc(fnamelen + 1);
BAIL_IF_MACRO(entry->name == NULL, ERR_OUT_OF_MEMORY, 0); 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; goto zip_load_entry_puked;
entry->name[fnamelen] = '\0'; /* null-terminate the filename. */ entry->name[fnamelen] = '\0'; /* null-terminate the filename. */
zip_convert_dos_path(entry, entry->name); zip_convert_dos_path(entry, entry->name);
si64 = __PHYSFS_platformTell(in); si64 = io->tell(io);
if (si64 == -1) if (si64 == -1)
goto zip_load_entry_puked; goto zip_load_entry_puked;
/* seek to the start of the next entry in the central directory... */ /* 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; goto zip_load_entry_puked;
return 1; /* success. */ return 1; /* success. */
@ -965,20 +1017,20 @@ static void zip_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
} /* zip_entry_swap */ } /* 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 data_ofs, PHYSFS_uint32 central_ofs)
{ {
PHYSFS_uint32 max = info->entryCount; PHYSFS_uint32 max = info->entryCount;
PHYSFS_uint32 i; 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); info->entries = (ZIPentry *) allocator.Malloc(sizeof (ZIPentry) * max);
BAIL_IF_MACRO(info->entries == NULL, ERR_OUT_OF_MEMORY, 0); BAIL_IF_MACRO(info->entries == NULL, ERR_OUT_OF_MEMORY, 0);
for (i = 0; i < max; i++) 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); zip_free_entries(info->entries, i);
return 0; return 0;
@ -990,7 +1042,7 @@ static int zip_load_entries(void *in, ZIPinfo *info,
} /* zip_load_entries */ } /* 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 *data_start,
PHYSFS_uint32 *central_dir_ofs) PHYSFS_uint32 *central_dir_ofs)
{ {
@ -1000,34 +1052,34 @@ static int zip_parse_end_of_central_dir(void *in, ZIPinfo *info,
PHYSFS_sint64 pos; PHYSFS_sint64 pos;
/* find the end-of-central-dir record, and seek to it. */ /* 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(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. */ /* 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); BAIL_IF_MACRO(ui32 != ZIP_END_OF_CENTRAL_DIR_SIG, ERR_NOT_AN_ARCHIVE, 0);
/* number of this disk */ /* 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); BAIL_IF_MACRO(ui16 != 0, ERR_UNSUPPORTED_ARCHIVE, 0);
/* number of the disk with the start of the central directory */ /* 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); BAIL_IF_MACRO(ui16 != 0, ERR_UNSUPPORTED_ARCHIVE, 0);
/* total number of entries in the central dir on this disk */ /* 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 */ /* 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); BAIL_IF_MACRO(ui16 != info->entryCount, ERR_UNSUPPORTED_ARCHIVE, 0);
/* size of the central directory */ /* 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 */ /* 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); 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; *central_dir_ofs += *data_start;
/* zipfile comment length */ /* 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... * 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 */ } /* 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; ZIPinfo *info = NULL;
PHYSFS_uint32 data_start; PHYSFS_uint32 data_start;
PHYSFS_uint32 cent_dir_ofs; 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(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) info = (ZIPinfo *) allocator.Malloc(sizeof (ZIPinfo));
goto zip_openarchive_failed; BAIL_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, NULL);
memset(info, '\0', sizeof (ZIPinfo));
if ((info = zip_create_zipinfo(name)) == NULL) info->io = io;
goto zip_openarchive_failed;
if (!zip_parse_end_of_central_dir(in, info, &data_start, &cent_dir_ofs)) if (!zip_parse_end_of_central_dir(io, info, &data_start, &cent_dir_ofs))
goto zip_openarchive_failed; goto ZIP_openarchive_failed;
if (!zip_load_entries(in, info, data_start, cent_dir_ofs)) if (!zip_load_entries(io, info, data_start, cent_dir_ofs))
goto zip_openarchive_failed; goto ZIP_openarchive_failed;
__PHYSFS_platformClose(in);
return info; return info;
zip_openarchive_failed: ZIP_openarchive_failed:
if (info != NULL) if (info != NULL)
{
if (info->archiveName != NULL)
allocator.Free(info->archiveName);
allocator.Free(info); allocator.Free(info);
} /* if */
if (in != NULL)
__PHYSFS_platformClose(in);
return NULL; return NULL;
} /* ZIP_openArchive */ } /* 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. */ if (entry->resolved == ZIP_UNRESOLVED_SYMLINK) /* gotta resolve it. */
{ {
int rc; if (!zip_resolve(info->io, info, entry))
void *in = __PHYSFS_platformOpenRead(info->archiveName);
BAIL_IF_MACRO(in == NULL, NULL, 0);
rc = zip_resolve(in, info, entry);
__PHYSFS_platformClose(in);
if (!rc)
return 0; return 0;
} /* if */ } /* if */
@ -1283,81 +1302,95 @@ static int ZIP_isSymLink(dvoid *opaque, const char *name, int *fileExists)
} /* ZIP_isSymLink */ } /* 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; int success;
void *retval = __PHYSFS_platformOpenRead(fn); PHYSFS_Io *retval = io->duplicate(io);
BAIL_IF_MACRO(retval == NULL, NULL, NULL); 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) if (success)
{ {
PHYSFS_sint64 offset; PHYSFS_sint64 offset;
offset = ((entry->symlink) ? entry->symlink->offset : entry->offset); offset = ((entry->symlink) ? entry->symlink->offset : entry->offset);
success = __PHYSFS_platformSeek(retval, offset); success = retval->seek(retval, offset);
} /* if */ } /* if */
if (!success) if (!success)
{ {
__PHYSFS_platformClose(retval); retval->destroy(retval);
retval = NULL; retval = NULL;
} /* if */ } /* if */
return retval; 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; ZIPinfo *info = (ZIPinfo *) opaque;
ZIPentry *entry = zip_find_entry(info, fnm, NULL); ZIPentry *entry = zip_find_entry(info, fnm, NULL);
ZIPfileinfo *finfo = NULL; ZIPfileinfo *finfo = NULL;
void *in;
*fileExists = (entry != NULL); *fileExists = (entry != NULL);
BAIL_IF_MACRO(entry == NULL, NULL, NULL); BAIL_IF_MACRO(entry == NULL, NULL, NULL);
in = zip_get_file_handle(info->archiveName, info, entry); retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
BAIL_IF_MACRO(in == NULL, NULL, NULL); GOTO_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
finfo = (ZIPfileinfo *) allocator.Malloc(sizeof (ZIPfileinfo)); finfo = (ZIPfileinfo *) allocator.Malloc(sizeof (ZIPfileinfo));
if (finfo == NULL) GOTO_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
{
__PHYSFS_platformClose(in);
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
} /* if */
memset(finfo, '\0', sizeof (ZIPfileinfo)); 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); finfo->entry = ((entry->symlink != NULL) ? entry->symlink : entry);
initializeZStream(&finfo->stream); initializeZStream(&finfo->stream);
if (finfo->entry->compression_method != COMPMETH_NONE) 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); finfo->buffer = (PHYSFS_uint8 *) allocator.Malloc(ZIP_READBUFSIZE);
if (finfo->buffer == NULL) GOTO_IF_MACRO(!finfo->buffer, ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
{ if (zlib_err(inflateInit2(&finfo->stream, -MAX_WBITS)) != Z_OK)
ZIP_fileClose(finfo); goto ZIP_openRead_failed;
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
} /* if */
} /* if */ } /* 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 */ } /* 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); BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* ZIP_openWrite */ } /* 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); BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* ZIP_openAppend */ } /* ZIP_openAppend */
@ -1366,8 +1399,8 @@ static fvoid *ZIP_openAppend(dvoid *opaque, const char *filename)
static void ZIP_dirClose(dvoid *opaque) static void ZIP_dirClose(dvoid *opaque)
{ {
ZIPinfo *zi = (ZIPinfo *) (opaque); ZIPinfo *zi = (ZIPinfo *) (opaque);
zi->io->destroy(zi->io);
zip_free_entries(zi->entries, zi->entryCount); zip_free_entries(zi->entries, zi->entryCount);
allocator.Free(zi->archiveName);
allocator.Free(zi); allocator.Free(zi);
} /* ZIP_dirClose */ } /* ZIP_dirClose */
@ -1445,14 +1478,7 @@ const PHYSFS_Archiver __PHYSFS_Archiver_ZIP =
ZIP_remove, /* remove() method */ ZIP_remove, /* remove() method */
ZIP_mkdir, /* mkdir() method */ ZIP_mkdir, /* mkdir() method */
ZIP_dirClose, /* dirClose() method */ ZIP_dirClose, /* dirClose() method */
ZIP_stat, /* stat() 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 */
}; };
#endif /* defined PHYSFS_SUPPORTS_ZIP */ #endif /* defined PHYSFS_SUPPORTS_ZIP */

View File

@ -31,10 +31,9 @@ typedef struct __PHYSFS_DIRHANDLE__
typedef struct __PHYSFS_FILEHANDLE__ 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 */ PHYSFS_uint8 forReading; /* Non-zero if reading, zero if write/append */
const DirHandle *dirHandle; /* Archiver instance that created this */ 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_uint8 *buffer; /* Buffer, if set (NULL otherwise). Don't touch! */
PHYSFS_uint32 bufsize; /* Bufsize, if set (0 otherwise). Don't touch! */ PHYSFS_uint32 bufsize; /* Bufsize, if set (0 otherwise). Don't touch! */
PHYSFS_uint32 buffill; /* Buffer fill size. Don't touch! */ PHYSFS_uint32 buffill; /* Buffer fill size. Don't touch! */
@ -152,6 +151,122 @@ static int externalAllocator = 0;
PHYSFS_Allocator allocator; 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 ... */ /* functions ... */
typedef struct typedef struct
@ -379,28 +494,37 @@ void PHYSFS_getLinkedVersion(PHYSFS_Version *ver)
static const char *find_filename_extension(const char *fname) static const char *find_filename_extension(const char *fname)
{ {
const char *retval = strchr(fname, '.'); const char *retval = NULL;
const char *p = retval; if (fname != NULL)
while (p != NULL)
{ {
p = strchr(p + 1, '.'); retval = strchr(fname, '.');
if (p != NULL) const char *p = retval;
retval = p;
} /* while */
if (retval != NULL) while (p != NULL)
retval++; /* skip '.' */ {
p = strchr(p + 1, '.');
if (p != NULL)
retval = p;
} /* while */
if (retval != NULL)
retval++; /* skip '.' */
} /* if */
return retval; return retval;
} /* find_filename_extension */ } /* 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) const char *d, int forWriting)
{ {
DirHandle *retval = NULL; 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) if (opaque != NULL)
{ {
retval = (DirHandle *) allocator.Malloc(sizeof (DirHandle)); retval = (DirHandle *) allocator.Malloc(sizeof (DirHandle));
@ -419,18 +543,26 @@ static DirHandle *tryOpenDir(const PHYSFS_Archiver *funcs,
} /* tryOpenDir */ } /* tryOpenDir */
static DirHandle *openDirectory(const char *d, int forWriting) static DirHandle *openDirectory(PHYSFS_Io *io, const char *d, int forWriting)
{ {
DirHandle *retval = NULL; DirHandle *retval = NULL;
const PHYSFS_Archiver **i; const PHYSFS_Archiver **i;
const char *ext; 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). */ if (io == NULL)
retval = tryOpenDir(&__PHYSFS_Archiver_DIR, d, forWriting); {
if (retval != NULL) BAIL_IF_MACRO(!__PHYSFS_platformExists(d), ERR_NO_SUCH_FILE, NULL);
return retval;
/* 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); ext = find_filename_extension(d);
if (ext != NULL) if (ext != NULL)
@ -439,21 +571,21 @@ static DirHandle *openDirectory(const char *d, int forWriting)
for (i = archivers; (*i != NULL) && (retval == NULL); i++) for (i = archivers; (*i != NULL) && (retval == NULL); i++)
{ {
if (__PHYSFS_stricmpASCII(ext, (*i)->info->extension) == 0) if (__PHYSFS_stricmpASCII(ext, (*i)->info->extension) == 0)
retval = tryOpenDir(*i, d, forWriting); retval = tryOpenDir(io, *i, d, forWriting);
} /* for */ } /* for */
/* failing an exact file extension match, try all the others... */ /* failing an exact file extension match, try all the others... */
for (i = archivers; (*i != NULL) && (retval == NULL); i++) for (i = archivers; (*i != NULL) && (retval == NULL); i++)
{ {
if (__PHYSFS_stricmpASCII(ext, (*i)->info->extension) != 0) if (__PHYSFS_stricmpASCII(ext, (*i)->info->extension) != 0)
retval = tryOpenDir(*i, d, forWriting); retval = tryOpenDir(io, *i, d, forWriting);
} /* for */ } /* for */
} /* if */ } /* if */
else /* no extension? Try them all. */ else /* no extension? Try them all. */
{ {
for (i = archivers; (*i != NULL) && (retval == NULL); i++) for (i = archivers; (*i != NULL) && (retval == NULL); i++)
retval = tryOpenDir(*i, d, forWriting); retval = tryOpenDir(io, *i, d, forWriting);
} /* else */ } /* else */
BAIL_IF_MACRO(retval == NULL, ERR_UNSUPPORTED_ARCHIVE, NULL); BAIL_IF_MACRO(retval == NULL, ERR_UNSUPPORTED_ARCHIVE, NULL);
@ -545,14 +677,12 @@ static int partOfMountPoint(DirHandle *h, char *fname)
} /* partOfMountPoint */ } /* partOfMountPoint */
static DirHandle *createDirHandle(const char *newDir, static DirHandle *createDirHandle(PHYSFS_Io *io, const char *newDir,
const char *mountPoint, const char *mountPoint, int forWriting)
int forWriting)
{ {
DirHandle *dirHandle = NULL; DirHandle *dirHandle = NULL;
char *tmpmntpnt = NULL; char *tmpmntpnt = NULL;
GOTO_IF_MACRO(!newDir, ERR_INVALID_ARGUMENT, badDirHandle);
if (mountPoint != NULL) if (mountPoint != NULL)
{ {
const size_t len = strlen(mountPoint) + 1; const size_t len = strlen(mountPoint) + 1;
@ -563,12 +693,17 @@ static DirHandle *createDirHandle(const char *newDir,
mountPoint = tmpmntpnt; /* sanitized version. */ mountPoint = tmpmntpnt; /* sanitized version. */
} /* if */ } /* if */
dirHandle = openDirectory(newDir, forWriting); dirHandle = openDirectory(io, newDir, forWriting);
GOTO_IF_MACRO(!dirHandle, NULL, badDirHandle); GOTO_IF_MACRO(!dirHandle, NULL, badDirHandle);
dirHandle->dirName = (char *) allocator.Malloc(strlen(newDir) + 1); if (newDir == NULL)
GOTO_IF_MACRO(!dirHandle->dirName, ERR_OUT_OF_MEMORY, badDirHandle); dirHandle->dirName = NULL;
strcpy(dirHandle->dirName, newDir); 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')) if ((mountPoint != NULL) && (*mountPoint != '\0'))
{ {
@ -791,13 +926,16 @@ static int closeFileHandleList(FileHandle **list)
for (i = *list; i != NULL; i = next) for (i = *list; i != NULL; i = next)
{ {
PHYSFS_Io *io = i->io;
next = i->next; next = i->next;
if (!i->funcs->fileClose(i->opaque))
if (!io->flush(io))
{ {
*list = i; *list = i;
return 0; return 0;
} /* if */ } /* if */
io->destroy(io);
allocator.Free(i); allocator.Free(i);
} /* for */ } /* for */
@ -946,7 +1084,8 @@ int PHYSFS_setWriteDir(const char *newDir)
if (newDir != NULL) if (newDir != NULL)
{ {
writeDir = createDirHandle(newDir, NULL, 1); /* !!! FIXME: PHYSFS_Io shouldn't be NULL */
writeDir = createDirHandle(NULL, newDir, NULL, 1);
retval = (writeDir != NULL); retval = (writeDir != NULL);
} /* if */ } /* if */
@ -976,7 +1115,7 @@ int PHYSFS_mount(const char *newDir, const char *mountPoint, int appendToPath)
prev = i; prev = i;
} /* for */ } /* for */
dh = createDirHandle(newDir, mountPoint, 0); dh = createDirHandle(NULL, newDir, mountPoint, 0);
BAIL_IF_MACRO_MUTEX(dh == NULL, NULL, stateLock, 0); BAIL_IF_MACRO_MUTEX(dh == NULL, NULL, stateLock, 0);
if (appendToPath) if (appendToPath)
@ -1735,7 +1874,7 @@ static PHYSFS_File *doOpenWrite(const char *_fname, int appending)
if (sanitizePlatformIndependentPath(_fname, fname)) if (sanitizePlatformIndependentPath(_fname, fname))
{ {
void *opaque = NULL; PHYSFS_Io *io = NULL;
DirHandle *h = NULL; DirHandle *h = NULL;
const PHYSFS_Archiver *f; const PHYSFS_Archiver *f;
@ -1748,24 +1887,23 @@ static PHYSFS_File *doOpenWrite(const char *_fname, int appending)
f = h->funcs; f = h->funcs;
if (appending) if (appending)
opaque = f->openAppend(h->opaque, fname); io = f->openAppend(h->opaque, fname);
else 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)); fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle));
if (fh == NULL) if (fh == NULL)
{ {
f->fileClose(opaque); io->destroy(io);
GOTO_MACRO(ERR_OUT_OF_MEMORY, doOpenWriteEnd); GOTO_MACRO(ERR_OUT_OF_MEMORY, doOpenWriteEnd);
} /* if */ } /* if */
else else
{ {
memset(fh, '\0', sizeof (FileHandle)); memset(fh, '\0', sizeof (FileHandle));
fh->opaque = opaque; fh->io = io;
fh->dirHandle = h; fh->dirHandle = h;
fh->funcs = h->funcs;
fh->next = openWriteList; fh->next = openWriteList;
openWriteList = fh; openWriteList = fh;
} /* else */ } /* else */
@ -1806,7 +1944,7 @@ PHYSFS_File *PHYSFS_openRead(const char *_fname)
{ {
int fileExists = 0; int fileExists = 0;
DirHandle *i = NULL; DirHandle *i = NULL;
fvoid *opaque = NULL; PHYSFS_Io *io = NULL;
__PHYSFS_platformGrabMutex(stateLock); __PHYSFS_platformGrabMutex(stateLock);
@ -1820,28 +1958,27 @@ PHYSFS_File *PHYSFS_openRead(const char *_fname)
char *arcfname = fname; char *arcfname = fname;
if (verifyPath(i, &arcfname, 0)) if (verifyPath(i, &arcfname, 0))
{ {
opaque = i->funcs->openRead(i->opaque, arcfname, &fileExists); io = i->funcs->openRead(i->opaque, arcfname, &fileExists);
if (opaque) if (io)
break; break;
} /* if */ } /* if */
i = i->next; i = i->next;
} while ((i != NULL) && (!fileExists)); } while ((i != NULL) && (!fileExists));
/* !!! FIXME: may not set an error if openRead didn't fail. */ /* !!! 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)); fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle));
if (fh == NULL) if (fh == NULL)
{ {
i->funcs->fileClose(opaque); io->destroy(io);
GOTO_MACRO(ERR_OUT_OF_MEMORY, openReadEnd); GOTO_MACRO(ERR_OUT_OF_MEMORY, openReadEnd);
} /* if */ } /* if */
memset(fh, '\0', sizeof (FileHandle)); memset(fh, '\0', sizeof (FileHandle));
fh->opaque = opaque; fh->io = io;
fh->forReading = 1; fh->forReading = 1;
fh->dirHandle = i; fh->dirHandle = i;
fh->funcs = i->funcs;
fh->next = openReadList; fh->next = openReadList;
openReadList = fh; openReadList = fh;
@ -1864,12 +2001,12 @@ static int closeHandleInOpenList(FileHandle **list, FileHandle *handle)
{ {
if (i == handle) /* handle is in this list? */ if (i == handle) /* handle is in this list? */
{ {
PHYSFS_Io *io = handle->io;
PHYSFS_uint8 *tmp = handle->buffer; PHYSFS_uint8 *tmp = handle->buffer;
rc = PHYSFS_flush((PHYSFS_File *) handle); rc = PHYSFS_flush((PHYSFS_File *) handle);
if (rc)
rc = handle->funcs->fileClose(handle->opaque);
if (!rc) if (!rc)
return -1; return -1;
io->destroy(io);
if (tmp != NULL) /* free any associated buffer. */ if (tmp != NULL) /* free any associated buffer. */
allocator.Free(tmp); allocator.Free(tmp);
@ -1914,6 +2051,7 @@ int PHYSFS_close(PHYSFS_File *_handle)
static PHYSFS_sint64 doBufferedRead(FileHandle *fh, void *buffer, static PHYSFS_sint64 doBufferedRead(FileHandle *fh, void *buffer,
PHYSFS_uint64 len) PHYSFS_uint64 len)
{ {
PHYSFS_Io *io = NULL;
PHYSFS_sint64 retval = 0; PHYSFS_sint64 retval = 0;
PHYSFS_uint32 buffered = 0; PHYSFS_uint32 buffered = 0;
PHYSFS_sint64 rc = 0; PHYSFS_sint64 rc = 0;
@ -1942,17 +2080,18 @@ static PHYSFS_sint64 doBufferedRead(FileHandle *fh, void *buffer,
assert(buffered == 0); assert(buffered == 0);
assert(len > 0); assert(len > 0);
io = fh->io;
if (len >= fh->bufsize) /* need more than the buffer takes. */ if (len >= fh->bufsize) /* need more than the buffer takes. */
{ {
/* leave buffer empty, go right to output instead. */ /* 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) if (rc < 0)
return ((retval == 0) ? rc : retval); return ((retval == 0) ? rc : retval);
return retval + rc; return retval + rc;
} /* if */ } /* if */
/* need less than buffer can take. Fill buffer. */ /* 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) if (rc < 0)
return ((retval == 0) ? rc : retval); return ((retval == 0) ? rc : retval);
@ -1993,7 +2132,7 @@ PHYSFS_sint64 PHYSFS_readBytes(PHYSFS_File *handle, void *buffer,
if (fh->buffer != NULL) if (fh->buffer != NULL)
return doBufferedRead(fh, buffer, len); return doBufferedRead(fh, buffer, len);
return fh->funcs->read(fh->opaque, buffer, len); return fh->io->read(fh->io, buffer, len);
} /* PHYSFS_readBytes */ } /* 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. */ /* would overflow buffer. Flush and then write the new objects, too. */
BAIL_IF_MACRO(!PHYSFS_flush(handle), NULL, -1); 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 */ } /* doBufferedWrite */
@ -2043,7 +2182,7 @@ PHYSFS_sint64 PHYSFS_writeBytes(PHYSFS_File *handle, const void *buffer,
if (fh->buffer != NULL) if (fh->buffer != NULL)
return doBufferedWrite(handle, buffer, len); return doBufferedWrite(handle, buffer, len);
return fh->funcs->write(fh->opaque, buffer, len); return fh->io->write(fh->io, buffer, len);
} /* PHYSFS_write */ } /* PHYSFS_write */
@ -2054,18 +2193,29 @@ int PHYSFS_eof(PHYSFS_File *handle)
if (!fh->forReading) /* never EOF on files opened for write/append. */ if (!fh->forReading) /* never EOF on files opened for write/append. */
return 0; return 0;
/* eof if buffer is empty and archiver says so. */ /* can't be eof if buffer isn't empty */
return (fh->bufpos == fh->buffill && (fh->funcs->eof(fh->opaque))); 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_eof */
PHYSFS_sint64 PHYSFS_tell(PHYSFS_File *handle) PHYSFS_sint64 PHYSFS_tell(PHYSFS_File *handle)
{ {
FileHandle *fh = (FileHandle *) handle; FileHandle *fh = (FileHandle *) handle;
PHYSFS_sint64 pos = fh->funcs->tell(fh->opaque); const PHYSFS_sint64 pos = fh->io->tell(fh->io);
PHYSFS_sint64 retval = fh->forReading ? const PHYSFS_sint64 retval = fh->forReading ?
(pos - fh->buffill) + fh->bufpos : (pos - fh->buffill) + fh->bufpos :
(pos + fh->buffill); (pos + fh->buffill);
return retval; return retval;
} /* PHYSFS_tell */ } /* PHYSFS_tell */
@ -2090,14 +2240,14 @@ int PHYSFS_seek(PHYSFS_File *handle, PHYSFS_uint64 pos)
/* we have to fall back to a 'raw' seek. */ /* we have to fall back to a 'raw' seek. */
fh->buffill = fh->bufpos = 0; fh->buffill = fh->bufpos = 0;
return fh->funcs->seek(fh->opaque, pos); return fh->io->seek(fh->io, pos);
} /* PHYSFS_seek */ } /* PHYSFS_seek */
PHYSFS_sint64 PHYSFS_fileLength(PHYSFS_File *handle) PHYSFS_sint64 PHYSFS_fileLength(PHYSFS_File *handle)
{ {
FileHandle *fh = (FileHandle *) handle; PHYSFS_Io *io = ((FileHandle *) handle)->io;
return fh->funcs->fileLength(fh->opaque); return io->length(io);
} /* PHYSFS_filelength */ } /* PHYSFS_filelength */
@ -2121,10 +2271,10 @@ int PHYSFS_setBuffer(PHYSFS_File *handle, PHYSFS_uint64 _bufsize)
if ((fh->forReading) && (fh->buffill != fh->bufpos)) if ((fh->forReading) && (fh->buffill != fh->bufpos))
{ {
PHYSFS_uint64 pos; 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); BAIL_IF_MACRO(curpos == -1, NULL, 0);
pos = ((curpos - fh->buffill) + fh->bufpos); 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 */
if (bufsize == 0) /* delete existing buffer. */ 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) int PHYSFS_flush(PHYSFS_File *handle)
{ {
FileHandle *fh = (FileHandle *) handle; FileHandle *fh = (FileHandle *) handle;
PHYSFS_Io *io;
PHYSFS_sint64 rc; PHYSFS_sint64 rc;
if ((fh->forReading) || (fh->bufpos == fh->buffill)) if ((fh->forReading) || (fh->bufpos == fh->buffill))
return 1; /* open for read or buffer empty are successful no-ops. */ return 1; /* open for read or buffer empty are successful no-ops. */
/* dump buffer to disk. */ /* dump buffer to disk. */
rc = fh->funcs->write(fh->opaque, fh->buffer + fh->bufpos, io = fh->io;
fh->buffill - fh->bufpos); rc = io->write(io, fh->buffer + fh->bufpos, fh->buffill - fh->bufpos);
BAIL_IF_MACRO(rc <= 0, NULL, 0); BAIL_IF_MACRO(rc <= 0, NULL, 0);
fh->bufpos = fh->buffill = 0; fh->bufpos = fh->buffill = 0;
return 1; return io->flush(io);
} /* PHYSFS_flush */ } /* 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 * function just wraps it anyhow. This function never clarified
* what would happen if you managed to read a partial object, so * what would happen if you managed to read a partial object, so
* working at the byte level makes this cleaner for everyone, * 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. * application.
* *
* \param handle handle returned from PHYSFS_openRead(). * \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 * function just wraps it anyhow. This function never clarified
* what would happen if you managed to write a partial object, so * what would happen if you managed to write a partial object, so
* working at the byte level makes this cleaner for everyone, * 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. * application.
* *
* \param handle retval from PHYSFS_openWrite() or PHYSFS_openAppend(). * \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) * \fn PHYSFS_sint64 PHYSFS_fileLength(PHYSFS_File *handle)
* \brief Get total length of a file in bytes. * \brief Get total length of a file in bytes.
* *
* Note that if the file size can't be determined (since the archive is * Note that if another process/thread is writing to this file at the same
* "streamed" or whatnot) than this will report (-1). Also note that if * time, then the information this function supplies could be incorrect
* another process/thread is writing to this file at the same time, then * before you get it. Use with caution, or better yet, don't use at all.
* 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*(). * \param handle handle returned from PHYSFS_open*().
* \return size in bytes of the file. -1 if can't be determined. * \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_removeFromSearchPath
* \sa PHYSFS_getSearchPath * \sa PHYSFS_getSearchPath
* \sa PHYSFS_getMountPoint * \sa PHYSFS_getMountPoint
* \sa PHYSFS_mountIo
*/ */
PHYSFS_DECL int PHYSFS_mount(const char *newDir, PHYSFS_DECL int PHYSFS_mount(const char *newDir,
const char *mountPoint, const char *mountPoint,
@ -2719,6 +2718,184 @@ PHYSFS_DECL PHYSFS_sint64 PHYSFS_writeBytes(PHYSFS_File *handle,
PHYSFS_uint64 len); 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. */ /* 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. */ /* end LANG section. */
struct __PHYSFS_DIRHANDLE__;
struct __PHYSFS_FILEFUNCTIONS__;
/* !!! FIXME: find something better than "dvoid" and "fvoid" ... */ /* !!! FIXME: find something better than "dvoid" and "fvoid" ... */
/* Opaque data for file and dir handlers... */ /* Opaque data for file and dir handlers... */
typedef void dvoid; typedef void dvoid;
typedef void fvoid;
typedef struct typedef struct
@ -741,16 +737,18 @@ typedef struct
*/ */
/* /*
* Open a dirhandle for dir/archive (name). * Open a dirhandle for dir/archive data provided by (io).
* This filename is in platform-dependent notation. * (name) is a filename associated with (io), but doesn't necessarily
* forWriting is non-zero if this is to be used for * 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 * the write directory, and zero if this is to be used for an
* element of the search path. * element of the search path.
* Returns NULL on failure, and calls __PHYSFS_setError(). * Returns NULL on failure, and calls __PHYSFS_setError().
* Returns non-NULL on success. The pointer returned will be * Returns non-NULL on success. The pointer returned will be
* passed as the "opaque" parameter for later calls. * 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), * 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!), * non-zero if the file existed (even if it's a broken symlink!),
* zero if it did not. * 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. * Open file for writing.
@ -824,7 +822,7 @@ typedef struct
* Returns non-NULL on success. The pointer returned will be * Returns non-NULL on success. The pointer returned will be
* passed as the "opaque" parameter for later file calls. * 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. * Open file for appending.
@ -837,7 +835,7 @@ typedef struct
* Returns non-NULL on success. The pointer returned will be * Returns non-NULL on success. The pointer returned will be
* passed as the "opaque" parameter for later file calls. * 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. * Delete a file in the archive/directory.
@ -862,9 +860,9 @@ typedef struct
/* /*
* Close directories/archives, and free any associated memory, * Close directories/archives, and free any associated memory,
* including (opaque) itself if applicable. Implementation can assume * including the original PHYSFS_Io and (opaque) itself, if
* that it won't be called if there are still files open from * applicable. Implementation can assume that it won't be called if
* this archive. * there are still files open from this archive.
*/ */
void (*dirClose)(dvoid *opaque); void (*dirClose)(dvoid *opaque);
@ -874,60 +872,6 @@ typedef struct
* On failure, call __PHYSFS_setError(). * On failure, call __PHYSFS_setError().
*/ */
int (*stat)(dvoid *opaque, const char *fn, int *exists, PHYSFS_Stat *stat); 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; } PHYSFS_Archiver;
@ -1082,6 +1026,14 @@ extern PHYSFS_Allocator __PHYSFS_AllocatorHooks;
/* convenience macro to make this less cumbersome internally... */ /* convenience macro to make this less cumbersome internally... */
#define allocator __PHYSFS_AllocatorHooks #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); void *__PHYSFS_platformOpenAppend(const char *filename);
/* /*
* Read more data from a platform-specific file handle. (opaque) should be * 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) * 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); int __PHYSFS_platformFlush(void *opaque);
/* /*
* Flush and close a file. (opaque) should be cast to whatever data type * Close file and deallocate resources. (opaque) should be cast to whatever
* your platform uses. Be sure to check for errors when closing; the * data type your platform uses. This should close the file in any scenario:
* caller expects that this function can fail if there was a flushing * flushing is a separate function call, and this function should never fail.
* error, etc.
* *
* You should clean up all resources associated with (opaque). * You should clean up all resources associated with (opaque); the pointer
* * will be considered invalid after this call.
* Return zero on failure, non-zero on success.
*/ */
int __PHYSFS_platformClose(void *opaque); void __PHYSFS_platformClose(void *opaque);
/* /*
* Platform implementation of PHYSFS_getCdRomDirsCallback()... * Platform implementation of PHYSFS_getCdRomDirsCallback()...
@ -1331,7 +1280,6 @@ int __PHYSFS_platformExists(const char *fname);
*/ */
int __PHYSFS_platformIsSymLink(const char *fname); int __PHYSFS_platformIsSymLink(const char *fname);
/* /*
* Return non-zero if filename (in platform-dependent notation) is a symlink. * Return non-zero if filename (in platform-dependent notation) is a symlink.
* Symlinks should be followed; if what the symlink points to is missing, * 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 */ } /* __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 */ } /* __PHYSFS_platformClose */

View File

@ -506,12 +506,11 @@ int __PHYSFS_platformFlush(void *opaque)
} /* __PHYSFS_platformFlush */ } /* __PHYSFS_platformFlush */
int __PHYSFS_platformClose(void *opaque) void __PHYSFS_platformClose(void *opaque)
{ {
HANDLE Handle = ((winCEfile *) opaque)->handle; HANDLE Handle = ((winCEfile *) opaque)->handle;
BAIL_IF_MACRO(!CloseHandle(Handle), win32strerror(), 0); (void) CloseHandle(Handle); /* ignore errors. You should have flushed! */
allocator.Free(opaque); allocator.Free(opaque);
return 1;
} /* __PHYSFS_platformClose */ } /* __PHYSFS_platformClose */

View File

@ -393,12 +393,11 @@ int __PHYSFS_platformFlush(void *opaque)
} /* __PHYSFS_platformFlush */ } /* __PHYSFS_platformFlush */
int __PHYSFS_platformClose(void *opaque) void __PHYSFS_platformClose(void *opaque)
{ {
int fd = *((int *) opaque); const int fd = *((int *) opaque);
BAIL_IF_MACRO(close(fd) == -1, strerror(errno), 0); (void) close(fd); /* we don't check this. You should have used flush! */
allocator.Free(opaque); allocator.Free(opaque);
return 1;
} /* __PHYSFS_platformClose */ } /* __PHYSFS_platformClose */

View File

@ -1182,12 +1182,11 @@ int __PHYSFS_platformFlush(void *opaque)
} /* __PHYSFS_platformFlush */ } /* __PHYSFS_platformFlush */
int __PHYSFS_platformClose(void *opaque) void __PHYSFS_platformClose(void *opaque)
{ {
HANDLE Handle = ((WinApiFile *) opaque)->handle; HANDLE Handle = ((WinApiFile *) opaque)->handle;
BAIL_IF_MACRO(!CloseHandle(Handle), winApiStrError(), 0); (void) CloseHandle(Handle); /* ignore errors. You should have flushed! */
allocator.Free(opaque); allocator.Free(opaque);
return 1;
} /* __PHYSFS_platformClose */ } /* __PHYSFS_platformClose */