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).
This commit is contained in:
Ryan C. Gordon 2012-11-28 01:36:13 -05:00
parent 123313c3cd
commit e40d80b00f
16 changed files with 520 additions and 226 deletions

View File

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

View File

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

View File

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

View File

@ -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 @@ errorcleanup:
} /* 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 @@ closefile:
} /* 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 @@ errorhandling:
* 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",

View File

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

View File

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

View File

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

View File

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

View File

@ -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 @@ UNPK_openRead_failed:
} /* 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)

View File

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

View File

@ -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 @@ ZIP_openRead_failed:
} /* 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",

View File

@ -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 @@ initializeMutexes_failed:
} /* 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;
const PHYSFS_Archiver * const *i;
assert(numStaticArchivers > 0); /* seriously, none at all?! */
assert(staticArchivers[numStaticArchivers - 1] == NULL);
assert(__PHYSFS_ARRAYLEN(staticArchivers) > 0); /* at least a NULL. */
assert(staticArchivers[__PHYSFS_ARRAYLEN(staticArchivers) - 1] == NULL);
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);
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)
{

View File

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

View File

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

View File

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

View File

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