Unverified Commit b6e2c003 authored by Rob Loach's avatar Rob Loach
Browse files

Add PhysFS

parent 27473b04
......@@ -4,6 +4,7 @@ INCFLAGS := -I$(CORE_DIR) \
-I$(CORE_DIR)/libretro-common/include \
-I$(CORE_DIR)/deps/zlib \
-I$(CORE_DIR)/deps/retroluxury/src \
-I$(CORE_DIR)/deps/physfs/src \
-I$(CORE_DIR)/deps \
-I$(LUALIB_DIR)
......@@ -60,6 +61,27 @@ SOURCES_C += $(LUALIB_DIR)/lapi.c \
$(LUALIB_DIR)/ldump.c
endif
# PhysFS
PHYSFS_ARCHIVE_ZIP=1
SOURCES_C += $(CORE_DIR)/deps/physfs/src/physfs.c \
$(CORE_DIR)/deps/physfs/src/physfs_byteorder.c \
$(CORE_DIR)/deps/physfs/src/physfs_unicode.c \
$(CORE_DIR)/deps/physfs/src/platform_posix.c \
$(CORE_DIR)/deps/physfs/src/platform_unix.c \
$(CORE_DIR)/deps/physfs/src/platform_macosx.c \
$(CORE_DIR)/deps/physfs/src/platform_windows.c \
$(CORE_DIR)/deps/physfs/src/archiver_dir.c \
$(CORE_DIR)/deps/physfs/src/archiver_unpacked.c \
$(CORE_DIR)/deps/physfs/src/archiver_grp.c \
$(CORE_DIR)/deps/physfs/src/archiver_hog.c \
$(CORE_DIR)/deps/physfs/src/archiver_lzma.c \
$(CORE_DIR)/deps/physfs/src/archiver_mvl.c \
$(CORE_DIR)/deps/physfs/src/archiver_qpak.c \
$(CORE_DIR)/deps/physfs/src/archiver_wad.c \
$(CORE_DIR)/deps/physfs/src/archiver_zip.c \
$(CORE_DIR)/deps/physfs/src/archiver_slb.c \
$(CORE_DIR)/deps/physfs/src/archiver_iso9660.c
SOURCES_C += $(CORE_DIR)/deps/retroluxury/src/external/resample.c \
$(CORE_DIR)/deps/retroluxury/src/rl_resample.c \
$(CORE_DIR)/deps/retroluxury/src/rl_sound.c \
......
Copyright (c) 2001-2016 Ryan C. Gordon and others.
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from
the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software in a
product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Ryan C. Gordon <icculus@icculus.org>
Notes, separate from the license. This is not legal advice.
Versions of PhysicsFS prior to 0.1.9 are licensed under the GNU Lesser General
Public License, which restricts you significantly more. For your own safety,
please make sure you've got 0.1.9 or later if you plan to use physfs in a
commercial or closed-source project.
Optional pieces of PhysicsFS may fall under other licenses, please consult
your lawyer for legal advice, which this is not...
lzma: if you enable LZMA (7zip) support, PhysicsFS uses the lzma sdk.
It uses the LGPL license, with exceptions for closed-source programs.
Please see lzma/lzma.txt for details.
PhysicsFS; a portable, flexible file i/o abstraction.
http://icculus.org/physfs/
Please see the docs directory for documentation, licensing, and information.
/*
* Standard directory I/O support routines for PhysicsFS.
*
* Please see the file LICENSE.txt in the source's root directory.
*
* This file written by Ryan C. Gordon.
*/
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
/* There's no PHYSFS_Io interface here. Use __PHYSFS_createNativeIo(). */
static char *cvtToDependent(const char *prepend, const char *path, char *buf)
{
BAIL_IF_MACRO(buf == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
sprintf(buf, "%s%s", prepend ? prepend : "", path);
if (__PHYSFS_platformDirSeparator != '/')
{
char *p;
for (p = strchr(buf, '/'); p != NULL; p = strchr(p + 1, '/'))
*p = __PHYSFS_platformDirSeparator;
} /* if */
return buf;
} /* cvtToDependent */
#define CVT_TO_DEPENDENT(buf, pre, dir) { \
const size_t len = ((pre) ? strlen((char *) pre) : 0) + strlen(dir) + 1; \
buf = cvtToDependent((char*)pre,dir,(char*)__PHYSFS_smallAlloc(len)); \
}
static void *DIR_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
{
PHYSFS_Stat st;
const char dirsep = __PHYSFS_platformDirSeparator;
char *retval = NULL;
const size_t namelen = strlen(name);
const size_t seplen = 1;
assert(io == NULL); /* shouldn't create an Io for these. */
BAIL_IF_MACRO(!__PHYSFS_platformStat(name, &st), ERRPASS, NULL);
if (st.filetype != PHYSFS_FILETYPE_DIRECTORY)
BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL);
retval = allocator.Malloc(namelen + seplen + 1);
BAIL_IF_MACRO(retval == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
strcpy(retval, name);
/* make sure there's a dir separator at the end of the string */
if (retval[namelen - 1] != dirsep)
{
retval[namelen] = dirsep;
retval[namelen + 1] = '\0';
} /* if */
return retval;
} /* DIR_openArchive */
static void DIR_enumerateFiles(void *opaque, const char *dname,
PHYSFS_EnumFilesCallback cb,
const char *origdir, void *callbackdata)
{
char *d;
CVT_TO_DEPENDENT(d, opaque, dname);
if (d != NULL)
{
__PHYSFS_platformEnumerateFiles(d, cb, origdir, callbackdata);
__PHYSFS_smallFree(d);
} /* if */
} /* DIR_enumerateFiles */
static PHYSFS_Io *doOpen(void *opaque, const char *name, const int mode)
{
PHYSFS_Io *io = NULL;
char *f = NULL;
CVT_TO_DEPENDENT(f, opaque, name);
BAIL_IF_MACRO(!f, ERRPASS, NULL);
io = __PHYSFS_createNativeIo(f, mode);
if (io == NULL)
{
const PHYSFS_ErrorCode err = PHYSFS_getLastErrorCode();
PHYSFS_Stat statbuf;
__PHYSFS_platformStat(f, &statbuf);
PHYSFS_setErrorCode(err);
} /* if */
__PHYSFS_smallFree(f);
return io;
} /* doOpen */
static PHYSFS_Io *DIR_openRead(void *opaque, const char *filename)
{
return doOpen(opaque, filename, 'r');
} /* DIR_openRead */
static PHYSFS_Io *DIR_openWrite(void *opaque, const char *filename)
{
return doOpen(opaque, filename, 'w');
} /* DIR_openWrite */
static PHYSFS_Io *DIR_openAppend(void *opaque, const char *filename)
{
return doOpen(opaque, filename, 'a');
} /* DIR_openAppend */
static int DIR_remove(void *opaque, const char *name)
{
int retval;
char *f;
CVT_TO_DEPENDENT(f, opaque, name);
BAIL_IF_MACRO(!f, ERRPASS, 0);
retval = __PHYSFS_platformDelete(f);
__PHYSFS_smallFree(f);
return retval;
} /* DIR_remove */
static int DIR_mkdir(void *opaque, const char *name)
{
int retval;
char *f;
CVT_TO_DEPENDENT(f, opaque, name);
BAIL_IF_MACRO(!f, ERRPASS, 0);
retval = __PHYSFS_platformMkDir(f);
__PHYSFS_smallFree(f);
return retval;
} /* DIR_mkdir */
static void DIR_closeArchive(void *opaque)
{
allocator.Free(opaque);
} /* DIR_closeArchive */
static int DIR_stat(void *opaque, const char *name, PHYSFS_Stat *stat)
{
int retval = 0;
char *d;
CVT_TO_DEPENDENT(d, opaque, name);
BAIL_IF_MACRO(!d, ERRPASS, 0);
retval = __PHYSFS_platformStat(d, stat);
__PHYSFS_smallFree(d);
return retval;
} /* DIR_stat */
const PHYSFS_Archiver __PHYSFS_Archiver_DIR =
{
CURRENT_PHYSFS_ARCHIVER_API_VERSION,
{
"",
"Non-archive, direct filesystem I/O",
"Ryan C. Gordon <icculus@icculus.org>",
"https://icculus.org/physfs/",
1, /* supportsSymlinks */
},
DIR_openArchive,
DIR_enumerateFiles,
DIR_openRead,
DIR_openWrite,
DIR_openAppend,
DIR_remove,
DIR_mkdir,
DIR_stat,
DIR_closeArchive
};
/* end of archiver_dir.c ... */
/*
* GRP support routines for PhysicsFS.
*
* This driver handles BUILD engine archives ("groupfiles"). This format
* (but not this driver) was put together by Ken Silverman.
*
* The format is simple enough. In Ken's words:
*
* What's the .GRP file format?
*
* The ".grp" file format is just a collection of a lot of files stored
* into 1 big one. I tried to make the format as simple as possible: The
* first 12 bytes contains my name, "KenSilverman". The next 4 bytes is
* the number of files that were compacted into the group file. Then for
* each file, there is a 16 byte structure, where the first 12 bytes are
* the filename, and the last 4 bytes are the file's size. The rest of
* the group file is just the raw data packed one after the other in the
* same order as the list of files.
*
* (That info is from http://www.advsys.net/ken/build.htm ...)
*
* Please see the file LICENSE.txt in the source's root directory.
*
* This file written by Ryan C. Gordon.
*/
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
#if PHYSFS_SUPPORTS_GRP
static UNPKentry *grpLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 fileCount)
{
PHYSFS_uint32 location = 16; /* sizeof sig. */
UNPKentry *entries = NULL;
UNPKentry *entry = NULL;
char *ptr = NULL;
entries = (UNPKentry *) allocator.Malloc(sizeof (UNPKentry) * fileCount);
BAIL_IF_MACRO(entries == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
location += (16 * fileCount);
for (entry = entries; fileCount > 0; fileCount--, entry++)
{
GOTO_IF_MACRO(!__PHYSFS_readAll(io, &entry->name, 12), ERRPASS, failed);
GOTO_IF_MACRO(!__PHYSFS_readAll(io, &entry->size, 4), ERRPASS, failed);
entry->name[12] = '\0'; /* name isn't null-terminated in file. */
if ((ptr = strchr(entry->name, ' ')) != NULL)
*ptr = '\0'; /* trim extra spaces. */
entry->size = PHYSFS_swapULE32(entry->size);
entry->startPos = location;
location += entry->size;
} /* for */
return entries;
failed:
allocator.Free(entries);
return NULL;
} /* grpLoadEntries */
static void *GRP_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
{
PHYSFS_uint8 buf[12];
PHYSFS_uint32 count = 0;
UNPKentry *entries = NULL;
assert(io != NULL); /* shouldn't ever happen. */
BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
BAIL_IF_MACRO(!__PHYSFS_readAll(io, buf, sizeof (buf)), ERRPASS, NULL);
if (memcmp(buf, "KenSilverman", sizeof (buf)) != 0)
BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL);
BAIL_IF_MACRO(!__PHYSFS_readAll(io, &count, sizeof(count)), ERRPASS, NULL);
count = PHYSFS_swapULE32(count);
entries = grpLoadEntries(io, count);
BAIL_IF_MACRO(!entries, ERRPASS, NULL);
return UNPK_openArchive(io, entries, count);
} /* GRP_openArchive */
const PHYSFS_Archiver __PHYSFS_Archiver_GRP =
{
CURRENT_PHYSFS_ARCHIVER_API_VERSION,
{
"GRP",
"Build engine Groupfile format",
"Ryan C. Gordon <icculus@icculus.org>",
"https://icculus.org/physfs/",
0, /* supportsSymlinks */
},
GRP_openArchive,
UNPK_enumerateFiles,
UNPK_openRead,
UNPK_openWrite,
UNPK_openAppend,
UNPK_remove,
UNPK_mkdir,
UNPK_stat,
UNPK_closeArchive
};
#endif /* defined PHYSFS_SUPPORTS_GRP */
/* end of archiver_grp.c ... */
/*
* HOG support routines for PhysicsFS.
*
* This driver handles Descent I/II HOG archives.
*
* The format is very simple:
*
* The file always starts with the 3-byte signature "DHF" (Descent
* HOG file). After that the files of a HOG are just attached after
* another, divided by a 17 bytes header, which specifies the name
* and length (in bytes) of the forthcoming file! So you just read
* the header with its information of how big the following file is,
* and then skip exact that number of bytes to get to the next file
* in that HOG.
*
* char sig[3] = {'D', 'H', 'F'}; // "DHF"=Descent HOG File
*
* struct {
* char file_name[13]; // Filename, padded to 13 bytes with 0s
* int file_size; // filesize in bytes
* char data[file_size]; // The file data
* } FILE_STRUCT; // Repeated until the end of the file.
*
* (That info is from http://www.descent2.com/ddn/specs/hog/)
*
* Please see the file LICENSE.txt in the source's root directory.
*
* This file written by Bradley Bell.
* Based on grp.c by Ryan C. Gordon.
*/
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
#if PHYSFS_SUPPORTS_HOG
static UNPKentry *hogLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 *_entCount)
{
const PHYSFS_uint64 iolen = io->length(io);
PHYSFS_uint32 entCount = 0;
void *ptr = NULL;
UNPKentry *entries = NULL;
UNPKentry *entry = NULL;
PHYSFS_uint32 size = 0;
PHYSFS_uint32 pos = 3;
while (pos < iolen)
{
entCount++;
ptr = allocator.Realloc(ptr, sizeof (UNPKentry) * entCount);
GOTO_IF_MACRO(ptr == NULL, PHYSFS_ERR_OUT_OF_MEMORY, failed);
entries = (UNPKentry *) ptr;
entry = &entries[entCount-1];
GOTO_IF_MACRO(!__PHYSFS_readAll(io, &entry->name, 13), ERRPASS, failed);
pos += 13;
GOTO_IF_MACRO(!__PHYSFS_readAll(io, &size, 4), ERRPASS, failed);
pos += 4;
entry->size = PHYSFS_swapULE32(size);
entry->startPos = pos;
pos += size;
/* skip over entry */
GOTO_IF_MACRO(!io->seek(io, pos), ERRPASS, failed);
} /* while */
*_entCount = entCount;
return entries;
failed:
allocator.Free(entries);
return NULL;
} /* hogLoadEntries */
static void *HOG_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
{
PHYSFS_uint8 buf[3];
PHYSFS_uint32 count = 0;
UNPKentry *entries = NULL;
assert(io != NULL); /* shouldn't ever happen. */
BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
BAIL_IF_MACRO(!__PHYSFS_readAll(io, buf, 3), ERRPASS, NULL);
BAIL_IF_MACRO(memcmp(buf, "DHF", 3) != 0, PHYSFS_ERR_UNSUPPORTED, NULL);
entries = hogLoadEntries(io, &count);
BAIL_IF_MACRO(!entries, ERRPASS, NULL);
return UNPK_openArchive(io, entries, count);
} /* HOG_openArchive */
const PHYSFS_Archiver __PHYSFS_Archiver_HOG =
{
CURRENT_PHYSFS_ARCHIVER_API_VERSION,
{
"HOG",
"Descent I/II HOG file format",
"Bradley Bell <btb@icculus.org>",
"https://icculus.org/physfs/",
0, /* supportsSymlinks */
},
HOG_openArchive,
UNPK_enumerateFiles,
UNPK_openRead,
UNPK_openWrite,
UNPK_openAppend,
UNPK_remove,
UNPK_mkdir,
UNPK_stat,
UNPK_closeArchive
};
#endif /* defined PHYSFS_SUPPORTS_HOG */
/* end of archiver_hog.c ... */
This diff is collapsed.
This diff is collapsed.
/*
* MVL support routines for PhysicsFS.
*
* This driver handles Descent II Movielib archives.
*
* The file format of MVL is quite easy...
*
* //MVL File format - Written by Heiko Herrmann
* char sig[4] = {'D','M', 'V', 'L'}; // "DMVL"=Descent MoVie Library
*
* int num_files; // the number of files in this MVL
*
* struct {
* char file_name[13]; // Filename, padded to 13 bytes with 0s
* int file_size; // filesize in bytes
* }DIR_STRUCT[num_files];
*
* struct {
* char data[file_size]; // The file data
* }FILE_STRUCT[num_files];
*
* (That info is from http://www.descent2.com/ddn/specs/mvl/)
*
* Please see the file LICENSE.txt in the source's root directory.
*
* This file written by Bradley Bell.
* Based on grp.c by Ryan C. Gordon.
*/
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
#if PHYSFS_SUPPORTS_MVL
static UNPKentry *mvlLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 fileCount)
{
PHYSFS_uint32 location = 8; /* sizeof sig. */
UNPKentry *entries = NULL;
UNPKentry *entry = NULL;
entries = (UNPKentry *) allocator.Malloc(sizeof (UNPKentry) * fileCount);
BAIL_IF_MACRO(entries == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
location += (17 * fileCount);
for (entry = entries; fileCount > 0; fileCount--, entry++)
{
if (!__PHYSFS_readAll(io, &entry->name, 13)) goto failed;
if (!__PHYSFS_readAll(io, &entry->size, 4)) goto failed;
entry->size = PHYSFS_swapULE32(entry->size);
entry->startPos = location;
location += entry->size;
} /* for */
return entries;
failed:
allocator.Free(entries);
return NULL;
} /* mvlLoadEntries */
static void *MVL_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
{
PHYSFS_uint8 buf[4];
PHYSFS_uint32 count = 0;
UNPKentry *entries = NULL;
assert(io != NULL); /* shouldn't ever happen. */
BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
BAIL_IF_MACRO(!__PHYSFS_readAll(io, buf, 4), ERRPASS, NULL);
BAIL_IF_MACRO(memcmp(buf, "DMVL", 4) != 0, PHYSFS_ERR_UNSUPPORTED, NULL);
BAIL_IF_MACRO(!__PHYSFS_readAll(io, &count, sizeof(count)), ERRPASS, NULL);
count = PHYSFS_swapULE32(count);
entries = mvlLoadEntries(io, count);
return (!entries) ? NULL : UNPK_openArchive(io, entries, count);
} /* MVL_openArchive */
const PHYSFS_Archiver __PHYSFS_Archiver_MVL =
{
CURRENT_PHYSFS_ARCHIVER_API_VERSION,
{
"MVL",
"Descent II Movielib format",
"Bradley Bell <btb@icculus.org>",
"https://icculus.org/physfs/",
0, /* supportsSymlinks */
},
MVL_openArchive,
UNPK_enumerateFiles,
UNPK_openRead,
UNPK_openWrite,
UNPK_openAppend,
UNPK_remove,
UNPK_mkdir,
UNPK_stat,
UNPK_closeArchive
};
#endif /* defined PHYSFS_SUPPORTS_MVL */
/* end of archiver_mvl.c ... */
/*
* QPAK support routines for PhysicsFS.
*
* This archiver handles the archive format utilized by Quake 1 and 2.