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