From e40d80b00f4b9750603358f86b95da611731d4ac Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 28 Nov 2012 01:36:13 -0500 Subject: [PATCH] Allow application-supplied archivers. This lets an application supply its own archivers, where they will work like any built-in archiver. This allows abstract directory interfaces the same way that PHYSFS_Io allows stream implementations. This is a work in progress still. The API is still changing, and will remain at version 0 until it is finalized (a theoretical future version 1 will be for when the final public interface changes, not when we evolve the initial API design). --- src/archiver_dir.c | 19 ++-- src/archiver_grp.c | 1 + src/archiver_hog.c | 1 + src/archiver_iso9660.c | 23 ++-- src/archiver_lzma.c | 23 ++-- src/archiver_mvl.c | 1 + src/archiver_qpak.c | 1 + src/archiver_slb.c | 1 + src/archiver_unpacked.c | 21 ++-- src/archiver_wad.c | 1 + src/archiver_zip.c | 19 ++-- src/physfs.c | 231 +++++++++++++++++++++++++++++++++----- src/physfs.h | 239 +++++++++++++++++++++++++++++++++++++++- src/physfs_internal.h | 151 ++----------------------- src/platform_posix.c | 4 +- src/platform_windows.c | 10 +- 16 files changed, 520 insertions(+), 226 deletions(-) diff --git a/src/archiver_dir.c b/src/archiver_dir.c index 4e0cfa4d..c19bb7f5 100644 --- a/src/archiver_dir.c +++ b/src/archiver_dir.c @@ -66,7 +66,7 @@ static void *DIR_openArchive(PHYSFS_Io *io, const char *name, int forWriting) } /* DIR_openArchive */ -static void DIR_enumerateFiles(PHYSFS_Dir *opaque, const char *dname, +static void DIR_enumerateFiles(void *opaque, const char *dname, int omitSymLinks, PHYSFS_EnumFilesCallback cb, const char *origdir, void *callbackdata) { @@ -82,7 +82,7 @@ static void DIR_enumerateFiles(PHYSFS_Dir *opaque, const char *dname, } /* DIR_enumerateFiles */ -static PHYSFS_Io *doOpen(PHYSFS_Dir *opaque, const char *name, +static PHYSFS_Io *doOpen(void *opaque, const char *name, const int mode, int *fileExists) { char *f; @@ -114,25 +114,25 @@ static PHYSFS_Io *doOpen(PHYSFS_Dir *opaque, const char *name, } /* doOpen */ -static PHYSFS_Io *DIR_openRead(PHYSFS_Dir *opaque, const char *fnm, int *exist) +static PHYSFS_Io *DIR_openRead(void *opaque, const char *fnm, int *exist) { return doOpen(opaque, fnm, 'r', exist); } /* DIR_openRead */ -static PHYSFS_Io *DIR_openWrite(PHYSFS_Dir *opaque, const char *filename) +static PHYSFS_Io *DIR_openWrite(void *opaque, const char *filename) { return doOpen(opaque, filename, 'w', NULL); } /* DIR_openWrite */ -static PHYSFS_Io *DIR_openAppend(PHYSFS_Dir *opaque, const char *filename) +static PHYSFS_Io *DIR_openAppend(void *opaque, const char *filename) { return doOpen(opaque, filename, 'a', NULL); } /* DIR_openAppend */ -static int DIR_remove(PHYSFS_Dir *opaque, const char *name) +static int DIR_remove(void *opaque, const char *name) { int retval; char *f; @@ -145,7 +145,7 @@ static int DIR_remove(PHYSFS_Dir *opaque, const char *name) } /* DIR_remove */ -static int DIR_mkdir(PHYSFS_Dir *opaque, const char *name) +static int DIR_mkdir(void *opaque, const char *name) { int retval; char *f; @@ -158,13 +158,13 @@ static int DIR_mkdir(PHYSFS_Dir *opaque, const char *name) } /* DIR_mkdir */ -static void DIR_closeArchive(PHYSFS_Dir *opaque) +static void DIR_closeArchive(void *opaque) { allocator.Free(opaque); } /* DIR_closeArchive */ -static int DIR_stat(PHYSFS_Dir *opaque, const char *name, +static int DIR_stat(void *opaque, const char *name, int *exists, PHYSFS_Stat *stat) { int retval = 0; @@ -180,6 +180,7 @@ static int DIR_stat(PHYSFS_Dir *opaque, const char *name, const PHYSFS_Archiver __PHYSFS_Archiver_DIR = { + CURRENT_PHYSFS_ARCHIVER_API_VERSION, { "", "Non-archive, direct filesystem I/O", diff --git a/src/archiver_grp.c b/src/archiver_grp.c index 1f2bc67f..bdfc65b1 100644 --- a/src/archiver_grp.c +++ b/src/archiver_grp.c @@ -87,6 +87,7 @@ static void *GRP_openArchive(PHYSFS_Io *io, const char *name, int forWriting) const PHYSFS_Archiver __PHYSFS_Archiver_GRP = { + CURRENT_PHYSFS_ARCHIVER_API_VERSION, { "GRP", "Build engine Groupfile format", diff --git a/src/archiver_hog.c b/src/archiver_hog.c index 801407c9..db195085 100644 --- a/src/archiver_hog.c +++ b/src/archiver_hog.c @@ -93,6 +93,7 @@ static void *HOG_openArchive(PHYSFS_Io *io, const char *name, int forWriting) const PHYSFS_Archiver __PHYSFS_Archiver_HOG = { + CURRENT_PHYSFS_ARCHIVER_API_VERSION, { "HOG", "Descent I/II HOG file format", diff --git a/src/archiver_iso9660.c b/src/archiver_iso9660.c index 9c832d13..798f10fd 100644 --- a/src/archiver_iso9660.c +++ b/src/archiver_iso9660.c @@ -291,8 +291,8 @@ static int iso_extractfilenameISO(ISO9660FileDescriptor *descriptor, for(;pos < descriptor->filenamelen; pos++) if (descriptor->filename[pos] == ';') lastfound = pos; - BAIL_IF_MACRO(lastfound < 1, PHYSFS_ERR_NO_SUCH_PATH /* !!! FIXME: PHYSFS_ERR_BAD_FILENAME */, -1); - BAIL_IF_MACRO(lastfound == (descriptor->filenamelen -1), PHYSFS_ERR_NO_SUCH_PATH /* !!! PHYSFS_ERR_BAD_FILENAME */, -1); + BAIL_IF_MACRO(lastfound < 1, PHYSFS_ERR_NOT_FOUND /* !!! FIXME: PHYSFS_ERR_BAD_FILENAME */, -1); + BAIL_IF_MACRO(lastfound == (descriptor->filenamelen -1), PHYSFS_ERR_NOT_FOUND /* !!! PHYSFS_ERR_BAD_FILENAME */, -1); strncpy(filename, descriptor->filename, lastfound); if (filename[lastfound - 1] == '.') filename[lastfound - 1] = '\0'; /* consume trailing ., as done in all implementations */ @@ -638,7 +638,7 @@ static void *ISO9660_openArchive(PHYSFS_Io *io, const char *filename, int forWri } /* ISO9660_openArchive */ -static void ISO9660_closeArchive(PHYSFS_Dir *opaque) +static void ISO9660_closeArchive(void *opaque) { ISO9660Handle *handle = (ISO9660Handle*) opaque; handle->io->destroy(handle->io); @@ -766,7 +766,7 @@ static int iso_file_open_foreign(ISO9660Handle *handle, } /* iso_file_open_foreign */ -static PHYSFS_Io *ISO9660_openRead(PHYSFS_Dir *opaque, const char *filename, +static PHYSFS_Io *ISO9660_openRead(void *opaque, const char *filename, int *exists) { PHYSFS_Io *retval = NULL; @@ -785,7 +785,7 @@ static PHYSFS_Io *ISO9660_openRead(PHYSFS_Dir *opaque, const char *filename, /* find file descriptor */ rc = iso_find_dir_entry(handle, filename, &descriptor, exists); GOTO_IF_MACRO(rc, ERRPASS, errorhandling); - GOTO_IF_MACRO(!*exists, PHYSFS_ERR_NO_SUCH_PATH, errorhandling); + GOTO_IF_MACRO(!*exists, PHYSFS_ERR_NOT_FOUND, errorhandling); fhandle->startblock = descriptor.extentpos + descriptor.extattributelen; fhandle->filesize = descriptor.datalen; @@ -816,7 +816,7 @@ static PHYSFS_Io *ISO9660_openRead(PHYSFS_Dir *opaque, const char *filename, * Information gathering functions ******************************************************************************/ -static void ISO9660_enumerateFiles(PHYSFS_Dir *opaque, const char *dname, +static void ISO9660_enumerateFiles(void *opaque, const char *dname, int omitSymLinks, PHYSFS_EnumFilesCallback cb, const char *origdir, void *callbackdata) @@ -873,7 +873,7 @@ static void ISO9660_enumerateFiles(PHYSFS_Dir *opaque, const char *dname, } /* ISO9660_enumerateFiles */ -static int ISO9660_stat(PHYSFS_Dir *opaque, const char *name, int *exists, +static int ISO9660_stat(void *opaque, const char *name, int *exists, PHYSFS_Stat *stat) { ISO9660Handle *handle = (ISO9660Handle*) opaque; @@ -920,25 +920,25 @@ static int ISO9660_stat(PHYSFS_Dir *opaque, const char *name, int *exists, * Not supported functions ******************************************************************************/ -static PHYSFS_Io *ISO9660_openWrite(PHYSFS_Dir *opaque, const char *name) +static PHYSFS_Io *ISO9660_openWrite(void *opaque, const char *name) { BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL); } /* ISO9660_openWrite */ -static PHYSFS_Io *ISO9660_openAppend(PHYSFS_Dir *opaque, const char *name) +static PHYSFS_Io *ISO9660_openAppend(void *opaque, const char *name) { BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL); } /* ISO9660_openAppend */ -static int ISO9660_remove(PHYSFS_Dir *opaque, const char *name) +static int ISO9660_remove(void *opaque, const char *name) { BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0); } /* ISO9660_remove */ -static int ISO9660_mkdir(PHYSFS_Dir *opaque, const char *name) +static int ISO9660_mkdir(void *opaque, const char *name) { BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0); } /* ISO9660_mkdir */ @@ -946,6 +946,7 @@ static int ISO9660_mkdir(PHYSFS_Dir *opaque, const char *name) const PHYSFS_Archiver __PHYSFS_Archiver_ISO9660 = { + CURRENT_PHYSFS_ARCHIVER_API_VERSION, { "ISO", "ISO9660 image file", diff --git a/src/archiver_lzma.c b/src/archiver_lzma.c index 52fa2203..77072589 100644 --- a/src/archiver_lzma.c +++ b/src/archiver_lzma.c @@ -205,7 +205,7 @@ static LZMAfile * lzma_find_file(const LZMAarchive *archive, const char *name) { LZMAfile *file = bsearch(name, archive->files, archive->db.Database.NumFiles, sizeof(*archive->files), lzma_file_cmp_stdlib); /* FIXME: Should become __PHYSFS_search!!! */ - BAIL_IF_MACRO(file == NULL, PHYSFS_ERR_NO_SUCH_PATH, NULL); + BAIL_IF_MACRO(file == NULL, PHYSFS_ERR_NOT_FOUND, NULL); return file; } /* lzma_find_file */ @@ -531,7 +531,7 @@ static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata, } /* doEnumCallback */ -static void LZMA_enumerateFiles(PHYSFS_Dir *opaque, const char *dname, +static void LZMA_enumerateFiles(void *opaque, const char *dname, int omitSymLinks, PHYSFS_EnumFilesCallback cb, const char *origdir, void *callbackdata) { @@ -551,7 +551,7 @@ static void LZMA_enumerateFiles(PHYSFS_Dir *opaque, const char *dname, file = archive->files; } - BAIL_IF_MACRO(file == NULL, PHYSFS_ERR_NO_SUCH_PATH, ); + BAIL_IF_MACRO(file == NULL, PHYSFS_ERR_NOT_FOUND, ); while (file < lastFile) { @@ -575,7 +575,7 @@ static void LZMA_enumerateFiles(PHYSFS_Dir *opaque, const char *dname, } /* LZMA_enumerateFiles */ -static PHYSFS_Io *LZMA_openRead(PHYSFS_Dir *opaque, const char *name, +static PHYSFS_Io *LZMA_openRead(void *opaque, const char *name, int *fileExists) { LZMAarchive *archive = (LZMAarchive *) opaque; @@ -583,7 +583,7 @@ static PHYSFS_Io *LZMA_openRead(PHYSFS_Dir *opaque, const char *name, PHYSFS_Io *io = NULL; *fileExists = (file != NULL); - BAIL_IF_MACRO(file == NULL, PHYSFS_ERR_NO_SUCH_PATH, NULL); + BAIL_IF_MACRO(file == NULL, PHYSFS_ERR_NOT_FOUND, NULL); BAIL_IF_MACRO(file->folder == NULL, PHYSFS_ERR_NOT_A_FILE, NULL); file->position = 0; @@ -598,19 +598,19 @@ static PHYSFS_Io *LZMA_openRead(PHYSFS_Dir *opaque, const char *name, } /* LZMA_openRead */ -static PHYSFS_Io *LZMA_openWrite(PHYSFS_Dir *opaque, const char *filename) +static PHYSFS_Io *LZMA_openWrite(void *opaque, const char *filename) { BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL); } /* LZMA_openWrite */ -static PHYSFS_Io *LZMA_openAppend(PHYSFS_Dir *opaque, const char *filename) +static PHYSFS_Io *LZMA_openAppend(void *opaque, const char *filename) { BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL); } /* LZMA_openAppend */ -static void LZMA_closeArchive(PHYSFS_Dir *opaque) +static void LZMA_closeArchive(void *opaque) { LZMAarchive *archive = (LZMAarchive *) opaque; @@ -628,18 +628,18 @@ static void LZMA_closeArchive(PHYSFS_Dir *opaque) } /* LZMA_closeArchive */ -static int LZMA_remove(PHYSFS_Dir *opaque, const char *name) +static int LZMA_remove(void *opaque, const char *name) { BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0); } /* LZMA_remove */ -static int LZMA_mkdir(PHYSFS_Dir *opaque, const char *name) +static int LZMA_mkdir(void *opaque, const char *name) { BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0); } /* LZMA_mkdir */ -static int LZMA_stat(PHYSFS_Dir *opaque, const char *filename, +static int LZMA_stat(void *opaque, const char *filename, int *exists, PHYSFS_Stat *stat) { const LZMAarchive *archive = (const LZMAarchive *) opaque; @@ -678,6 +678,7 @@ static int LZMA_stat(PHYSFS_Dir *opaque, const char *filename, const PHYSFS_Archiver __PHYSFS_Archiver_LZMA = { + CURRENT_PHYSFS_ARCHIVER_API_VERSION, { "7Z", "LZMA (7zip) format", diff --git a/src/archiver_mvl.c b/src/archiver_mvl.c index 2e8439cc..0843e5d7 100644 --- a/src/archiver_mvl.c +++ b/src/archiver_mvl.c @@ -80,6 +80,7 @@ static void *MVL_openArchive(PHYSFS_Io *io, const char *name, int forWriting) const PHYSFS_Archiver __PHYSFS_Archiver_MVL = { + CURRENT_PHYSFS_ARCHIVER_API_VERSION, { "MVL", "Descent II Movielib format", diff --git a/src/archiver_qpak.c b/src/archiver_qpak.c index 304f9532..af0323dd 100644 --- a/src/archiver_qpak.c +++ b/src/archiver_qpak.c @@ -96,6 +96,7 @@ static void *QPAK_openArchive(PHYSFS_Io *io, const char *name, int forWriting) const PHYSFS_Archiver __PHYSFS_Archiver_QPAK = { + CURRENT_PHYSFS_ARCHIVER_API_VERSION, { "PAK", "Quake I/II format", diff --git a/src/archiver_slb.c b/src/archiver_slb.c index 0a88a714..ece8ae7f 100644 --- a/src/archiver_slb.c +++ b/src/archiver_slb.c @@ -101,6 +101,7 @@ static void *SLB_openArchive(PHYSFS_Io *io, const char *name, int forWriting) const PHYSFS_Archiver __PHYSFS_Archiver_SLB = { + CURRENT_PHYSFS_ARCHIVER_API_VERSION, { "SLB", "I-War / Independence War Slab file", diff --git a/src/archiver_unpacked.c b/src/archiver_unpacked.c index 496766e2..d751351f 100644 --- a/src/archiver_unpacked.c +++ b/src/archiver_unpacked.c @@ -34,7 +34,7 @@ typedef struct } UNPKfileinfo; -void UNPK_closeArchive(PHYSFS_Dir *opaque) +void UNPK_closeArchive(void *opaque) { UNPKinfo *info = ((UNPKinfo *) opaque); info->io->destroy(info->io); @@ -242,7 +242,7 @@ static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata, } /* doEnumCallback */ -void UNPK_enumerateFiles(PHYSFS_Dir *opaque, const char *dname, +void UNPK_enumerateFiles(void *opaque, const char *dname, int omitSymLinks, PHYSFS_EnumFilesCallback cb, const char *origdir, void *callbackdata) { @@ -340,11 +340,11 @@ static UNPKentry *findEntry(const UNPKinfo *info, const char *path, int *isDir) if (isDir != NULL) *isDir = 0; - BAIL_MACRO(PHYSFS_ERR_NO_SUCH_PATH, NULL); + BAIL_MACRO(PHYSFS_ERR_NOT_FOUND, NULL); } /* findEntry */ -PHYSFS_Io *UNPK_openRead(PHYSFS_Dir *opaque, const char *fnm, int *fileExists) +PHYSFS_Io *UNPK_openRead(void *opaque, const char *fnm, int *fileExists) { PHYSFS_Io *retval = NULL; UNPKinfo *info = (UNPKinfo *) opaque; @@ -390,31 +390,31 @@ PHYSFS_Io *UNPK_openRead(PHYSFS_Dir *opaque, const char *fnm, int *fileExists) } /* UNPK_openRead */ -PHYSFS_Io *UNPK_openWrite(PHYSFS_Dir *opaque, const char *name) +PHYSFS_Io *UNPK_openWrite(void *opaque, const char *name) { BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL); } /* UNPK_openWrite */ -PHYSFS_Io *UNPK_openAppend(PHYSFS_Dir *opaque, const char *name) +PHYSFS_Io *UNPK_openAppend(void *opaque, const char *name) { BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL); } /* UNPK_openAppend */ -int UNPK_remove(PHYSFS_Dir *opaque, const char *name) +int UNPK_remove(void *opaque, const char *name) { BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0); } /* UNPK_remove */ -int UNPK_mkdir(PHYSFS_Dir *opaque, const char *name) +int UNPK_mkdir(void *opaque, const char *name) { BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0); } /* UNPK_mkdir */ -int UNPK_stat(PHYSFS_Dir *opaque, const char *filename, +int UNPK_stat(void *opaque, const char *filename, int *exists, PHYSFS_Stat *stat) { int isDir = 0; @@ -448,8 +448,7 @@ int UNPK_stat(PHYSFS_Dir *opaque, const char *filename, } /* UNPK_stat */ -PHYSFS_Dir *UNPK_openArchive(PHYSFS_Io *io, UNPKentry *e, - const PHYSFS_uint32 num) +void *UNPK_openArchive(PHYSFS_Io *io, UNPKentry *e, const PHYSFS_uint32 num) { UNPKinfo *info = (UNPKinfo *) allocator.Malloc(sizeof (UNPKinfo)); if (info == NULL) diff --git a/src/archiver_wad.c b/src/archiver_wad.c index c4681905..535c00b9 100644 --- a/src/archiver_wad.c +++ b/src/archiver_wad.c @@ -104,6 +104,7 @@ static void *WAD_openArchive(PHYSFS_Io *io, const char *name, int forWriting) const PHYSFS_Archiver __PHYSFS_Archiver_WAD = { + CURRENT_PHYSFS_ARCHIVER_API_VERSION, { "WAD", "DOOM engine format", diff --git a/src/archiver_zip.c b/src/archiver_zip.c index 8e3bd558..848aa77c 100644 --- a/src/archiver_zip.c +++ b/src/archiver_zip.c @@ -600,7 +600,7 @@ static ZIPentry *zip_find_entry(const ZIPinfo *info, const char *path, if (isDir != NULL) *isDir = 0; - BAIL_MACRO(PHYSFS_ERR_NO_SUCH_PATH, NULL); + BAIL_MACRO(PHYSFS_ERR_NOT_FOUND, NULL); } /* zip_find_entry */ @@ -1487,7 +1487,7 @@ static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata, } /* doEnumCallback */ -static void ZIP_enumerateFiles(PHYSFS_Dir *opaque, const char *dname, +static void ZIP_enumerateFiles(void *opaque, const char *dname, int omitSymLinks, PHYSFS_EnumFilesCallback cb, const char *origdir, void *callbackdata) { @@ -1560,7 +1560,7 @@ static PHYSFS_Io *zip_get_io(PHYSFS_Io *io, ZIPinfo *inf, ZIPentry *entry) } /* zip_get_io */ -static PHYSFS_Io *ZIP_openRead(PHYSFS_Dir *opaque, const char *fnm, +static PHYSFS_Io *ZIP_openRead(void *opaque, const char *fnm, int *fileExists) { PHYSFS_Io *retval = NULL; @@ -1619,19 +1619,19 @@ static PHYSFS_Io *ZIP_openRead(PHYSFS_Dir *opaque, const char *fnm, } /* ZIP_openRead */ -static PHYSFS_Io *ZIP_openWrite(PHYSFS_Dir *opaque, const char *filename) +static PHYSFS_Io *ZIP_openWrite(void *opaque, const char *filename) { BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL); } /* ZIP_openWrite */ -static PHYSFS_Io *ZIP_openAppend(PHYSFS_Dir *opaque, const char *filename) +static PHYSFS_Io *ZIP_openAppend(void *opaque, const char *filename) { BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL); } /* ZIP_openAppend */ -static void ZIP_closeArchive(PHYSFS_Dir *opaque) +static void ZIP_closeArchive(void *opaque) { ZIPinfo *zi = (ZIPinfo *) (opaque); zi->io->destroy(zi->io); @@ -1640,19 +1640,19 @@ static void ZIP_closeArchive(PHYSFS_Dir *opaque) } /* ZIP_closeArchive */ -static int ZIP_remove(PHYSFS_Dir *opaque, const char *name) +static int ZIP_remove(void *opaque, const char *name) { BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0); } /* ZIP_remove */ -static int ZIP_mkdir(PHYSFS_Dir *opaque, const char *name) +static int ZIP_mkdir(void *opaque, const char *name) { BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0); } /* ZIP_mkdir */ -static int ZIP_stat(PHYSFS_Dir *opaque, const char *filename, int *exists, +static int ZIP_stat(void *opaque, const char *filename, int *exists, PHYSFS_Stat *stat) { int isDir = 0; @@ -1694,6 +1694,7 @@ static int ZIP_stat(PHYSFS_Dir *opaque, const char *filename, int *exists, const PHYSFS_Archiver __PHYSFS_Archiver_ZIP = { + CURRENT_PHYSFS_ARCHIVER_API_VERSION, { "ZIP", "PkZip/WinZip/Info-Zip compatible", diff --git a/src/physfs.c b/src/physfs.c index ef8ede6f..e1b92ba6 100644 --- a/src/physfs.c +++ b/src/physfs.c @@ -58,7 +58,7 @@ extern const PHYSFS_Archiver __PHYSFS_Archiver_SLB; extern const PHYSFS_Archiver __PHYSFS_Archiver_DIR; extern const PHYSFS_Archiver __PHYSFS_Archiver_ISO9660; -static const PHYSFS_Archiver *staticArchivers[] = +static const PHYSFS_Archiver * const staticArchivers[] = { #if PHYSFS_SUPPORTS_ZIP &__PHYSFS_Archiver_ZIP, @@ -105,6 +105,7 @@ static char *prefDir = NULL; static int allowSymLinks = 0; static const PHYSFS_Archiver **archivers = NULL; static const PHYSFS_ArchiveInfo **archiveInfo = NULL; +static volatile size_t numArchivers = 0; /* mutexes ... */ static void *errorLock = NULL; /* protects error message list. */ @@ -752,7 +753,7 @@ PHYSFS_DECL const char *PHYSFS_getErrorByCode(PHYSFS_ErrorCode code) case PHYSFS_ERR_FILES_STILL_OPEN: return "files still open"; case PHYSFS_ERR_INVALID_ARGUMENT: return "invalid argument"; case PHYSFS_ERR_NOT_MOUNTED: return "not mounted"; - case PHYSFS_ERR_NO_SUCH_PATH: return "no such path"; + case PHYSFS_ERR_NOT_FOUND: return "not found"; case PHYSFS_ERR_SYMLINK_FORBIDDEN: return "symlinks are forbidden"; case PHYSFS_ERR_NO_WRITE_DIR: return "write directory is not set"; case PHYSFS_ERR_OPEN_FOR_READING: return "file open for reading"; @@ -768,6 +769,7 @@ PHYSFS_DECL const char *PHYSFS_getErrorByCode(PHYSFS_ErrorCode code) case PHYSFS_ERR_BUSY: return "tried to modify a file the OS needs"; case PHYSFS_ERR_DIR_NOT_EMPTY: return "directory isn't empty"; case PHYSFS_ERR_OS_ERROR: return "OS reported an error"; + case PHYSFS_ERR_DUPLICATE: return "duplicate resource"; } /* switch */ return NULL; /* don't know this error code. */ @@ -890,14 +892,14 @@ static DirHandle *openDirectory(PHYSFS_Io *io, const char *d, int forWriting) /* Look for archivers with matching file extensions first... */ for (i = archivers; (*i != NULL) && (retval == NULL); i++) { - if (__PHYSFS_stricmpASCII(ext, (*i)->info.extension) == 0) + if (__PHYSFS_utf8stricmp(ext, (*i)->info.extension) == 0) 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) + if (__PHYSFS_utf8stricmp(ext, (*i)->info.extension) != 0) retval = tryOpenDir(io, *i, d, forWriting); } /* for */ } /* if */ @@ -1125,32 +1127,26 @@ static int initializeMutexes(void) } /* initializeMutexes */ -static void setDefaultAllocator(void); +static int doRegisterArchiver(const PHYSFS_Archiver *_archiver); static int initStaticArchivers(void) { - const size_t numStaticArchivers = __PHYSFS_ARRAYLEN(staticArchivers); - const size_t len = numStaticArchivers * sizeof (void *); - size_t i; - - assert(numStaticArchivers > 0); /* seriously, none at all?! */ - assert(staticArchivers[numStaticArchivers - 1] == NULL); + const PHYSFS_Archiver * const *i; - archiveInfo = (const PHYSFS_ArchiveInfo **) allocator.Malloc(len); - BAIL_IF_MACRO(!archiveInfo, PHYSFS_ERR_OUT_OF_MEMORY, 0); - archivers = (const PHYSFS_Archiver **) allocator.Malloc(len); - BAIL_IF_MACRO(!archivers, PHYSFS_ERR_OUT_OF_MEMORY, 0); + assert(__PHYSFS_ARRAYLEN(staticArchivers) > 0); /* at least a NULL. */ + assert(staticArchivers[__PHYSFS_ARRAYLEN(staticArchivers) - 1] == NULL); - for (i = 0; i < numStaticArchivers - 1; i++) - archiveInfo[i] = &staticArchivers[i]->info; - archiveInfo[numStaticArchivers - 1] = NULL; - - memcpy(archivers, staticArchivers, len); + for (i = staticArchivers; *i != NULL; i++) + { + if (!doRegisterArchiver(*i)) + return 0; + } /* for */ return 1; } /* initStaticArchivers */ +static void setDefaultAllocator(void); static int doDeinit(void); int PHYSFS_init(const char *argv0) @@ -1243,6 +1239,63 @@ static void freeSearchPath(void) } /* freeSearchPath */ +/* MAKE SURE you hold stateLock before calling this! */ +static int archiverInUse(const PHYSFS_Archiver *arc, const DirHandle *list) +{ + const DirHandle *i; + for (i = list; i != NULL; i = i->next) + { + if (i->funcs == arc) + return 1; + } /* for */ + + return 0; /* not in use */ +} /* archiverInUse */ + + +/* MAKE SURE you hold stateLock before calling this! */ +static int doDeregisterArchiver(const size_t idx) +{ + const size_t len = (numArchivers - idx) * sizeof (void *); + const PHYSFS_ArchiveInfo *info = archiveInfo[idx]; + const PHYSFS_Archiver *arc = archivers[idx]; + + /* make sure nothing is still using this archiver */ + if (archiverInUse(arc, searchPath) || archiverInUse(arc, writeDir)) + BAIL_MACRO(PHYSFS_ERR_FILES_STILL_OPEN, 0); + + allocator.Free((void *) info->extension); + allocator.Free((void *) info->description); + allocator.Free((void *) info->author); + allocator.Free((void *) info->url); + allocator.Free((void *) arc); + + memmove(&archiveInfo[idx], &archiveInfo[idx+1], len); + memmove(&archivers[idx], &archivers[idx+1], len); + + assert(numArchivers > 0); + numArchivers--; + + return 1; +} /* doDeregisterArchiver */ + + +/* Does NOT hold the state lock; we're shutting down. */ +static void freeArchivers(void) +{ + while (numArchivers > 0) + { + const int rc = doDeregisterArchiver(numArchivers - 1); + assert(rc); /* nothing should be mounted during shutdown. */ + } /* while */ + + allocator.Free(archivers); + allocator.Free(archiveInfo); + archivers = NULL; + archiveInfo = NULL; +} /* freeArchivers */ + + static int doDeinit(void) { BAIL_IF_MACRO(!__PHYSFS_platformDeinit(), ERRPASS, 0); @@ -1251,6 +1304,7 @@ static int doDeinit(void) BAIL_IF_MACRO(!PHYSFS_setWriteDir(NULL), PHYSFS_ERR_FILES_STILL_OPEN, 0); freeSearchPath(); + freeArchivers(); freeErrorStates(); if (baseDir != NULL) @@ -1310,6 +1364,133 @@ int PHYSFS_isInit(void) } /* PHYSFS_isInit */ +static char *PHYSFS_strdup(const char *str) +{ + char *retval = (char *) allocator.Malloc(strlen(str) + 1); + if (retval) + strcpy(retval, str); + return retval; +} /* PHYSFS_strdup */ + + +/* MAKE SURE you hold stateLock before calling this! */ +static int doRegisterArchiver(const PHYSFS_Archiver *_archiver) +{ + const PHYSFS_uint32 maxver = CURRENT_PHYSFS_ARCHIVER_API_VERSION; + const size_t len = (numArchivers + 2) * sizeof (void *); + PHYSFS_Archiver *archiver = NULL; + PHYSFS_ArchiveInfo *info = NULL; + const char *ext = NULL; + void *ptr = NULL; + size_t i; + + BAIL_IF_MACRO(!_archiver, PHYSFS_ERR_INVALID_ARGUMENT, 0); + BAIL_IF_MACRO(_archiver->version > maxver, PHYSFS_ERR_UNSUPPORTED, 0); + BAIL_IF_MACRO(!_archiver->info.extension, PHYSFS_ERR_INVALID_ARGUMENT, 0); + BAIL_IF_MACRO(!_archiver->info.description, PHYSFS_ERR_INVALID_ARGUMENT, 0); + BAIL_IF_MACRO(!_archiver->info.author, PHYSFS_ERR_INVALID_ARGUMENT, 0); + BAIL_IF_MACRO(!_archiver->info.url, PHYSFS_ERR_INVALID_ARGUMENT, 0); + BAIL_IF_MACRO(!_archiver->openArchive, PHYSFS_ERR_INVALID_ARGUMENT, 0); + BAIL_IF_MACRO(!_archiver->enumerateFiles, PHYSFS_ERR_INVALID_ARGUMENT, 0); + BAIL_IF_MACRO(!_archiver->openRead, PHYSFS_ERR_INVALID_ARGUMENT, 0); + BAIL_IF_MACRO(!_archiver->openWrite, PHYSFS_ERR_INVALID_ARGUMENT, 0); + BAIL_IF_MACRO(!_archiver->openAppend, PHYSFS_ERR_INVALID_ARGUMENT, 0); + BAIL_IF_MACRO(!_archiver->remove, PHYSFS_ERR_INVALID_ARGUMENT, 0); + BAIL_IF_MACRO(!_archiver->mkdir, PHYSFS_ERR_INVALID_ARGUMENT, 0); + BAIL_IF_MACRO(!_archiver->closeArchive, PHYSFS_ERR_INVALID_ARGUMENT, 0); + BAIL_IF_MACRO(!_archiver->stat, PHYSFS_ERR_INVALID_ARGUMENT, 0); + + ext = _archiver->info.extension; + for (i = 0; i < numArchivers; i++) + { + if (__PHYSFS_utf8stricmp(archiveInfo[i]->extension, ext) == 0) + BAIL_MACRO(PHYSFS_ERR_DUPLICATE, 0); // !!! FIXME: better error? ERR_IN_USE? + } /* for */ + + /* make a copy of the data. */ + archiver = (PHYSFS_Archiver *) allocator.Malloc(sizeof (*archiver)); + GOTO_IF_MACRO(!archiver, PHYSFS_ERR_OUT_OF_MEMORY, regfailed); + + /* Must copy sizeof (OLD_VERSION_OF_STRUCT) when version changes! */ + memcpy(archiver, _archiver, sizeof (*archiver)); + + info = (PHYSFS_ArchiveInfo *) &archiver->info; + memset(info, '\0', sizeof (*info)); /* NULL in case an alloc fails. */ + #define CPYSTR(item) \ + info->item = PHYSFS_strdup(_archiver->info.item); \ + GOTO_IF_MACRO(!info->item, PHYSFS_ERR_OUT_OF_MEMORY, regfailed); + CPYSTR(extension); + CPYSTR(description); + CPYSTR(author); + CPYSTR(url); + #undef CPYSTR + + ptr = allocator.Realloc(archiveInfo, len); + GOTO_IF_MACRO(!ptr, PHYSFS_ERR_OUT_OF_MEMORY, regfailed); + archiveInfo = (const PHYSFS_ArchiveInfo **) ptr; + + ptr = allocator.Realloc(archivers, len); + GOTO_IF_MACRO(!ptr, PHYSFS_ERR_OUT_OF_MEMORY, regfailed); + archivers = (const PHYSFS_Archiver **) ptr; + + archiveInfo[numArchivers] = info; + archiveInfo[numArchivers + 1] = NULL; + + archivers[numArchivers] = archiver; + archivers[numArchivers + 1] = NULL; + + numArchivers++; + + return 1; + +regfailed: + if (info != NULL) + { + allocator.Free((void *) info->extension); + allocator.Free((void *) info->description); + allocator.Free((void *) info->author); + allocator.Free((void *) info->url); + } /* if */ + allocator.Free(archiver); + + return 0; +} /* doRegisterArchiver */ + + +int PHYSFS_registerArchiver(const PHYSFS_Archiver *archiver) +{ + int retval; + BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, 0); + __PHYSFS_platformGrabMutex(stateLock); + retval = doRegisterArchiver(archiver); + __PHYSFS_platformReleaseMutex(stateLock); + return retval; +} /* PHYSFS_registerArchiver */ + + +int PHYSFS_deregisterArchiver(const char *ext) +{ + size_t i; + + BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, 0); + BAIL_IF_MACRO(!ext, PHYSFS_ERR_INVALID_ARGUMENT, 0); + + __PHYSFS_platformGrabMutex(stateLock); + for (i = 0; i < numArchivers; i++) + { + if (__PHYSFS_utf8stricmp(archiveInfo[i]->extension, ext) == 0) + { + const int retval = doDeregisterArchiver(i); + __PHYSFS_platformReleaseMutex(stateLock); + return retval; + } /* if */ + } /* for */ + __PHYSFS_platformReleaseMutex(stateLock); + + BAIL_MACRO(PHYSFS_ERR_NOT_FOUND, 0); +} /* PHYSFS_deregisterArchiver */ + + const PHYSFS_ArchiveInfo **PHYSFS_supportedArchiveTypes(void) { BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, NULL); @@ -1702,7 +1883,7 @@ int PHYSFS_setSaneConfig(const char *organization, const char *appName, if ((l > extlen) && ((*i)[l - extlen - 1] == '.')) { ext = (*i) + (l - extlen); - if (__PHYSFS_stricmpASCII(ext, archiveExt) == 0) + if (__PHYSFS_utf8stricmp(ext, archiveExt) == 0) setSaneCfgAddPath(*i, l, dirsep, archivesFirst); } /* if */ } /* for */ @@ -1763,12 +1944,12 @@ static int verifyPath(DirHandle *h, char **_fname, int allowMissing) size_t len = strlen(fname); assert(mntpntlen > 1); /* root mount points should be NULL. */ /* not under the mountpoint, so skip this archive. */ - BAIL_IF_MACRO(len < mntpntlen-1, PHYSFS_ERR_NO_SUCH_PATH, 0); + BAIL_IF_MACRO(len < mntpntlen-1, PHYSFS_ERR_NOT_FOUND, 0); /* !!! FIXME: Case insensitive? */ retval = strncmp(h->mountPoint, fname, mntpntlen-1); - BAIL_IF_MACRO(retval != 0, PHYSFS_ERR_NO_SUCH_PATH, 0); + BAIL_IF_MACRO(retval != 0, PHYSFS_ERR_NOT_FOUND, 0); if (len > mntpntlen-1) /* corner case... */ - BAIL_IF_MACRO(fname[mntpntlen-1]!='/', PHYSFS_ERR_NO_SUCH_PATH, 0); + BAIL_IF_MACRO(fname[mntpntlen-1]!='/', PHYSFS_ERR_NOT_FOUND, 0); fname += mntpntlen-1; /* move to start of actual archive path. */ if (*fname == '/') fname++; @@ -2222,7 +2403,7 @@ PHYSFS_File *PHYSFS_openRead(const char *_fname) __PHYSFS_platformGrabMutex(stateLock); - GOTO_IF_MACRO(!searchPath, PHYSFS_ERR_NO_SUCH_PATH, openReadEnd); + GOTO_IF_MACRO(!searchPath, PHYSFS_ERR_NOT_FOUND, openReadEnd); for (i = searchPath; (i != NULL) && (!fileExists); i = i->next) { diff --git a/src/physfs.h b/src/physfs.h index 2a2dc41c..69c399ba 100644 --- a/src/physfs.h +++ b/src/physfs.h @@ -399,6 +399,8 @@ typedef struct PHYSFS_File * supported. * * \sa PHYSFS_supportedArchiveTypes + * \sa PHYSFS_registerArchiver + * \sa PHYSFS_deregisterArchiver */ typedef struct PHYSFS_ArchiveInfo { @@ -573,9 +575,13 @@ PHYSFS_DECL int PHYSFS_deinit(void); * * The return values are pointers to internal memory, and should * be considered READ ONLY, and never freed. The returned values are - * valid until the next call to PHYSFS_deinit(). + * valid until the next call to PHYSFS_deinit(), PHYSFS_registerArchiver(), + * or PHYSFS_deregisterArchiver(). * * \return READ ONLY Null-terminated array of READ ONLY structures. + * + * \sa PHYSFS_registerArchiver + * \sa PHYSFS_deregisterArchiver */ PHYSFS_DECL const PHYSFS_ArchiveInfo **PHYSFS_supportedArchiveTypes(void); @@ -3129,7 +3135,7 @@ typedef enum PHYSFS_ErrorCode PHYSFS_ERR_FILES_STILL_OPEN, /**< Files still open. */ PHYSFS_ERR_INVALID_ARGUMENT, /**< Bad parameter passed to an function. */ PHYSFS_ERR_NOT_MOUNTED, /**< Requested archive/dir not mounted. */ - PHYSFS_ERR_NO_SUCH_PATH, /**< No such file, directory, or parent. */ + PHYSFS_ERR_NOT_FOUND, /**< File (or whatever) not found. */ PHYSFS_ERR_SYMLINK_FORBIDDEN,/**< Symlink seen when not permitted. */ PHYSFS_ERR_NO_WRITE_DIR, /**< No write dir has been specified. */ PHYSFS_ERR_OPEN_FOR_READING, /**< Wrote to a file opened for reading. */ @@ -3144,7 +3150,8 @@ typedef enum PHYSFS_ErrorCode PHYSFS_ERR_BAD_FILENAME, /**< Filename is bogus/insecure. */ PHYSFS_ERR_BUSY, /**< Tried to modify a file the OS needs. */ PHYSFS_ERR_DIR_NOT_EMPTY, /**< Tried to delete dir with files in it. */ - PHYSFS_ERR_OS_ERROR /**< Unspecified OS-level error. */ + PHYSFS_ERR_OS_ERROR, /**< Unspecified OS-level error. */ + PHYSFS_ERR_DUPLICATE /**< Duplicate entry. */ } PHYSFS_ErrorCode; @@ -3307,8 +3314,232 @@ PHYSFS_DECL void PHYSFS_setErrorCode(PHYSFS_ErrorCode code); PHYSFS_DECL const char *PHYSFS_getPrefDir(const char *org, const char *app); -/* Everything above this line is part of the PhysicsFS 2.1 API. */ +/** + * \struct PHYSFS_Archiver + * \brief Abstract interface to provide support for user-defined archives. + * + * \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 a means to mount various archive file + * formats, and physical directories in the native filesystem. However, + * applications have been limited to the file formats provided by the + * library. This interface allows an application to provide their own + * archive file types. + * + * Conceptually, a PHYSFS_Archiver provides directory entries, while + * PHYSFS_Io provides data streams for those directory entries. The most + * obvious use of PHYSFS_Archiver is to provide support for an archive + * file type that isn't provided by PhysicsFS directly: perhaps some + * proprietary format that only your application needs to understand. + * + * Internally, all the built-in archive support uses this interface, so the + * best examples for building a PHYSFS_Archiver is the source code to + * PhysicsFS itself. + * + * An archiver is added to the system with PHYSFS_registerArchiver(), and then + * it will be available for use automatically with PHYSFS_mount(); if a + * given archive can be handled with your archiver, it will be given control + * as appropriate. + * + * These methods deal with dir handles. You have one instance of your + * archiver, and it generates a unique, opaque handle for each opened + * archive in its openArchive() method. Since the lifetime of an Archiver + * (not an archive) is generally the entire lifetime of the process, and it's + * assumed to be a singleton, we do not provide any instance data for the + * archiver itself; the app can just use some static variables if necessary. + * + * Symlinks should always be followed (except in stat()); PhysicsFS will + * use the stat() method to check for symlinks and make a judgement on + * whether to continue to call other methods based on that. + * + * Archivers, when necessary, should set the PhysicsFS error state with + * PHYSFS_setErrorCode() before returning. PhysicsFS will pass these errors + * back to the application unmolested in most cases. + * + * Thread safety: TO BE DECIDED. !!! FIXME + * + * \sa PHYSFS_registerArchiver + * \sa PHYSFS_deregisterArchiver + * \sa PHYSFS_supportedArchiveTypes + */ +typedef struct PHYSFS_Archiver +{ + +// !!! FIXME: split read/write interfaces? + + /** + * \brief Binary compatibility information. + * + * This must be set to zero at this time. Future versions of this + * struct will increment this field, so we know what a given + * implementation supports. We'll presumably keep supporting older + * versions as we offer new features, though. + */ + PHYSFS_uint32 version; + /** + * \brief Basic info about this archiver. + * + * This is used to identify your archive, and is returned in + * PHYSFS_supportedArchiveTypes(). + */ + const PHYSFS_ArchiveInfo info; + + /** + * \brief + * + * Open an archive 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. + * (forWrite) 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. + * Return NULL on failure. We ignore any error code you set here; + * when PHYSFS_mount() returns, the error will be PHYSFS_ERR_UNSUPPORTED + * (no Archivers could handle this data). // !!! FIXME: yeah? + * Returns non-NULL on success. The pointer returned will be + * passed as the "opaque" parameter for later calls. + */ + void *(*openArchive)(PHYSFS_Io *io, const char *name, int forWrite); + + /** + * List all files in (dirname). Each file is passed to (cb), + * where a copy is made if appropriate, so you should dispose of + * it properly upon return from the callback. + * You should omit symlinks if (omitSymLinks) is non-zero. + * If you have a failure, report as much as you can. + * (dirname) is in platform-independent notation. + */ + +// !!! FIXME: get rid of this omitsymlinks nonsense. + void (*enumerateFiles)(void *opaque, const char *dirname, + int omitSymLinks, PHYSFS_EnumFilesCallback cb, + const char *origdir, void *callbackdata); + + /** + * Open file for reading. + * This filename, (fnm), is in platform-independent notation. + * If you can't handle multiple opens of the same file, + * you can opt to fail for the second call. + * Fail if the file does not exist. + * Returns NULL on failure, and calls PHYSFS_setErrorCode(). + * Returns non-NULL on success. The pointer returned will be + * passed as the "opaque" parameter for later file calls. + * + * Regardless of success or failure, please set *exists to + * non-zero if the file existed (even if it's a broken symlink!), + * zero if it did not. + */ +// !!! FIXME: get rid of the exists nonsense, check error code instead. + PHYSFS_Io *(*openRead)(void *opaque, const char *fnm, int *exists); + + /** + * Open file for writing. + * If the file does not exist, it should be created. If it exists, + * it should be truncated to zero bytes. The writing + * offset should be the start of the file. + * This filename is in platform-independent notation. + * If you can't handle multiple opens of the same file, + * you can opt to fail for the second call. + * Returns NULL on failure, and calls PHYSFS_setErrorCode(). + * Returns non-NULL on success. The pointer returned will be + * passed as the "opaque" parameter for later file calls. + */ + PHYSFS_Io *(*openWrite)(void *opaque, const char *filename); + + /** + * Open file for appending. + * If the file does not exist, it should be created. The writing + * offset should be the end of the file. + * This filename is in platform-independent notation. + * If you can't handle multiple opens of the same file, + * you can opt to fail for the second call. + * Returns NULL on failure, and calls PHYSFS_setErrorCode(). + * Returns non-NULL on success. The pointer returned will be + * passed as the "opaque" parameter for later file calls. + */ + PHYSFS_Io *(*openAppend)(void *opaque, const char *filename); + + /** + * Delete a file in the archive/directory. + * Return non-zero on success, zero on failure. + * This filename is in platform-independent notation. + * This method may be NULL. + * On failure, call PHYSFS_setErrorCode(). + */ + int (*remove)(void *opaque, const char *filename); + + /** + * Create a directory in the archive/directory. + * If the application is trying to make multiple dirs, PhysicsFS + * will split them up into multiple calls before passing them to + * your driver. + * Return non-zero on success, zero on failure. + * This filename is in platform-independent notation. + * This method may be NULL. + * On failure, call PHYSFS_setErrorCode(). + */ + int (*mkdir)(void *opaque, const char *filename); + + // !!! FIXME: reorder these methods. + /** + * Close directories/archives, and free any associated memory, + * 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 (*closeArchive)(void *opaque); + + /** + * Obtain basic file metadata. + * Returns non-zero on success, zero on failure. + * On failure, call PHYSFS_setErrorCode(). + */ +// !!! FIXME: remove this exists nonsense (check error code instead) + int (*stat)(void *opaque, const char *fn, int *exists, PHYSFS_Stat *stat); +} PHYSFS_Archiver; + +/** + * \fn int PHYSFS_registerArchiver(const PHYSFS_Archiver *archiver) + * \brief Add a new archiver to the system. + * + * !!! FIXME: write me. + * + * You may not have two archivers that handle the same extension. If you are + * going to have a clash, you can deregister the other archiver (including + * built-in ones) with PHYSFS_deregisterArchiver(). + * + * The data in (archiver) is copied; you may free this pointer when this + * function returns. + * + * \param archiver The archiver to register. + * \return Zero on error, non-zero on success. + * + * \sa PHYSFS_Archiver + * \sa PHYSFS_deregisterArchiver + */ +PHYSFS_DECL int PHYSFS_registerArchiver(const PHYSFS_Archiver *archiver); + +/** + * \fn int PHYSFS_deregisterArchiver(const char *ext) + * \brief Remove an archiver from the system. + * + * !!! FIXME: write me. + * + * This fails if there are any archives still open that use this archiver. + * + * \param ext Filename extension that the archiver handles. + * \return Zero on error, non-zero on success. + * + * \sa PHYSFS_Archiver + * \sa PHYSFS_registerArchiver + */ +PHYSFS_DECL int PHYSFS_deregisterArchiver(const char *ext); + + +/* Everything above this line is part of the PhysicsFS 2.1 API. */ #ifdef __cplusplus } diff --git a/src/physfs_internal.h b/src/physfs_internal.h index 8836aa3b..9a8dee14 100644 --- a/src/physfs_internal.h +++ b/src/physfs_internal.h @@ -124,137 +124,10 @@ void __PHYSFS_smallFree(void *ptr); /* The latest supported PHYSFS_Io::version value. */ #define CURRENT_PHYSFS_IO_API_VERSION 0 -/* Opaque data for file and dir handlers... */ -typedef void PHYSFS_Dir; +/* The latest supported PHYSFS_Archiver::version value. */ +#define CURRENT_PHYSFS_ARCHIVER_API_VERSION 0 -typedef struct -{ - /* - * Basic info about this archiver... - */ - const PHYSFS_ArchiveInfo info; - - - /* - * DIRECTORY ROUTINES: - * These functions are for dir handles. Generate a handle with the - * openArchive() method, then pass it as the "opaque" PHYSFS_Dir to the - * others. - * - * Symlinks should always be followed (except in stat()); PhysicsFS will - * use the stat() method to check for symlinks and make a judgement on - * whether to continue to call other methods based on that. - */ - - /* - * 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. - * (forWrite) 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. We ignore any error code you set here. - * Returns non-NULL on success. The pointer returned will be - * passed as the "opaque" parameter for later calls. - */ - PHYSFS_Dir *(*openArchive)(PHYSFS_Io *io, const char *name, int forWrite); - - /* - * List all files in (dirname). Each file is passed to (cb), - * where a copy is made if appropriate, so you should dispose of - * it properly upon return from the callback. - * You should omit symlinks if (omitSymLinks) is non-zero. - * If you have a failure, report as much as you can. - * (dirname) is in platform-independent notation. - */ - void (*enumerateFiles)(PHYSFS_Dir *opaque, const char *dirname, - int omitSymLinks, PHYSFS_EnumFilesCallback cb, - const char *origdir, void *callbackdata); - - /* - * Open file for reading. - * This filename, (fnm), is in platform-independent notation. - * If you can't handle multiple opens of the same file, - * you can opt to fail for the second call. - * Fail if the file does not exist. - * 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 file calls. - * - * Regardless of success or failure, please set *exists to - * non-zero if the file existed (even if it's a broken symlink!), - * zero if it did not. - */ - PHYSFS_Io *(*openRead)(PHYSFS_Dir *opaque, const char *fnm, int *exists); - - /* - * Open file for writing. - * If the file does not exist, it should be created. If it exists, - * it should be truncated to zero bytes. The writing - * offset should be the start of the file. - * This filename is in platform-independent notation. - * If you can't handle multiple opens of the same file, - * you can opt to fail for the second call. - * 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 file calls. - */ - PHYSFS_Io *(*openWrite)(PHYSFS_Dir *opaque, const char *filename); - - /* - * Open file for appending. - * If the file does not exist, it should be created. The writing - * offset should be the end of the file. - * This filename is in platform-independent notation. - * If you can't handle multiple opens of the same file, - * you can opt to fail for the second call. - * 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 file calls. - */ - PHYSFS_Io *(*openAppend)(PHYSFS_Dir *opaque, const char *filename); - - /* - * Delete a file in the archive/directory. - * Return non-zero on success, zero on failure. - * This filename is in platform-independent notation. - * This method may be NULL. - * On failure, call __PHYSFS_setError(). - */ - int (*remove)(PHYSFS_Dir *opaque, const char *filename); - - /* - * Create a directory in the archive/directory. - * If the application is trying to make multiple dirs, PhysicsFS - * will split them up into multiple calls before passing them to - * your driver. - * Return non-zero on success, zero on failure. - * This filename is in platform-independent notation. - * This method may be NULL. - * On failure, call __PHYSFS_setError(). - */ - int (*mkdir)(PHYSFS_Dir *opaque, const char *filename); - - /* - * Close directories/archives, and free any associated memory, - * 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 (*closeArchive)(PHYSFS_Dir *opaque); - - /* - * Obtain basic file metadata. - * Returns non-zero on success, zero on failure. - * On failure, call __PHYSFS_setError(). - */ - int (*stat)(PHYSFS_Dir *opaque, const char *fn, - int *exists, PHYSFS_Stat *stat); -} PHYSFS_Archiver; - - -/* +/* !!! FIXME: update this documentation. * Call this to set the message returned by PHYSFS_getLastError(). * Please only use the ERR_* constants above, or add new constants to the * above group, but I want these all in one place. @@ -425,17 +298,17 @@ typedef struct PHYSFS_uint32 size; } UNPKentry; -void UNPK_closeArchive(PHYSFS_Dir *opaque); -PHYSFS_Dir *UNPK_openArchive(PHYSFS_Io *io,UNPKentry *e,const PHYSFS_uint32 n); -void UNPK_enumerateFiles(PHYSFS_Dir *opaque, const char *dname, +void UNPK_closeArchive(void *opaque); +void *UNPK_openArchive(PHYSFS_Io *io,UNPKentry *e,const PHYSFS_uint32 n); +void UNPK_enumerateFiles(void *opaque, const char *dname, int omitSymLinks, PHYSFS_EnumFilesCallback cb, const char *origdir, void *callbackdata); -PHYSFS_Io *UNPK_openRead(PHYSFS_Dir *opaque, const char *fnm, int *fileExists); -PHYSFS_Io *UNPK_openWrite(PHYSFS_Dir *opaque, const char *name); -PHYSFS_Io *UNPK_openAppend(PHYSFS_Dir *opaque, const char *name); -int UNPK_remove(PHYSFS_Dir *opaque, const char *name); -int UNPK_mkdir(PHYSFS_Dir *opaque, const char *name); -int UNPK_stat(PHYSFS_Dir *opaque, const char *fn, int *exist, PHYSFS_Stat *st); +PHYSFS_Io *UNPK_openRead(void *opaque, const char *fnm, int *fileExists); +PHYSFS_Io *UNPK_openWrite(void *opaque, const char *name); +PHYSFS_Io *UNPK_openAppend(void *opaque, const char *name); +int UNPK_remove(void *opaque, const char *name); +int UNPK_mkdir(void *opaque, const char *name); +int UNPK_stat(void *opaque, const char *fn, int *exist, PHYSFS_Stat *st); /*--------------------------------------------------------------------------*/ diff --git a/src/platform_posix.c b/src/platform_posix.c index b358fdf8..3b0994c0 100644 --- a/src/platform_posix.c +++ b/src/platform_posix.c @@ -41,9 +41,9 @@ static PHYSFS_ErrorCode errcodeFromErrnoError(const int err) case ELOOP: return PHYSFS_ERR_SYMLINK_LOOP; case EMLINK: return PHYSFS_ERR_NO_SPACE; case ENAMETOOLONG: return PHYSFS_ERR_BAD_FILENAME; - case ENOENT: return PHYSFS_ERR_NO_SUCH_PATH; + case ENOENT: return PHYSFS_ERR_NOT_FOUND; case ENOSPC: return PHYSFS_ERR_NO_SPACE; - case ENOTDIR: return PHYSFS_ERR_NO_SUCH_PATH; + case ENOTDIR: return PHYSFS_ERR_NOT_FOUND; case EISDIR: return PHYSFS_ERR_NOT_A_FILE; case EROFS: return PHYSFS_ERR_READ_ONLY; case ETXTBSY: return PHYSFS_ERR_BUSY; diff --git a/src/platform_windows.c b/src/platform_windows.c index f6079b6f..7b38a98c 100644 --- a/src/platform_windows.c +++ b/src/platform_windows.c @@ -124,13 +124,13 @@ static PHYSFS_ErrorCode errcodeFromWinApiError(const DWORD err) case ERROR_INVALID_NAME: return PHYSFS_ERR_BAD_FILENAME; case ERROR_BAD_PATHNAME: return PHYSFS_ERR_BAD_FILENAME; case ERROR_DIRECTORY: return PHYSFS_ERR_BAD_FILENAME; - case ERROR_FILE_NOT_FOUND: return PHYSFS_ERR_NO_SUCH_PATH; - case ERROR_PATH_NOT_FOUND: return PHYSFS_ERR_NO_SUCH_PATH; - case ERROR_DELETE_PENDING: return PHYSFS_ERR_NO_SUCH_PATH; - case ERROR_INVALID_DRIVE: return PHYSFS_ERR_NO_SUCH_PATH; + case ERROR_FILE_NOT_FOUND: return PHYSFS_ERR_NOT_FOUND; + case ERROR_PATH_NOT_FOUND: return PHYSFS_ERR_NOT_FOUND; + case ERROR_DELETE_PENDING: return PHYSFS_ERR_NOT_FOUND; + case ERROR_INVALID_DRIVE: return PHYSFS_ERR_NOT_FOUND; case ERROR_HANDLE_DISK_FULL: return PHYSFS_ERR_NO_SPACE; case ERROR_DISK_FULL: return PHYSFS_ERR_NO_SPACE; - /* !!! FIXME: ?? case ENOTDIR: return PHYSFS_ERR_NO_SUCH_PATH; */ + /* !!! FIXME: ?? case ENOTDIR: return PHYSFS_ERR_NOT_FOUND; */ /* !!! FIXME: ?? case EISDIR: return PHYSFS_ERR_NOT_A_FILE; */ case ERROR_WRITE_PROTECT: return PHYSFS_ERR_READ_ONLY; case ERROR_LOCK_VIOLATION: return PHYSFS_ERR_BUSY;