Added PhysFS lib

This commit is contained in:
pelya
2012-06-19 17:49:54 +03:00
parent 1fe5b68fd0
commit 37ed5c4a6f
33 changed files with 20161 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
repo: 7672c9962ce627edaaa67ff54fe4ad8f9a46dc2b
node: 92a35b8603186c536e4cc126458dfc2d2809b19c
branch: stable-2.0
latesttag: release-2.0.2
latesttagdistance: 1

View File

@@ -0,0 +1,2 @@
syntax:glob
cmake-build

View File

@@ -0,0 +1,16 @@
0bb92a5f0fffd2452cc737346e8b796c213a5688 release-0.1.1
2f2afcbd8abd784f738ac45b0368044763d63748 release-0.1.0
3c7cf50a58fbf220154acd4bdfdf00a21f259eb7 release-0.1.8
473b50402f55b2340fc286775d1b78d18a810362 release-0.1.3
60b5f566a2585d78b2ffadd8d9c16299d0340820 release-1.0.0
67aff4091bf129f7167ed87f937b15f31093e19e release-0.1.9
6ad1722bbcaec1265cb74c9b7be13fe02a547d37 release-0.1.7
8f3ccaaea1cd5dc19235882494d6102e5e9176fb release-0.1.2
c966316c89981bea6ccaa2c2909bb303bfeeb82b release-0.1.6
d2f04ab4b4127757234af6b30bfc98ad4ee9cb15 release-0.1.4
d94f1ccac8095509c57ad640d54796aea0d260f0 release-0.1.5
fe0c1d6f40afa6fca09a277a1ade59231f16c66f release-1.1.1
5d70fca3be361258edfb59c3edaba5abe75a1e88 release-2.0.0
df04959950eb3830c39adfa983789f70f86062d7 release-1.1.0
94771621792f838aa4cacf9a1e1f4f86c1cb0711 release-2.0.1
236afd18dd8cae34adb9897024bdcecc1dc8ca5d release-2.0.2

View File

@@ -0,0 +1,24 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := physfs
APP_SUBDIRS := . archivers platform include
LOCAL_CFLAGS := -O2 -fsigned-char -Dphysfs_EXPORTS -D_REENTRANT -D_THREAD_SAFE -DHAVE_ASSERT_H=1 -DPHYSFS_SUPPORTS_ZIP=1 -DPHYSFS_SUPPORTS_GRP=1 -DPHYSFS_SUPPORTS_HOG=1 -DPHYSFS_SUPPORTS_MVL=1 -DPHYSFS_SUPPORTS_QPAK=1 -D_FILE_OFFSET_BITS=32 -D_LARGE_FILES -DPHYSFS_NO_CDROM_SUPPORT=1
LOCAL_CPP_EXTENSION := .cpp
LOCAL_C_INCLUDES := $(foreach F, $(APP_SUBDIRS), $(LOCAL_PATH)/$(F))
LOCAL_SRC_FILES := $(foreach F, $(APP_SUBDIRS), $(addprefix $(F)/,$(notdir $(wildcard $(LOCAL_PATH)/$(F)/*.c))))
LOCAL_STATIC_LIBRARIES :=
LOCAL_SHARED_LIBRARIES := lzma
LOCAL_LDLIBS := -lz
include $(BUILD_SHARED_LIBRARY)

View File

@@ -0,0 +1,11 @@
The changelog is no longer maintained by hand. It made sense to have a single
timeline when we were using CVS, but modern revision control tools make this
redundant, at best.
If you want a list of changes, updated in real time, just point your web
browser here:
http://hg.icculus.org/icculus/physfs/

View File

@@ -0,0 +1,388 @@
# PhysicsFS; a portable, flexible file i/o abstraction.
# Copyright (C) 2007 Ryan C. Gordon.
#
# Please see the file LICENSE.txt in the source's root directory.
CMAKE_MINIMUM_REQUIRED(VERSION 2.4)
PROJECT(PhysicsFS)
SET(PHYSFS_VERSION 2.0.2)
# Increment this if/when we break backwards compatibility.
SET(PHYSFS_SOVERSION 1)
# I hate that they define "WIN32" ... we're about to move to Win64...I hope!
IF(WIN32 AND NOT WINDOWS)
SET(WINDOWS TRUE)
ENDIF(WIN32 AND NOT WINDOWS)
# Bleh, let's do it for "APPLE" too.
IF(APPLE AND NOT MACOSX)
SET(MACOSX TRUE)
ENDIF(APPLE AND NOT MACOSX)
INCLUDE(CheckIncludeFile)
INCLUDE(CheckLibraryExists)
INCLUDE(CheckCSourceCompiles)
INCLUDE_DIRECTORIES(.)
#INCLUDE_DIRECTORIES(platform)
#INCLUDE_DIRECTORIES(archivers)
IF(MACOSX)
# Fallback to older OS X on PowerPC to support wider range of systems...
IF(CMAKE_OSX_ARCHITECTURES MATCHES ppc)
ADD_DEFINITIONS(-DMAC_OS_X_VERSION_MIN_REQUIRED=1020)
SET(OTHER_LDFLAGS ${OTHER_LDFLAGS} " -mmacosx-version-min=10.2")
ENDIF(CMAKE_OSX_ARCHITECTURES MATCHES ppc)
# Need these everywhere...
ADD_DEFINITIONS(-fno-common)
SET(OTHER_LDFLAGS ${OTHER_LDFLAGS} " -framework Carbon -framework IOKit")
ENDIF(MACOSX)
# Add some gcc-specific command lines.
IF(CMAKE_COMPILER_IS_GNUCC)
# Always build with debug symbols...you can strip it later.
ADD_DEFINITIONS(-g -pipe -Werror -fsigned-char)
# Stupid BeOS generates warnings in the system headers.
IF(NOT BEOS)
ADD_DEFINITIONS(-Wall)
ENDIF(NOT BEOS)
CHECK_C_SOURCE_COMPILES("
#if ((defined(__GNUC__)) && (__GNUC__ >= 4))
int main(int argc, char **argv) { int is_gcc4 = 1; return 0; }
#else
#error This is not gcc4.
#endif
" PHYSFS_IS_GCC4)
IF(PHYSFS_IS_GCC4)
# Not supported on several operating systems at this time.
IF(NOT OS2 AND NOT SOLARIS AND NOT WINDOWS)
ADD_DEFINITIONS(-fvisibility=hidden)
ENDIF(NOT OS2 AND NOT SOLARIS AND NOT WINDOWS)
ENDIF(PHYSFS_IS_GCC4)
ENDIF(CMAKE_COMPILER_IS_GNUCC)
IF(MSVC)
# VS.NET 8.0 got really really anal about strcpy, etc, which even if we
# cleaned up our code, zlib, etc still use...so disable the warning.
ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS=1)
ENDIF(MSVC)
# Basic chunks of source code ...
SET(ZLIB_SRCS
zlib123/adler32.c
zlib123/compress.c
zlib123/crc32.c
zlib123/deflate.c
zlib123/gzio.c
zlib123/infback.c
zlib123/inffast.c
zlib123/inflate.c
zlib123/inftrees.c
zlib123/trees.c
zlib123/uncompr.c
zlib123/zutil.c
)
SET(LZMA_SRCS
lzma/C/7zCrc.c
lzma/C/Archive/7z/7zBuffer.c
lzma/C/Archive/7z/7zDecode.c
lzma/C/Archive/7z/7zExtract.c
lzma/C/Archive/7z/7zHeader.c
lzma/C/Archive/7z/7zIn.c
lzma/C/Archive/7z/7zItem.c
lzma/C/Archive/7z/7zMethodID.c
lzma/C/Compress/Branch/BranchX86.c
lzma/C/Compress/Branch/BranchX86_2.c
lzma/C/Compress/Lzma/LzmaDecode.c
)
IF(BEOS)
# We add this explicitly, since we don't want CMake to think this
# is a C++ project unless we're on BeOS.
SET(PHYSFS_BEOS_SRCS platform/beos.cpp)
FIND_LIBRARY(BE_LIBRARY be)
FIND_LIBRARY(ROOT_LIBRARY root)
SET(OPTIONAL_LIBRARY_LIBS ${OPTIONAL_LIBRARY_LIBS} ${BE_LIBRARY} ${ROOT_LIBRARY})
ENDIF(BEOS)
# Almost everything is "compiled" here, but things that don't apply to the
# build are #ifdef'd out. This is to make it easy to embed PhysicsFS into
# another project or bring up a new build system: just compile all the source
# code and #define the things you want.
SET(PHYSFS_SRCS
physfs.c
physfs_byteorder.c
physfs_unicode.c
platform/os2.c
platform/pocketpc.c
platform/posix.c
platform/unix.c
platform/macosx.c
platform/windows.c
archivers/dir.c
archivers/grp.c
archivers/hog.c
archivers/lzma.c
archivers/mvl.c
archivers/qpak.c
archivers/wad.c
archivers/zip.c
${PHYSFS_BEOS_SRCS}
)
# platform layers ...
IF(UNIX)
IF(BEOS)
SET(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
SET(PHYSFS_HAVE_THREAD_SUPPORT TRUE)
SET(HAVE_PTHREAD_H TRUE)
ELSE(BEOS)
# !!! FIXME
# AC_DEFINE([PHYSFS_HAVE_LLSEEK], 1, [define if we have llseek])
CHECK_INCLUDE_FILE(sys/ucred.h HAVE_UCRED_H)
IF(HAVE_UCRED_H)
ADD_DEFINITIONS(-DPHYSFS_HAVE_SYS_UCRED_H=1)
SET(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
ENDIF(HAVE_UCRED_H)
CHECK_INCLUDE_FILE(mntent.h HAVE_MNTENT_H)
IF(HAVE_MNTENT_H)
ADD_DEFINITIONS(-DPHYSFS_HAVE_MNTENT_H=1)
SET(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
ENDIF(HAVE_MNTENT_H)
CHECK_INCLUDE_FILE(pthread.h HAVE_PTHREAD_H)
IF(HAVE_PTHREAD_H)
SET(PHYSFS_HAVE_THREAD_SUPPORT TRUE)
ENDIF(HAVE_PTHREAD_H)
ENDIF(BEOS)
ENDIF(UNIX)
IF(WINDOWS)
SET(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
SET(PHYSFS_HAVE_THREAD_SUPPORT TRUE)
ENDIF(WINDOWS)
IF(NOT PHYSFS_HAVE_CDROM_SUPPORT)
ADD_DEFINITIONS(-DPHYSFS_NO_CDROM_SUPPORT=1)
MESSAGE(WARNING " ***")
MESSAGE(WARNING " *** There is no CD-ROM support in this build!")
MESSAGE(WARNING " *** PhysicsFS will just pretend there are no discs.")
MESSAGE(WARNING " *** This may be fine, depending on how PhysicsFS is used,")
MESSAGE(WARNING " *** but is this what you REALLY wanted?")
MESSAGE(WARNING " *** (Maybe fix CMakeLists.txt, or write a platform driver?)")
MESSAGE(WARNING " ***")
ENDIF(NOT PHYSFS_HAVE_CDROM_SUPPORT)
IF(PHYSFS_HAVE_THREAD_SUPPORT)
ADD_DEFINITIONS(-D_REENTRANT -D_THREAD_SAFE)
ELSE(PHYSFS_HAVE_THREAD_SUPPORT)
ADD_DEFINITIONS(-DPHYSFS_NO_THREAD_SUPPORT=1)
MESSAGE(WARNING " ***")
MESSAGE(WARNING " *** There is no thread support in this build!")
MESSAGE(WARNING " *** PhysicsFS will NOT be reentrant!")
MESSAGE(WARNING " *** This may be fine, depending on how PhysicsFS is used,")
MESSAGE(WARNING " *** but is this what you REALLY wanted?")
MESSAGE(WARNING " *** (Maybe fix CMakeLists.txt, or write a platform driver?)")
MESSAGE(WARNING " ***")
ENDIF(PHYSFS_HAVE_THREAD_SUPPORT)
CHECK_INCLUDE_FILE(assert.h HAVE_ASSERT_H)
IF(HAVE_ASSERT_H)
ADD_DEFINITIONS(-DHAVE_ASSERT_H=1)
ENDIF(HAVE_ASSERT_H)
# Archivers ...
OPTION(PHYSFS_ARCHIVE_ZIP "Enable ZIP support" TRUE)
IF(PHYSFS_ARCHIVE_ZIP)
ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_ZIP=1)
SET(PHYSFS_NEED_ZLIB TRUE)
ENDIF(PHYSFS_ARCHIVE_ZIP)
OPTION(PHYSFS_ARCHIVE_7Z "Enable 7zip support" TRUE)
IF(PHYSFS_ARCHIVE_7Z)
ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_7Z=1)
# !!! FIXME: rename to 7z.c?
SET(PHYSFS_SRCS ${PHYSFS_SRCS} ${LZMA_SRCS})
ENDIF(PHYSFS_ARCHIVE_7Z)
OPTION(PHYSFS_ARCHIVE_GRP "Enable Build Engine GRP support" TRUE)
IF(PHYSFS_ARCHIVE_GRP)
ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_GRP=1)
ENDIF(PHYSFS_ARCHIVE_GRP)
OPTION(PHYSFS_ARCHIVE_WAD "Enable Doom WAD support" TRUE)
IF(PHYSFS_ARCHIVE_WAD)
ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_WAD=1)
ENDIF(PHYSFS_ARCHIVE_WAD)
OPTION(PHYSFS_ARCHIVE_HOG "Enable Descent I/II HOG support" TRUE)
IF(PHYSFS_ARCHIVE_HOG)
ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_HOG=1)
ENDIF(PHYSFS_ARCHIVE_HOG)
OPTION(PHYSFS_ARCHIVE_MVL "Enable Descent I/II MVL support" TRUE)
IF(PHYSFS_ARCHIVE_MVL)
ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_MVL=1)
ENDIF(PHYSFS_ARCHIVE_MVL)
OPTION(PHYSFS_ARCHIVE_QPAK "Enable Quake I/II QPAK support" TRUE)
IF(PHYSFS_ARCHIVE_QPAK)
ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_QPAK=1)
ENDIF(PHYSFS_ARCHIVE_QPAK)
# See if some archiver required zlib, and see about using system version.
IF(PHYSFS_NEED_ZLIB)
FIND_PACKAGE(ZLIB)
IF(ZLIB_FOUND)
OPTION(PHYSFS_INTERNAL_ZLIB "Link own zlib instead of system library" FALSE)
ELSE(HAVE_SYSTEM_ZLIB)
SET(PHYSFS_INTERNAL_ZLIB TRUE)
ENDIF(ZLIB_FOUND)
IF(PHYSFS_INTERNAL_ZLIB)
INCLUDE_DIRECTORIES(zlib123)
ADD_DEFINITIONS(-DZ_PREFIX=1)
SET(PHYSFS_SRCS ${PHYSFS_SRCS} ${ZLIB_SRCS})
ELSE(PHYSFS_INTERNAL_ZLIB)
SET(OPTIONAL_LIBRARY_LIBS ${OPTIONAL_LIBRARY_LIBS} ${ZLIB_LIBRARY})
INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
ENDIF(PHYSFS_INTERNAL_ZLIB)
ENDIF(PHYSFS_NEED_ZLIB)
OPTION(PHYSFS_BUILD_STATIC "Build static library" TRUE)
IF(PHYSFS_BUILD_STATIC)
ADD_LIBRARY(physfs-static STATIC ${PHYSFS_SRCS})
SET_TARGET_PROPERTIES(physfs-static PROPERTIES OUTPUT_NAME "physfs")
SET(PHYSFS_LIB_TARGET physfs-static)
SET(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";physfs-static")
ENDIF(PHYSFS_BUILD_STATIC)
OPTION(PHYSFS_BUILD_SHARED "Build shared library" TRUE)
IF(PHYSFS_BUILD_SHARED)
ADD_LIBRARY(physfs SHARED ${PHYSFS_SRCS})
SET_TARGET_PROPERTIES(physfs PROPERTIES VERSION ${PHYSFS_VERSION})
SET_TARGET_PROPERTIES(physfs PROPERTIES SOVERSION ${PHYSFS_SOVERSION})
TARGET_LINK_LIBRARIES(physfs ${OPTIONAL_LIBRARY_LIBS} ${OTHER_LDFLAGS})
SET(PHYSFS_LIB_TARGET physfs)
SET(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";physfs")
ENDIF(PHYSFS_BUILD_SHARED)
IF(NOT PHYSFS_BUILD_SHARED AND NOT PHYSFS_BUILD_STATIC)
MESSAGE(FATAL "Both shared and static libraries are disabled!")
ENDIF(NOT PHYSFS_BUILD_SHARED AND NOT PHYSFS_BUILD_STATIC)
# CMake FAQ says I need this...
IF(PHYSFS_BUILD_SHARED AND PHYSFS_BUILD_STATIC)
SET_TARGET_PROPERTIES(physfs PROPERTIES CLEAN_DIRECT_OUTPUT 1)
SET_TARGET_PROPERTIES(physfs-static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
ENDIF(PHYSFS_BUILD_SHARED AND PHYSFS_BUILD_STATIC)
OPTION(PHYSFS_BUILD_TEST "Build stdio test program." TRUE)
MARK_AS_ADVANCED(PHYSFS_BUILD_TEST)
IF(PHYSFS_BUILD_TEST)
FIND_PATH(READLINE_H readline/readline.h)
FIND_PATH(HISTORY_H readline/history.h)
IF(READLINE_H AND HISTORY_H)
FIND_LIBRARY(CURSES_LIBRARY NAMES curses ncurses)
SET(CMAKE_REQUIRED_LIBRARIES ${CURSES_LIBRARY})
FIND_LIBRARY(READLINE_LIBRARY readline)
FIND_LIBRARY(HISTORY_LIBRARY history)
IF(READLINE_LIBRARY AND HISTORY_LIBRARY)
SET(HAVE_SYSTEM_READLINE TRUE)
SET(TEST_PHYSFS_LIBS ${TEST_PHYSFS_LIBS} ${READLINE_LIBRARY} ${CURSES_LIBRARY})
INCLUDE_DIRECTORIES(${READLINE_H} ${HISTORY_H})
ADD_DEFINITIONS(-DPHYSFS_HAVE_READLINE=1)
ENDIF(READLINE_LIBRARY AND HISTORY_LIBRARY)
ENDIF(READLINE_H AND HISTORY_H)
ADD_EXECUTABLE(test_physfs test/test_physfs.c)
TARGET_LINK_LIBRARIES(test_physfs ${PHYSFS_LIB_TARGET} ${TEST_PHYSFS_LIBS} ${OTHER_LDFLAGS})
SET(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";test_physfs")
ENDIF(PHYSFS_BUILD_TEST)
OPTION(PHYSFS_BUILD_WX_TEST "Build wxWidgets test program." TRUE)
MARK_AS_ADVANCED(PHYSFS_BUILD_WX_TEST)
IF(PHYSFS_BUILD_WX_TEST)
SET(wxWidgets_USE_LIBS base core adv)
SET(wxWidgets_INCLUDE_DIRS_NO_SYSTEM 1)
FIND_PACKAGE(wxWidgets)
IF(wxWidgets_FOUND)
INCLUDE(${wxWidgets_USE_FILE})
ADD_EXECUTABLE(wxtest_physfs test/wxtest_physfs.cpp)
SET_SOURCE_FILES_PROPERTIES(test/wxtest_physfs.cpp COMPILE_FLAGS ${wxWidgets_CXX_FLAGS})
TARGET_LINK_LIBRARIES(wxtest_physfs ${PHYSFS_LIB_TARGET} ${wxWidgets_LIBRARIES} ${OTHER_LDFLAGS})
SET(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";wxtest_physfs")
ELSE(wxWidgets_FOUND)
MESSAGE(STATUS "wxWidgets not found. Disabling wx test app.")
SET(PHYSFS_BUILD_WX_TEST FALSE)
ENDIF(wxWidgets_FOUND)
ENDIF(PHYSFS_BUILD_WX_TEST)
INSTALL(TARGETS ${PHYSFS_INSTALL_TARGETS}
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib${LIB_SUFFIX}
ARCHIVE DESTINATION lib${LIB_SUFFIX})
INSTALL(FILES physfs.h DESTINATION include)
FIND_PACKAGE(Doxygen)
IF(DOXYGEN_FOUND)
ADD_CUSTOM_TARGET(docs ${DOXYGEN_EXECUTABLE} COMMENT "Building documentation")
ELSE(DOXYGEN_FOUND)
MESSAGE(STATUS "Doxygen not found. You won't be able to build documentation.")
ENDIF(DOXYGEN_FOUND)
IF(UNIX)
SET(PHYSFS_TARBALL "${CMAKE_CURRENT_SOURCE_DIR}/../physfs-${PHYSFS_VERSION}.tar.gz")
ADD_CUSTOM_TARGET(
dist
hg archive -t tgz "${PHYSFS_TARBALL}"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
COMMENT "Building source tarball '${PHYSFS_TARBALL}'..."
)
ENDIF(UNIX)
MACRO(MESSAGE_BOOL_OPTION _NAME _VALUE)
IF(${_VALUE})
MESSAGE(STATUS " ${_NAME}: enabled")
ELSE(${_VALUE})
MESSAGE(STATUS " ${_NAME}: disabled")
ENDIF(${_VALUE})
ENDMACRO(MESSAGE_BOOL_OPTION)
MESSAGE(STATUS "PhysicsFS will build with the following options:")
MESSAGE_BOOL_OPTION("ZIP support" PHYSFS_ARCHIVE_ZIP)
MESSAGE_BOOL_OPTION("7zip support" PHYSFS_ARCHIVE_7Z)
MESSAGE_BOOL_OPTION("GRP support" PHYSFS_ARCHIVE_GRP)
MESSAGE_BOOL_OPTION("WAD support" PHYSFS_ARCHIVE_WAD)
MESSAGE_BOOL_OPTION("HOG support" PHYSFS_ARCHIVE_HOG)
MESSAGE_BOOL_OPTION("MVL support" PHYSFS_ARCHIVE_MVL)
MESSAGE_BOOL_OPTION("QPAK support" PHYSFS_ARCHIVE_QPAK)
MESSAGE_BOOL_OPTION("CD-ROM drive support" PHYSFS_HAVE_CDROM_SUPPORT)
MESSAGE_BOOL_OPTION("Thread safety" PHYSFS_HAVE_THREAD_SUPPORT)
MESSAGE_BOOL_OPTION("Build own zlib" PHYSFS_INTERNAL_ZLIB)
MESSAGE_BOOL_OPTION("Build static library" PHYSFS_BUILD_STATIC)
MESSAGE_BOOL_OPTION("Build shared library" PHYSFS_BUILD_SHARED)
MESSAGE_BOOL_OPTION("Build wxWidgets test program" PHYSFS_BUILD_WX_TEST)
MESSAGE_BOOL_OPTION("Build stdio test program" PHYSFS_BUILD_TEST)
IF(PHYSFS_BUILD_TEST)
MESSAGE_BOOL_OPTION(" Use readline in test program" HAVE_SYSTEM_READLINE)
ENDIF(PHYSFS_BUILD_TEST)
# end of CMakeLists.txt ...

View File

@@ -0,0 +1,113 @@
Maintainer and general codemonkey:
Ryan C. Gordon
Tons of win32 help:
Adam Gates
More win32 hacking:
Gregory S. Read
Fixes for missing current working directories,
PHYSFS_setSaneConfig() improvements,
other bugfixes:
David Hedbor
Darwin support:
Patrick Stein
configure fixes,
RPM specfile:
Edward Rudd
GetLastModTime API,
other stuff:
John R. Hall
Various support, fixes and suggestions:
Alexander Pipelka
Russian translation,
Ruby bindings,
QPAK archiver:
Ed Sinjiashvili
French translation:
Stéphane Peter
Debian package support:
Colin Bayer
"abs-file.h" in "extras" dir:
Adam D. Moss
WinCE port and other Win32 patches:
Corona688
German translation:
Michael Renner
Apple Project Builder support,
Mac OS X improvements:
Eric Wing
iPhone support:
Christian Gmeiner
HOG archiver,
MVL archiver:
Bradley Bell
MIX archiver:
Sebastian Steinhauer
Bug fixes:
Tolga Dalman
Initial PHYSFS_mount() work:
Philip D. Bober
Brazillian Portuguese translation:
Danny Angelo Carminati Grein
Spanish translation:
Pedro J. Pérez
MacOS Classic fixes,
MPW support,
bug fixes:
Chris Taylor
Mingw support,
General bug fixes:
Matze Braun
Haiku support:
scott mc
Bug fixes:
Jörg Walter
Bug fixes:
Olivier Boudeville
Bug fixes:
Henk Boom
Build system fixes:
Marc Kleine-Budde
Windows .rc file,
7zip/lzma archiver:
Dennis Schridde
OS/2 updates:
Dave Yeo
Bug fixes:
Patrice Mandin
Other stuff:
Your name here! Patches go to icculus@icculus.org ...
/* end of CREDITS.txt ... */

1079
project/jni/physfs/Doxyfile Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,153 @@
The latest PhysicsFS information and releases can be found at:
http://icculus.org/physfs/
Building is (ahem) very easy.
ALL PLATFORMS:
Please understand your rights and mine: read the text file LICENSE.txt in the
root of the source tree. If you can't abide by it, delete this source tree
now. The license is extremely liberal, even to closed-source, commercial
applications.
If you've got Doxygen (http://www.doxygen.org/) installed, you can run it
without any command line arguments in the root of the source tree to generate
the API reference (or build the "docs" target from your build system). This
is optional. You can browse the API docs online here:
http://icculus.org/physfs/docs/
UNIX:
You will need CMake (http://www.cmake.org/) 2.4 or later installed.
Make a directory, wherever you like. This will be your build directory.
Chdir to your build directory. Run "cmake /where/i/unpacked/physfs" to
generate Makefiles. You can then run "ccmake ." and customize the build,
but the defaults are probably okay. You can have CMake generate KDevelop
project files if you prefer these.
Run "make". PhysicsFS will now build.
As root, run "make install".
If you get sick of the library, run "xargs rm < install_manifest.txt" as root
and it will remove all traces of the library from the system paths.
Once you are satisfied, you can delete the build directory.
Primary Unix development is done with GNU/Linux, but PhysicsFS is known to
work out of the box with several flavors of Unix. It it doesn't work, patches
to get it running can be sent to icculus@icculus.org.
BeOS, Zeta, and Haiku:
Use the "Unix" instructions, above. The CMake port to BeOS is fairly new at
the time of this writing, but it works. You can get a build of CMake from
bebits.com or build it yourself from source from cmake.org.
Windows:
If building with Cygwin, mingw32, MSYS, or something else that uses the GNU
toolchain, follow the Unix instructions, above.
If you want to use Visual Studio, nmake, or the Platform SDK, you will need
CMake (http://www.cmake.org/) 2.4 or later installed. Point CMake at the
CMakeLists.txt file in the root of the source directory and hit the
"Configure" button. After telling it what type of compiler you are targeting
(Borland, Visual Studio, etc), CMake will process for while and then give you
a list of options you can change (what archivers you want to support, etc).
If you aren't sure, the defaults are probably fine. Hit the "Configure"
button again, then "OK" once configuration has completed with options that
match your liking. Now project files for your favorite programming
environment will be generated for you in the directory you specified.
Go there and use them to build PhysicsFS.
PhysicsFS will only link directly against system libraries that have existed
since Windows 95 and Windows NT 3.51. If there's a newer API we want to use,
we try to dynamically load it at runtime and fallback to a reasonable
behaviour when we can't find it...this is used for Unicode support and
locating user-specific directories, etc.
PhysicsFS has not been tested on 64-bit Windows, but probably works. There is
no 16-bit Windows support at all. Reports of success and problems can go to
Ryan at icculus@icculus.org ...
If someone is willing to maintain prebuilt PhysicsFS DLLs, I'd like to hear
from you; send an email to icculus@icculus.org ...
PocketPC/WindowsCE:
Code exists for PocketPC support, and there are shipping titles that used
PhysicsFS 1.0 on PocketPC...but it isn't tested in 2.0, and is probably
broken with the new build system. Please send patches.
MAC OS 8/9:
Classic Mac OS support has been dropped in PhysicsFS 2.0. Apple hasn't updated
pre-OSX versions in more than a decade at this point, none of the hardware
they've shipped will boot it for almost as many years, and finding
developer tools for it is becoming almost impossible. As the switch to Intel
hardware has removed the "Classic" emulation environment, it was time to
remove support from PhysicsFS. That being said, the PhysicsFS 1.0 branch can
still target back to Mac OS 8.5, so you can use that if you need support for
this legacy OS. We still very much support Mac OS X, though: see below.
MAC OS X:
You will need CMake (http://www.cmake.org/) 2.4 or later installed.
You can either generate a Unix makefile with CMake, or generate an Xcode
project, whichever makes you more comfortable.
PowerPC and Intel Macs should both be supported.
If someone is willing to maintain prebuilt PhysicsFS Shared Libraries for
Mac OS X, I'd like to hear from you; send an email to icculus@icculus.org.
OS/2:
You need Innotek GCC and libc installed (or kLIBC). I tried this on a stock
Warp 4 install, no fixpaks. You need to install link386.exe (Selective
Install, "link object modules" option). Once klibc and GCC are installed
correctly, unpack the source to PhysicsFS and run the script
file "makeos2.cmd". I know this isn't ideal, but I wanted to have this build
without users having to hunt down a "make" program.
Someone please port CMake to OS/2. Ideally I'd like to be able to target
Innotek GCC and OpenWatcom with CMake.
If someone is willing to maintain prebuilt PhysicsFS Shared Libraries for
OS/2, I'd like to hear from you; send an email to icculus@icculus.org.
OTHER PLATFORMS:
Many Unix-like platforms might "just work" with CMake. Some of these platforms
are known to have worked at one time, but have not been heavily tested, if
tested at all. PhysicsFS is, as far as we know, 64-bit and byteorder clean,
and is known to compile on several compilers across many platforms. To
implement a new platform or archiver, please read the heavily-commented
physfs_internal.h and look in the platform/ and archiver/ directories for
examples.
--ryan. (icculus@icculus.org)

View File

@@ -0,0 +1,44 @@
Copyright (c) 2001-2011 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...
zlib: if you enable ZIP archive support, PhysicsFS uses zlib. Its license
requirements are identical to PhysicsFS.
Please see zlib123/README for details.
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.

View File

@@ -0,0 +1,45 @@
Stuff that needs to be done and wishlist:
These are in no particular order.
Some might be dupes, some might be done already.
UNICODE:
- OS/2: Codepages. No full Unicode in the filesystem, but we can probably make
a conversion effort.
Stuff:
- Other archivers: perhaps tar(.gz|.bz2), RPM, ARJ, etc. These are less
important, since streaming archives aren't of much value to games (which
is why zipfiles are king: random access), but it could have uses for, say,
an installer/updater.
- Reduce malloc() pressure all over the place. We fragment memory like mad.
- profile string list interpolation.
- We have two different ways to find dir entries in zip.c.
- Do symlinks in zip archiver work when they point to dirs?
- Enable more warnings?
- Use __cdecl in physfs.h?
- Look for FIXMEs (many marked with "!!!" in comments).
- Find some way to relax or remove the security model for external tools.
- OSX shouldn't use ~/.app for userdir.
- fscanf and fprintf support in extras dir.
- Why do we call it openArchive and dirClose?
- Sanity check byte order at runtime.
- Memory locking?
- Find a better name than dvoid and fvoid.
- Can windows.c and pocketpc.c get merged?
- There's so much cut-and-paste between archivers...can this be reduced?
- General code audit.
- Multiple write dirs with mount points?
- Deprecate PHYSFS_setSaneConfig and move it to extras?
- Why is physfsrwops.c cut-and-pasted into the ruby bindings?
- Replace code from SDL...
- Should file enumeration return an error or set error state?
- Need "getmountpoint" command in test_physfs.c ...
- Look for calloc() calls that aren't going through the allocation hooks.
- Write up a simple HOWTO on embedding physicsfs in another project.
- Archivers need abstracted i/o to read from memory or files (archives in archives?)
- Probably other stuff. Requests and recommendations are welcome.
// end of TODO.txt ...

View File

@@ -0,0 +1,283 @@
/*
* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "physfs.h"
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
static PHYSFS_sint64 DIR_read(fvoid *opaque, void *buffer,
PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
{
PHYSFS_sint64 retval;
retval = __PHYSFS_platformRead(opaque, buffer, objSize, objCount);
return(retval);
} /* DIR_read */
static PHYSFS_sint64 DIR_write(fvoid *opaque, const void *buffer,
PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
{
PHYSFS_sint64 retval;
retval = __PHYSFS_platformWrite(opaque, buffer, objSize, objCount);
return(retval);
} /* DIR_write */
static int DIR_eof(fvoid *opaque)
{
return(__PHYSFS_platformEOF(opaque));
} /* DIR_eof */
static PHYSFS_sint64 DIR_tell(fvoid *opaque)
{
return(__PHYSFS_platformTell(opaque));
} /* DIR_tell */
static int DIR_seek(fvoid *opaque, PHYSFS_uint64 offset)
{
return(__PHYSFS_platformSeek(opaque, offset));
} /* DIR_seek */
static PHYSFS_sint64 DIR_fileLength(fvoid *opaque)
{
return(__PHYSFS_platformFileLength(opaque));
} /* DIR_fileLength */
static int DIR_fileClose(fvoid *opaque)
{
/*
* we manually flush the buffer, since that's the place a close will
* most likely fail, but that will leave the file handle in an undefined
* state if it fails. Flush failures we can recover from.
*/
BAIL_IF_MACRO(!__PHYSFS_platformFlush(opaque), NULL, 0);
BAIL_IF_MACRO(!__PHYSFS_platformClose(opaque), NULL, 0);
return(1);
} /* DIR_fileClose */
static int DIR_isArchive(const char *filename, int forWriting)
{
/* directories ARE archives in this driver... */
return(__PHYSFS_platformIsDirectory(filename));
} /* DIR_isArchive */
static void *DIR_openArchive(const char *name, int forWriting)
{
const char *dirsep = PHYSFS_getDirSeparator();
char *retval = NULL;
size_t namelen = strlen(name);
size_t seplen = strlen(dirsep);
/* !!! FIXME: when is this not called right before openArchive? */
BAIL_IF_MACRO(!DIR_isArchive(name, forWriting),
ERR_UNSUPPORTED_ARCHIVE, 0);
retval = allocator.Malloc(namelen + seplen + 1);
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
/* make sure there's a dir separator at the end of the string */
strcpy(retval, name);
if (strcmp((name + namelen) - seplen, dirsep) != 0)
strcat(retval, dirsep);
return(retval);
} /* DIR_openArchive */
static void DIR_enumerateFiles(dvoid *opaque, const char *dname,
int omitSymLinks, PHYSFS_EnumFilesCallback cb,
const char *origdir, void *callbackdata)
{
char *d = __PHYSFS_platformCvtToDependent((char *)opaque, dname, NULL);
if (d != NULL)
{
__PHYSFS_platformEnumerateFiles(d, omitSymLinks, cb,
origdir, callbackdata);
allocator.Free(d);
} /* if */
} /* DIR_enumerateFiles */
static int DIR_exists(dvoid *opaque, const char *name)
{
char *f = __PHYSFS_platformCvtToDependent((char *) opaque, name, NULL);
int retval;
BAIL_IF_MACRO(f == NULL, NULL, 0);
retval = __PHYSFS_platformExists(f);
allocator.Free(f);
return(retval);
} /* DIR_exists */
static int DIR_isDirectory(dvoid *opaque, const char *name, int *fileExists)
{
char *d = __PHYSFS_platformCvtToDependent((char *) opaque, name, NULL);
int retval = 0;
BAIL_IF_MACRO(d == NULL, NULL, 0);
*fileExists = __PHYSFS_platformExists(d);
if (*fileExists)
retval = __PHYSFS_platformIsDirectory(d);
allocator.Free(d);
return(retval);
} /* DIR_isDirectory */
static int DIR_isSymLink(dvoid *opaque, const char *name, int *fileExists)
{
char *f = __PHYSFS_platformCvtToDependent((char *) opaque, name, NULL);
int retval = 0;
BAIL_IF_MACRO(f == NULL, NULL, 0);
*fileExists = __PHYSFS_platformExists(f);
if (*fileExists)
retval = __PHYSFS_platformIsSymLink(f);
allocator.Free(f);
return(retval);
} /* DIR_isSymLink */
static PHYSFS_sint64 DIR_getLastModTime(dvoid *opaque,
const char *name,
int *fileExists)
{
char *d = __PHYSFS_platformCvtToDependent((char *) opaque, name, NULL);
PHYSFS_sint64 retval = -1;
BAIL_IF_MACRO(d == NULL, NULL, 0);
*fileExists = __PHYSFS_platformExists(d);
if (*fileExists)
retval = __PHYSFS_platformGetLastModTime(d);
allocator.Free(d);
return(retval);
} /* DIR_getLastModTime */
static fvoid *doOpen(dvoid *opaque, const char *name,
void *(*openFunc)(const char *filename),
int *fileExists)
{
char *f = __PHYSFS_platformCvtToDependent((char *) opaque, name, NULL);
void *rc = NULL;
BAIL_IF_MACRO(f == NULL, NULL, NULL);
if (fileExists != NULL)
{
*fileExists = __PHYSFS_platformExists(f);
if (!(*fileExists))
{
allocator.Free(f);
return(NULL);
} /* if */
} /* if */
rc = openFunc(f);
allocator.Free(f);
return((fvoid *) rc);
} /* doOpen */
static fvoid *DIR_openRead(dvoid *opaque, const char *fnm, int *exist)
{
return(doOpen(opaque, fnm, __PHYSFS_platformOpenRead, exist));
} /* DIR_openRead */
static fvoid *DIR_openWrite(dvoid *opaque, const char *filename)
{
return(doOpen(opaque, filename, __PHYSFS_platformOpenWrite, NULL));
} /* DIR_openWrite */
static fvoid *DIR_openAppend(dvoid *opaque, const char *filename)
{
return(doOpen(opaque, filename, __PHYSFS_platformOpenAppend, NULL));
} /* DIR_openAppend */
static int DIR_remove(dvoid *opaque, const char *name)
{
char *f = __PHYSFS_platformCvtToDependent((char *) opaque, name, NULL);
int retval;
BAIL_IF_MACRO(f == NULL, NULL, 0);
retval = __PHYSFS_platformDelete(f);
allocator.Free(f);
return(retval);
} /* DIR_remove */
static int DIR_mkdir(dvoid *opaque, const char *name)
{
char *f = __PHYSFS_platformCvtToDependent((char *) opaque, name, NULL);
int retval;
BAIL_IF_MACRO(f == NULL, NULL, 0);
retval = __PHYSFS_platformMkDir(f);
allocator.Free(f);
return(retval);
} /* DIR_mkdir */
static void DIR_dirClose(dvoid *opaque)
{
allocator.Free(opaque);
} /* DIR_dirClose */
const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_DIR =
{
"",
DIR_ARCHIVE_DESCRIPTION,
"Ryan C. Gordon <icculus@icculus.org>",
"http://icculus.org/physfs/",
};
const PHYSFS_Archiver __PHYSFS_Archiver_DIR =
{
&__PHYSFS_ArchiveInfo_DIR,
DIR_isArchive, /* isArchive() method */
DIR_openArchive, /* openArchive() method */
DIR_enumerateFiles, /* enumerateFiles() method */
DIR_exists, /* exists() method */
DIR_isDirectory, /* isDirectory() method */
DIR_isSymLink, /* isSymLink() method */
DIR_getLastModTime, /* getLastModTime() method */
DIR_openRead, /* openRead() method */
DIR_openWrite, /* openWrite() method */
DIR_openAppend, /* openAppend() method */
DIR_remove, /* remove() method */
DIR_mkdir, /* mkdir() method */
DIR_dirClose, /* dirClose() method */
DIR_read, /* read() method */
DIR_write, /* write() method */
DIR_eof, /* eof() method */
DIR_tell, /* tell() method */
DIR_seek, /* seek() method */
DIR_fileLength, /* fileLength() method */
DIR_fileClose /* fileClose() method */
};
/* end of dir.c ... */

View File

@@ -0,0 +1,475 @@
/*
* 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.
*/
#if (defined PHYSFS_SUPPORTS_GRP)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "physfs.h"
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
typedef struct
{
char name[13];
PHYSFS_uint32 startPos;
PHYSFS_uint32 size;
} GRPentry;
typedef struct
{
char *filename;
PHYSFS_sint64 last_mod_time;
PHYSFS_uint32 entryCount;
GRPentry *entries;
} GRPinfo;
typedef struct
{
void *handle;
GRPentry *entry;
PHYSFS_uint32 curPos;
} GRPfileinfo;
static void GRP_dirClose(dvoid *opaque)
{
GRPinfo *info = ((GRPinfo *) opaque);
allocator.Free(info->filename);
allocator.Free(info->entries);
allocator.Free(info);
} /* GRP_dirClose */
static PHYSFS_sint64 GRP_read(fvoid *opaque, void *buffer,
PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
{
GRPfileinfo *finfo = (GRPfileinfo *) opaque;
GRPentry *entry = finfo->entry;
PHYSFS_uint32 bytesLeft = entry->size - finfo->curPos;
PHYSFS_uint32 objsLeft = (bytesLeft / objSize);
PHYSFS_sint64 rc;
if (objsLeft < objCount)
objCount = objsLeft;
rc = __PHYSFS_platformRead(finfo->handle, buffer, objSize, objCount);
if (rc > 0)
finfo->curPos += (PHYSFS_uint32) (rc * objSize);
return(rc);
} /* GRP_read */
static PHYSFS_sint64 GRP_write(fvoid *opaque, const void *buffer,
PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
} /* GRP_write */
static int GRP_eof(fvoid *opaque)
{
GRPfileinfo *finfo = (GRPfileinfo *) opaque;
GRPentry *entry = finfo->entry;
return(finfo->curPos >= entry->size);
} /* GRP_eof */
static PHYSFS_sint64 GRP_tell(fvoid *opaque)
{
return(((GRPfileinfo *) opaque)->curPos);
} /* GRP_tell */
static int GRP_seek(fvoid *opaque, PHYSFS_uint64 offset)
{
GRPfileinfo *finfo = (GRPfileinfo *) opaque;
GRPentry *entry = finfo->entry;
int rc;
BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
rc = __PHYSFS_platformSeek(finfo->handle, entry->startPos + offset);
if (rc)
finfo->curPos = (PHYSFS_uint32) offset;
return(rc);
} /* GRP_seek */
static PHYSFS_sint64 GRP_fileLength(fvoid *opaque)
{
GRPfileinfo *finfo = (GRPfileinfo *) opaque;
return((PHYSFS_sint64) finfo->entry->size);
} /* GRP_fileLength */
static int GRP_fileClose(fvoid *opaque)
{
GRPfileinfo *finfo = (GRPfileinfo *) opaque;
BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0);
allocator.Free(finfo);
return(1);
} /* GRP_fileClose */
static int grp_open(const char *filename, int forWriting,
void **fh, PHYSFS_uint32 *count)
{
PHYSFS_uint8 buf[12];
*fh = NULL;
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
*fh = __PHYSFS_platformOpenRead(filename);
BAIL_IF_MACRO(*fh == NULL, NULL, 0);
if (__PHYSFS_platformRead(*fh, buf, 12, 1) != 1)
goto openGrp_failed;
if (memcmp(buf, "KenSilverman", 12) != 0)
{
__PHYSFS_setError(ERR_UNSUPPORTED_ARCHIVE);
goto openGrp_failed;
} /* if */
if (__PHYSFS_platformRead(*fh, count, sizeof (PHYSFS_uint32), 1) != 1)
goto openGrp_failed;
*count = PHYSFS_swapULE32(*count);
return(1);
openGrp_failed:
if (*fh != NULL)
__PHYSFS_platformClose(*fh);
*count = -1;
*fh = NULL;
return(0);
} /* grp_open */
static int GRP_isArchive(const char *filename, int forWriting)
{
void *fh;
PHYSFS_uint32 fileCount;
int retval = grp_open(filename, forWriting, &fh, &fileCount);
if (fh != NULL)
__PHYSFS_platformClose(fh);
return(retval);
} /* GRP_isArchive */
static int grp_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
{
if (one != two)
{
const GRPentry *a = (const GRPentry *) _a;
return(strcmp(a[one].name, a[two].name));
} /* if */
return 0;
} /* grp_entry_cmp */
static void grp_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
{
if (one != two)
{
GRPentry tmp;
GRPentry *first = &(((GRPentry *) _a)[one]);
GRPentry *second = &(((GRPentry *) _a)[two]);
memcpy(&tmp, first, sizeof (GRPentry));
memcpy(first, second, sizeof (GRPentry));
memcpy(second, &tmp, sizeof (GRPentry));
} /* if */
} /* grp_entry_swap */
static int grp_load_entries(const char *name, int forWriting, GRPinfo *info)
{
void *fh = NULL;
PHYSFS_uint32 fileCount;
PHYSFS_uint32 location = 16; /* sizeof sig. */
GRPentry *entry;
char *ptr;
BAIL_IF_MACRO(!grp_open(name, forWriting, &fh, &fileCount), NULL, 0);
info->entryCount = fileCount;
info->entries = (GRPentry *) allocator.Malloc(sizeof(GRPentry)*fileCount);
if (info->entries == NULL)
{
__PHYSFS_platformClose(fh);
BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
} /* if */
location += (16 * fileCount);
for (entry = info->entries; fileCount > 0; fileCount--, entry++)
{
if (__PHYSFS_platformRead(fh, &entry->name, 12, 1) != 1)
{
__PHYSFS_platformClose(fh);
return(0);
} /* if */
entry->name[12] = '\0'; /* name isn't null-terminated in file. */
if ((ptr = strchr(entry->name, ' ')) != NULL)
*ptr = '\0'; /* trim extra spaces. */
if (__PHYSFS_platformRead(fh, &entry->size, 4, 1) != 1)
{
__PHYSFS_platformClose(fh);
return(0);
} /* if */
entry->size = PHYSFS_swapULE32(entry->size);
entry->startPos = location;
location += entry->size;
} /* for */
__PHYSFS_platformClose(fh);
__PHYSFS_sort(info->entries, info->entryCount,
grp_entry_cmp, grp_entry_swap);
return(1);
} /* grp_load_entries */
static void *GRP_openArchive(const char *name, int forWriting)
{
PHYSFS_sint64 modtime = __PHYSFS_platformGetLastModTime(name);
GRPinfo *info = (GRPinfo *) allocator.Malloc(sizeof (GRPinfo));
BAIL_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, 0);
memset(info, '\0', sizeof (GRPinfo));
info->filename = (char *) allocator.Malloc(strlen(name) + 1);
GOTO_IF_MACRO(!info->filename, ERR_OUT_OF_MEMORY, GRP_openArchive_failed);
if (!grp_load_entries(name, forWriting, info))
goto GRP_openArchive_failed;
strcpy(info->filename, name);
info->last_mod_time = modtime;
return(info);
GRP_openArchive_failed:
if (info != NULL)
{
if (info->filename != NULL)
allocator.Free(info->filename);
if (info->entries != NULL)
allocator.Free(info->entries);
allocator.Free(info);
} /* if */
return(NULL);
} /* GRP_openArchive */
static void GRP_enumerateFiles(dvoid *opaque, const char *dname,
int omitSymLinks, PHYSFS_EnumFilesCallback cb,
const char *origdir, void *callbackdata)
{
/* no directories in GRP files. */
if (*dname == '\0')
{
GRPinfo *info = (GRPinfo *) opaque;
GRPentry *entry = info->entries;
PHYSFS_uint32 max = info->entryCount;
PHYSFS_uint32 i;
for (i = 0; i < max; i++, entry++)
cb(callbackdata, origdir, entry->name);
} /* if */
} /* GRP_enumerateFiles */
static GRPentry *grp_find_entry(GRPinfo *info, const char *name)
{
char *ptr = strchr(name, '.');
GRPentry *a = info->entries;
PHYSFS_sint32 lo = 0;
PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
PHYSFS_sint32 middle;
int rc;
/*
* Rule out filenames to avoid unneeded processing...no dirs,
* big filenames, or extensions > 3 chars.
*/
BAIL_IF_MACRO((ptr) && (strlen(ptr) > 4), ERR_NO_SUCH_FILE, NULL);
BAIL_IF_MACRO(strlen(name) > 12, ERR_NO_SUCH_FILE, NULL);
BAIL_IF_MACRO(strchr(name, '/') != NULL, ERR_NO_SUCH_FILE, NULL);
while (lo <= hi)
{
middle = lo + ((hi - lo) / 2);
rc = strcmp(name, a[middle].name);
if (rc == 0) /* found it! */
return(&a[middle]);
else if (rc > 0)
lo = middle + 1;
else
hi = middle - 1;
} /* while */
BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
} /* grp_find_entry */
static int GRP_exists(dvoid *opaque, const char *name)
{
return(grp_find_entry((GRPinfo *) opaque, name) != NULL);
} /* GRP_exists */
static int GRP_isDirectory(dvoid *opaque, const char *name, int *fileExists)
{
*fileExists = GRP_exists(opaque, name);
return(0); /* never directories in a groupfile. */
} /* GRP_isDirectory */
static int GRP_isSymLink(dvoid *opaque, const char *name, int *fileExists)
{
*fileExists = GRP_exists(opaque, name);
return(0); /* never symlinks in a groupfile. */
} /* GRP_isSymLink */
static PHYSFS_sint64 GRP_getLastModTime(dvoid *opaque,
const char *name,
int *fileExists)
{
GRPinfo *info = (GRPinfo *) opaque;
PHYSFS_sint64 retval = -1;
*fileExists = (grp_find_entry(info, name) != NULL);
if (*fileExists) /* use time of GRP itself in the physical filesystem. */
retval = info->last_mod_time;
return(retval);
} /* GRP_getLastModTime */
static fvoid *GRP_openRead(dvoid *opaque, const char *fnm, int *fileExists)
{
GRPinfo *info = (GRPinfo *) opaque;
GRPfileinfo *finfo;
GRPentry *entry;
entry = grp_find_entry(info, fnm);
*fileExists = (entry != NULL);
BAIL_IF_MACRO(entry == NULL, NULL, NULL);
finfo = (GRPfileinfo *) allocator.Malloc(sizeof (GRPfileinfo));
BAIL_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, NULL);
finfo->handle = __PHYSFS_platformOpenRead(info->filename);
if ( (finfo->handle == NULL) ||
(!__PHYSFS_platformSeek(finfo->handle, entry->startPos)) )
{
allocator.Free(finfo);
return(NULL);
} /* if */
finfo->curPos = 0;
finfo->entry = entry;
return(finfo);
} /* GRP_openRead */
static fvoid *GRP_openWrite(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* GRP_openWrite */
static fvoid *GRP_openAppend(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* GRP_openAppend */
static int GRP_remove(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* GRP_remove */
static int GRP_mkdir(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* GRP_mkdir */
const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_GRP =
{
"GRP",
GRP_ARCHIVE_DESCRIPTION,
"Ryan C. Gordon <icculus@icculus.org>",
"http://icculus.org/physfs/",
};
const PHYSFS_Archiver __PHYSFS_Archiver_GRP =
{
&__PHYSFS_ArchiveInfo_GRP,
GRP_isArchive, /* isArchive() method */
GRP_openArchive, /* openArchive() method */
GRP_enumerateFiles, /* enumerateFiles() method */
GRP_exists, /* exists() method */
GRP_isDirectory, /* isDirectory() method */
GRP_isSymLink, /* isSymLink() method */
GRP_getLastModTime, /* getLastModTime() method */
GRP_openRead, /* openRead() method */
GRP_openWrite, /* openWrite() method */
GRP_openAppend, /* openAppend() method */
GRP_remove, /* remove() method */
GRP_mkdir, /* mkdir() method */
GRP_dirClose, /* dirClose() method */
GRP_read, /* read() method */
GRP_write, /* write() method */
GRP_eof, /* eof() method */
GRP_tell, /* tell() method */
GRP_seek, /* seek() method */
GRP_fileLength, /* fileLength() method */
GRP_fileClose /* fileClose() method */
};
#endif /* defined PHYSFS_SUPPORTS_GRP */
/* end of grp.c ... */

View File

@@ -0,0 +1,514 @@
/*
* 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.
*/
#if (defined PHYSFS_SUPPORTS_HOG)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "physfs.h"
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
/*
* One HOGentry is kept for each file in an open HOG archive.
*/
typedef struct
{
char name[13];
PHYSFS_uint32 startPos;
PHYSFS_uint32 size;
} HOGentry;
/*
* One HOGinfo is kept for each open HOG archive.
*/
typedef struct
{
char *filename;
PHYSFS_sint64 last_mod_time;
PHYSFS_uint32 entryCount;
HOGentry *entries;
} HOGinfo;
/*
* One HOGfileinfo is kept for each open file in a HOG archive.
*/
typedef struct
{
void *handle;
HOGentry *entry;
PHYSFS_uint32 curPos;
} HOGfileinfo;
static void HOG_dirClose(dvoid *opaque)
{
HOGinfo *info = ((HOGinfo *) opaque);
allocator.Free(info->filename);
allocator.Free(info->entries);
allocator.Free(info);
} /* HOG_dirClose */
static PHYSFS_sint64 HOG_read(fvoid *opaque, void *buffer,
PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
{
HOGfileinfo *finfo = (HOGfileinfo *) opaque;
HOGentry *entry = finfo->entry;
PHYSFS_uint32 bytesLeft = entry->size - finfo->curPos;
PHYSFS_uint32 objsLeft = (bytesLeft / objSize);
PHYSFS_sint64 rc;
if (objsLeft < objCount)
objCount = objsLeft;
rc = __PHYSFS_platformRead(finfo->handle, buffer, objSize, objCount);
if (rc > 0)
finfo->curPos += (PHYSFS_uint32) (rc * objSize);
return(rc);
} /* HOG_read */
static PHYSFS_sint64 HOG_write(fvoid *opaque, const void *buffer,
PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
} /* HOG_write */
static int HOG_eof(fvoid *opaque)
{
HOGfileinfo *finfo = (HOGfileinfo *) opaque;
HOGentry *entry = finfo->entry;
return(finfo->curPos >= entry->size);
} /* HOG_eof */
static PHYSFS_sint64 HOG_tell(fvoid *opaque)
{
return(((HOGfileinfo *) opaque)->curPos);
} /* HOG_tell */
static int HOG_seek(fvoid *opaque, PHYSFS_uint64 offset)
{
HOGfileinfo *finfo = (HOGfileinfo *) opaque;
HOGentry *entry = finfo->entry;
int rc;
BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
rc = __PHYSFS_platformSeek(finfo->handle, entry->startPos + offset);
if (rc)
finfo->curPos = (PHYSFS_uint32) offset;
return(rc);
} /* HOG_seek */
static PHYSFS_sint64 HOG_fileLength(fvoid *opaque)
{
HOGfileinfo *finfo = (HOGfileinfo *) opaque;
return((PHYSFS_sint64) finfo->entry->size);
} /* HOG_fileLength */
static int HOG_fileClose(fvoid *opaque)
{
HOGfileinfo *finfo = (HOGfileinfo *) opaque;
BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0);
allocator.Free(finfo);
return(1);
} /* HOG_fileClose */
static int hog_open(const char *filename, int forWriting,
void **fh, PHYSFS_uint32 *count)
{
PHYSFS_uint8 buf[13];
PHYSFS_uint32 size;
PHYSFS_sint64 pos;
*count = 0;
*fh = NULL;
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
*fh = __PHYSFS_platformOpenRead(filename);
BAIL_IF_MACRO(*fh == NULL, NULL, 0);
if (__PHYSFS_platformRead(*fh, buf, 3, 1) != 1)
goto openHog_failed;
if (memcmp(buf, "DHF", 3) != 0)
{
__PHYSFS_setError(ERR_UNSUPPORTED_ARCHIVE);
goto openHog_failed;
} /* if */
while (1)
{
if (__PHYSFS_platformRead(*fh, buf, 13, 1) != 1)
break; /* eof here is ok */
if (__PHYSFS_platformRead(*fh, &size, 4, 1) != 1)
goto openHog_failed;
size = PHYSFS_swapULE32(size);
(*count)++;
/* Skip over entry... */
pos = __PHYSFS_platformTell(*fh);
if (pos == -1)
goto openHog_failed;
if (!__PHYSFS_platformSeek(*fh, pos + size))
goto openHog_failed;
} /* while */
/* Rewind to start of entries... */
if (!__PHYSFS_platformSeek(*fh, 3))
goto openHog_failed;
return(1);
openHog_failed:
if (*fh != NULL)
__PHYSFS_platformClose(*fh);
*count = -1;
*fh = NULL;
return(0);
} /* hog_open */
static int HOG_isArchive(const char *filename, int forWriting)
{
void *fh;
PHYSFS_uint32 fileCount;
int retval = hog_open(filename, forWriting, &fh, &fileCount);
if (fh != NULL)
__PHYSFS_platformClose(fh);
return(retval);
} /* HOG_isArchive */
static int hog_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
{
if (one != two)
{
const HOGentry *a = (const HOGentry *) _a;
return(__PHYSFS_stricmpASCII(a[one].name, a[two].name));
} /* if */
return 0;
} /* hog_entry_cmp */
static void hog_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
{
if (one != two)
{
HOGentry tmp;
HOGentry *first = &(((HOGentry *) _a)[one]);
HOGentry *second = &(((HOGentry *) _a)[two]);
memcpy(&tmp, first, sizeof (HOGentry));
memcpy(first, second, sizeof (HOGentry));
memcpy(second, &tmp, sizeof (HOGentry));
} /* if */
} /* hog_entry_swap */
static int hog_load_entries(const char *name, int forWriting, HOGinfo *info)
{
void *fh = NULL;
PHYSFS_uint32 fileCount;
HOGentry *entry;
BAIL_IF_MACRO(!hog_open(name, forWriting, &fh, &fileCount), NULL, 0);
info->entryCount = fileCount;
info->entries = (HOGentry *) allocator.Malloc(sizeof(HOGentry)*fileCount);
if (info->entries == NULL)
{
__PHYSFS_platformClose(fh);
BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
} /* if */
for (entry = info->entries; fileCount > 0; fileCount--, entry++)
{
if (__PHYSFS_platformRead(fh, &entry->name, 13, 1) != 1)
{
__PHYSFS_platformClose(fh);
return(0);
} /* if */
if (__PHYSFS_platformRead(fh, &entry->size, 4, 1) != 1)
{
__PHYSFS_platformClose(fh);
return(0);
} /* if */
entry->size = PHYSFS_swapULE32(entry->size);
entry->startPos = (unsigned int) __PHYSFS_platformTell(fh);
if (entry->startPos == -1)
{
__PHYSFS_platformClose(fh);
return(0);
}
/* Skip over entry */
if (!__PHYSFS_platformSeek(fh, entry->startPos + entry->size))
{
__PHYSFS_platformClose(fh);
return(0);
}
} /* for */
__PHYSFS_platformClose(fh);
__PHYSFS_sort(info->entries, info->entryCount,
hog_entry_cmp, hog_entry_swap);
return(1);
} /* hog_load_entries */
static void *HOG_openArchive(const char *name, int forWriting)
{
PHYSFS_sint64 modtime = __PHYSFS_platformGetLastModTime(name);
HOGinfo *info = (HOGinfo *) allocator.Malloc(sizeof (HOGinfo));
BAIL_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, 0);
memset(info, '\0', sizeof (HOGinfo));
info->filename = (char *) allocator.Malloc(strlen(name) + 1);
GOTO_IF_MACRO(!info->filename, ERR_OUT_OF_MEMORY, HOG_openArchive_failed);
if (!hog_load_entries(name, forWriting, info))
goto HOG_openArchive_failed;
strcpy(info->filename, name);
info->last_mod_time = modtime;
return(info);
HOG_openArchive_failed:
if (info != NULL)
{
if (info->filename != NULL)
allocator.Free(info->filename);
if (info->entries != NULL)
allocator.Free(info->entries);
allocator.Free(info);
} /* if */
return(NULL);
} /* HOG_openArchive */
static void HOG_enumerateFiles(dvoid *opaque, const char *dname,
int omitSymLinks, PHYSFS_EnumFilesCallback cb,
const char *origdir, void *callbackdata)
{
/* no directories in HOG files. */
if (*dname == '\0')
{
HOGinfo *info = (HOGinfo *) opaque;
HOGentry *entry = info->entries;
PHYSFS_uint32 max = info->entryCount;
PHYSFS_uint32 i;
for (i = 0; i < max; i++, entry++)
cb(callbackdata, origdir, entry->name);
} /* if */
} /* HOG_enumerateFiles */
static HOGentry *hog_find_entry(HOGinfo *info, const char *name)
{
char *ptr = strchr(name, '.');
HOGentry *a = info->entries;
PHYSFS_sint32 lo = 0;
PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
PHYSFS_sint32 middle;
int rc;
/*
* Rule out filenames to avoid unneeded processing...no dirs,
* big filenames, or extensions > 3 chars.
*/
BAIL_IF_MACRO((ptr) && (strlen(ptr) > 4), ERR_NO_SUCH_FILE, NULL);
BAIL_IF_MACRO(strlen(name) > 12, ERR_NO_SUCH_FILE, NULL);
BAIL_IF_MACRO(strchr(name, '/') != NULL, ERR_NO_SUCH_FILE, NULL);
while (lo <= hi)
{
middle = lo + ((hi - lo) / 2);
rc = __PHYSFS_stricmpASCII(name, a[middle].name);
if (rc == 0) /* found it! */
return(&a[middle]);
else if (rc > 0)
lo = middle + 1;
else
hi = middle - 1;
} /* while */
BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
} /* hog_find_entry */
static int HOG_exists(dvoid *opaque, const char *name)
{
return(hog_find_entry(((HOGinfo *) opaque), name) != NULL);
} /* HOG_exists */
static int HOG_isDirectory(dvoid *opaque, const char *name, int *fileExists)
{
*fileExists = HOG_exists(opaque, name);
return(0); /* never directories in a groupfile. */
} /* HOG_isDirectory */
static int HOG_isSymLink(dvoid *opaque, const char *name, int *fileExists)
{
*fileExists = HOG_exists(opaque, name);
return(0); /* never symlinks in a groupfile. */
} /* HOG_isSymLink */
static PHYSFS_sint64 HOG_getLastModTime(dvoid *opaque,
const char *name,
int *fileExists)
{
HOGinfo *info = ((HOGinfo *) opaque);
PHYSFS_sint64 retval = -1;
*fileExists = (hog_find_entry(info, name) != NULL);
if (*fileExists) /* use time of HOG itself in the physical filesystem. */
retval = info->last_mod_time;
return(retval);
} /* HOG_getLastModTime */
static fvoid *HOG_openRead(dvoid *opaque, const char *fnm, int *fileExists)
{
HOGinfo *info = ((HOGinfo *) opaque);
HOGfileinfo *finfo;
HOGentry *entry;
entry = hog_find_entry(info, fnm);
*fileExists = (entry != NULL);
BAIL_IF_MACRO(entry == NULL, NULL, NULL);
finfo = (HOGfileinfo *) allocator.Malloc(sizeof (HOGfileinfo));
BAIL_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, NULL);
finfo->handle = __PHYSFS_platformOpenRead(info->filename);
if ( (finfo->handle == NULL) ||
(!__PHYSFS_platformSeek(finfo->handle, entry->startPos)) )
{
allocator.Free(finfo);
return(NULL);
} /* if */
finfo->curPos = 0;
finfo->entry = entry;
return(finfo);
} /* HOG_openRead */
static fvoid *HOG_openWrite(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* HOG_openWrite */
static fvoid *HOG_openAppend(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* HOG_openAppend */
static int HOG_remove(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* HOG_remove */
static int HOG_mkdir(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* HOG_mkdir */
const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_HOG =
{
"HOG",
HOG_ARCHIVE_DESCRIPTION,
"Bradley Bell <btb@icculus.org>",
"http://icculus.org/physfs/",
};
const PHYSFS_Archiver __PHYSFS_Archiver_HOG =
{
&__PHYSFS_ArchiveInfo_HOG,
HOG_isArchive, /* isArchive() method */
HOG_openArchive, /* openArchive() method */
HOG_enumerateFiles, /* enumerateFiles() method */
HOG_exists, /* exists() method */
HOG_isDirectory, /* isDirectory() method */
HOG_isSymLink, /* isSymLink() method */
HOG_getLastModTime, /* getLastModTime() method */
HOG_openRead, /* openRead() method */
HOG_openWrite, /* openWrite() method */
HOG_openAppend, /* openAppend() method */
HOG_remove, /* remove() method */
HOG_mkdir, /* mkdir() method */
HOG_dirClose, /* dirClose() method */
HOG_read, /* read() method */
HOG_write, /* write() method */
HOG_eof, /* eof() method */
HOG_tell, /* tell() method */
HOG_seek, /* seek() method */
HOG_fileLength, /* fileLength() method */
HOG_fileClose /* fileClose() method */
};
#endif /* defined PHYSFS_SUPPORTS_HOG */
/* end of hog.c ... */

View File

@@ -0,0 +1,736 @@
/*
* LZMA support routines for PhysicsFS.
*
* Please see the file lzma.txt in the lzma/ directory.
*
* This file was written by Dennis Schridde, with some peeking at "7zMain.c"
* by Igor Pavlov.
*/
#if (defined PHYSFS_SUPPORTS_7Z)
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "physfs.h"
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
#include "lzma/C/7zCrc.h"
#include "lzma/C/Archive/7z/7zIn.h"
#include "lzma/C/Archive/7z/7zExtract.h"
/* 7z internal from 7zIn.c */
extern int TestSignatureCandidate(Byte *testBytes);
#ifdef _LZMA_IN_CB
# define BUFFER_SIZE (1 << 12)
#endif /* _LZMA_IN_CB */
/*
* Carries filestream metadata through 7z
*/
typedef struct _FileInputStream
{
ISzAlloc allocImp; /* Allocation implementation, used by 7z */
ISzAlloc allocTempImp; /* Temporary allocation implementation, used by 7z */
ISzInStream inStream; /* Input stream with read callbacks, used by 7z */
void *file; /* Filehandle, used by read implementation */
#ifdef _LZMA_IN_CB
Byte buffer[BUFFER_SIZE]; /* Buffer, used by read implementation */
#endif /* _LZMA_IN_CB */
} FileInputStream;
/*
* In the 7z format archives are splited into blocks, those are called folders
* Set by LZMA_read()
*/
typedef struct _LZMAfolder
{
PHYSFS_uint32 index; /* Index of folder in archive */
PHYSFS_uint32 references; /* Number of files using this block */
PHYSFS_uint8 *cache; /* Cached folder */
size_t size; /* Size of folder */
} LZMAfolder;
/*
* Set by LZMA_openArchive(), except folder which gets it's values
* in LZMA_read()
*/
typedef struct _LZMAarchive
{
struct _LZMAfile *files; /* Array of files, size == archive->db.Database.NumFiles */
LZMAfolder *folders; /* Array of folders, size == archive->db.Database.NumFolders */
CArchiveDatabaseEx db; /* For 7z: Database */
FileInputStream stream; /* For 7z: Input file incl. read and seek callbacks */
} LZMAarchive;
/* Set by LZMA_openArchive(), except offset which is set by LZMA_read() */
typedef struct _LZMAfile
{
PHYSFS_uint32 index; /* Index of file in archive */
LZMAarchive *archive; /* Link to corresponding archive */
LZMAfolder *folder; /* Link to corresponding folder */
CFileItem *item; /* For 7z: File info, eg. name, size */
size_t offset; /* Offset in folder */
size_t position; /* Current "virtual" position in file */
} LZMAfile;
/* Memory management implementations to be passed to 7z */
static void *SzAllocPhysicsFS(size_t size)
{
return ((size == 0) ? NULL : allocator.Malloc(size));
} /* SzAllocPhysicsFS */
static void SzFreePhysicsFS(void *address)
{
if (address != NULL)
allocator.Free(address);
} /* SzFreePhysicsFS */
/* Filesystem implementations to be passed to 7z */
#ifdef _LZMA_IN_CB
/*
* Read implementation, to be passed to 7z
* WARNING: If the ISzInStream in 'object' is not contained in a valid FileInputStream this _will_ break horribly!
*/
SZ_RESULT SzFileReadImp(void *object, void **buffer, size_t maxReqSize,
size_t *processedSize)
{
FileInputStream *s = (FileInputStream *)(object - offsetof(FileInputStream, inStream)); /* HACK! */
PHYSFS_sint64 processedSizeLoc = 0;
if (maxReqSize > BUFFER_SIZE)
maxReqSize = BUFFER_SIZE;
processedSizeLoc = __PHYSFS_platformRead(s->file, s->buffer, 1, maxReqSize);
*buffer = s->buffer;
if (processedSize != NULL)
*processedSize = (size_t) processedSizeLoc;
return SZ_OK;
} /* SzFileReadImp */
#else
/*
* Read implementation, to be passed to 7z
* WARNING: If the ISzInStream in 'object' is not contained in a valid FileInputStream this _will_ break horribly!
*/
SZ_RESULT SzFileReadImp(void *object, void *buffer, size_t size,
size_t *processedSize)
{
FileInputStream *s = (FileInputStream *)((unsigned long)object - offsetof(FileInputStream, inStream)); /* HACK! */
size_t processedSizeLoc = __PHYSFS_platformRead(s->file, buffer, 1, size);
if (processedSize != 0)
*processedSize = processedSizeLoc;
return SZ_OK;
} /* SzFileReadImp */
#endif
/*
* Seek implementation, to be passed to 7z
* WARNING: If the ISzInStream in 'object' is not contained in a valid FileInputStream this _will_ break horribly!
*/
SZ_RESULT SzFileSeekImp(void *object, CFileSize pos)
{
FileInputStream *s = (FileInputStream *)((unsigned long)object - offsetof(FileInputStream, inStream)); /* HACK! */
if (__PHYSFS_platformSeek(s->file, (PHYSFS_uint64) pos))
return SZ_OK;
return SZE_FAIL;
} /* SzFileSeekImp */
/*
* Translate Microsoft FILETIME (used by 7zip) into UNIX timestamp
*/
static PHYSFS_sint64 lzma_filetime_to_unix_timestamp(CArchiveFileTime *ft)
{
/* MS counts in nanoseconds ... */
const PHYSFS_uint64 FILETIME_NANOTICKS_PER_SECOND = __PHYSFS_UI64(10000000);
/* MS likes to count seconds since 01.01.1601 ... */
const PHYSFS_uint64 FILETIME_UNIX_DIFF = __PHYSFS_UI64(11644473600);
PHYSFS_uint64 filetime = ft->Low | ((PHYSFS_uint64)ft->High << 32);
return filetime/FILETIME_NANOTICKS_PER_SECOND - FILETIME_UNIX_DIFF;
} /* lzma_filetime_to_unix_timestamp */
/*
* Compare a file with a given name, C89 stdlib variant
* Used for sorting
*/
static int lzma_file_cmp_stdlib(const void *key, const void *object)
{
const char *name = (const char *) key;
LZMAfile *file = (LZMAfile *) object;
return(strcmp(name, file->item->Name));
} /* lzma_file_cmp_posix */
/*
* Compare two files with each other based on the name
* Used for sorting
*/
static int lzma_file_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
{
LZMAfile *files = (LZMAfile *) _a;
return(strcmp(files[one].item->Name, files[two].item->Name));
} /* lzma_file_cmp */
/*
* Swap two entries in the file array
*/
static void lzma_file_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
{
LZMAfile tmp;
LZMAfile *first = &(((LZMAfile *) _a)[one]);
LZMAfile *second = &(((LZMAfile *) _a)[two]);
memcpy(&tmp, first, sizeof (LZMAfile));
memcpy(first, second, sizeof (LZMAfile));
memcpy(second, &tmp, sizeof (LZMAfile));
} /* lzma_file_swap */
/*
* Find entry 'name' in 'archive'
*/
static LZMAfile * lzma_find_file(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, ERR_NO_SUCH_FILE, NULL);
return(file);
} /* lzma_find_file */
/*
* Load metadata for the file at given index
*/
static int lzma_file_init(LZMAarchive *archive, PHYSFS_uint32 fileIndex)
{
LZMAfile *file = &archive->files[fileIndex];
PHYSFS_uint32 folderIndex = archive->db.FileIndexToFolderIndexMap[fileIndex];
file->index = fileIndex; /* Store index into 7z array, since we sort our own. */
file->archive = archive;
file->folder = (folderIndex != (PHYSFS_uint32)-1 ? &archive->folders[folderIndex] : NULL); /* Directories don't have a folder (they contain no own data...) */
file->item = &archive->db.Database.Files[fileIndex]; /* Holds crucial data and is often referenced -> Store link */
file->position = 0;
file->offset = 0; /* Offset will be set by LZMA_read() */
return(1);
} /* lzma_load_file */
/*
* Load metadata for all files
*/
static int lzma_files_init(LZMAarchive *archive)
{
PHYSFS_uint32 fileIndex = 0, numFiles = archive->db.Database.NumFiles;
for (fileIndex = 0; fileIndex < numFiles; fileIndex++ )
{
if (!lzma_file_init(archive, fileIndex))
{
return(0); /* FALSE on failure */
}
} /* for */
__PHYSFS_sort(archive->files, numFiles, lzma_file_cmp, lzma_file_swap);
return(1);
} /* lzma_load_files */
/*
* Initialise specified archive
*/
static void lzma_archive_init(LZMAarchive *archive)
{
memset(archive, 0, sizeof(*archive));
/* Prepare callbacks for 7z */
archive->stream.inStream.Read = SzFileReadImp;
archive->stream.inStream.Seek = SzFileSeekImp;
archive->stream.allocImp.Alloc = SzAllocPhysicsFS;
archive->stream.allocImp.Free = SzFreePhysicsFS;
archive->stream.allocTempImp.Alloc = SzAllocPhysicsFS;
archive->stream.allocTempImp.Free = SzFreePhysicsFS;
}
/*
* Deinitialise archive
*/
static void lzma_archive_exit(LZMAarchive *archive)
{
/* Free arrays */
allocator.Free(archive->folders);
allocator.Free(archive->files);
allocator.Free(archive);
}
/*
* Wrap all 7z calls in this, so the physfs error state is set appropriately.
*/
static int lzma_err(SZ_RESULT rc)
{
switch (rc)
{
case SZ_OK: /* Same as LZMA_RESULT_OK */
break;
case SZE_DATA_ERROR: /* Same as LZMA_RESULT_DATA_ERROR */
__PHYSFS_setError(ERR_DATA_ERROR);
break;
case SZE_OUTOFMEMORY:
__PHYSFS_setError(ERR_OUT_OF_MEMORY);
break;
case SZE_CRC_ERROR:
__PHYSFS_setError(ERR_CORRUPTED);
break;
case SZE_NOTIMPL:
__PHYSFS_setError(ERR_NOT_IMPLEMENTED);
break;
case SZE_FAIL:
__PHYSFS_setError(ERR_UNKNOWN_ERROR); /* !!! FIXME: right? */
break;
case SZE_ARCHIVE_ERROR:
__PHYSFS_setError(ERR_CORRUPTED); /* !!! FIXME: right? */
break;
default:
__PHYSFS_setError(ERR_UNKNOWN_ERROR);
} /* switch */
return(rc);
} /* lzma_err */
static PHYSFS_sint64 LZMA_read(fvoid *opaque, void *outBuffer,
PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
{
LZMAfile *file = (LZMAfile *) opaque;
size_t wantedSize = objSize*objCount;
size_t remainingSize = file->item->Size - file->position;
size_t fileSize = 0;
BAIL_IF_MACRO(wantedSize == 0, NULL, 0); /* quick rejection. */
BAIL_IF_MACRO(remainingSize == 0, ERR_PAST_EOF, 0);
if (remainingSize < wantedSize)
{
wantedSize = remainingSize - (remainingSize % objSize);
objCount = (PHYSFS_uint32) (remainingSize / objSize);
BAIL_IF_MACRO(objCount == 0, ERR_PAST_EOF, 0); /* quick rejection. */
__PHYSFS_setError(ERR_PAST_EOF); /* this is always true here. */
} /* if */
/* Only decompress the folder if it is not allready cached */
if (file->folder->cache == NULL)
{
int rc = lzma_err(SzExtract(
&file->archive->stream.inStream, /* compressed data */
&file->archive->db, /* 7z's database, containing everything */
file->index, /* Index into database arrays */
/* Index of cached folder, will be changed by SzExtract */
&file->folder->index,
/* Cache for decompressed folder, allocated/freed by SzExtract */
&file->folder->cache,
/* Size of cache, will be changed by SzExtract */
&file->folder->size,
/* Offset of this file inside the cache, set by SzExtract */
&file->offset,
&fileSize, /* Size of this file */
&file->archive->stream.allocImp,
&file->archive->stream.allocTempImp));
if (rc != SZ_OK)
return -1;
} /* if */
/* Copy wanted bytes over from cache to outBuffer */
memcpy(outBuffer,
(file->folder->cache +
file->offset + file->position),
wantedSize);
file->position += wantedSize; /* Increase virtual position */
return objCount;
} /* LZMA_read */
static PHYSFS_sint64 LZMA_write(fvoid *opaque, const void *buf,
PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
} /* LZMA_write */
static int LZMA_eof(fvoid *opaque)
{
LZMAfile *file = (LZMAfile *) opaque;
return (file->position >= file->item->Size);
} /* LZMA_eof */
static PHYSFS_sint64 LZMA_tell(fvoid *opaque)
{
LZMAfile *file = (LZMAfile *) opaque;
return (file->position);
} /* LZMA_tell */
static int LZMA_seek(fvoid *opaque, PHYSFS_uint64 offset)
{
LZMAfile *file = (LZMAfile *) opaque;
BAIL_IF_MACRO(offset < 0, ERR_SEEK_OUT_OF_RANGE, 0);
BAIL_IF_MACRO(offset > file->item->Size, ERR_PAST_EOF, 0);
file->position = offset; /* We only use a virtual position... */
return 1;
} /* LZMA_seek */
static PHYSFS_sint64 LZMA_fileLength(fvoid *opaque)
{
LZMAfile *file = (LZMAfile *) opaque;
return (file->item->Size);
} /* LZMA_fileLength */
static int LZMA_fileClose(fvoid *opaque)
{
LZMAfile *file = (LZMAfile *) opaque;
BAIL_IF_MACRO(file->folder == NULL, ERR_NOT_A_FILE, 0);
/* Only decrease refcount if someone actually requested this file... Prevents from overflows and close-on-open... */
if (file->folder->references > 0)
file->folder->references--;
if (file->folder->references == 0)
{
/* Free the cache which might have been allocated by LZMA_read() */
allocator.Free(file->folder->cache);
file->folder->cache = NULL;
}
return(1);
} /* LZMA_fileClose */
static int LZMA_isArchive(const char *filename, int forWriting)
{
PHYSFS_uint8 sig[k7zSignatureSize];
void *in;
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
in = __PHYSFS_platformOpenRead(filename);
BAIL_IF_MACRO(in == NULL, NULL, 0);
/* Read signature bytes */
if (__PHYSFS_platformRead(in, sig, k7zSignatureSize, 1) != 1)
{
__PHYSFS_platformClose(in); /* Don't forget to close the file before returning... */
BAIL_MACRO(NULL, 0);
}
__PHYSFS_platformClose(in);
/* Test whether sig is the 7z signature */
return(TestSignatureCandidate(sig));
} /* LZMA_isArchive */
static void *LZMA_openArchive(const char *name, int forWriting)
{
size_t len = 0;
LZMAarchive *archive = NULL;
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, NULL);
BAIL_IF_MACRO(!LZMA_isArchive(name,forWriting), ERR_UNSUPPORTED_ARCHIVE, 0);
archive = (LZMAarchive *) allocator.Malloc(sizeof (LZMAarchive));
BAIL_IF_MACRO(archive == NULL, ERR_OUT_OF_MEMORY, NULL);
lzma_archive_init(archive);
if ( (archive->stream.file = __PHYSFS_platformOpenRead(name)) == NULL )
{
__PHYSFS_platformClose(archive->stream.file);
lzma_archive_exit(archive);
return(NULL); /* Error is set by platformOpenRead! */
}
CrcGenerateTable();
SzArDbExInit(&archive->db);
if (lzma_err(SzArchiveOpen(&archive->stream.inStream,
&archive->db,
&archive->stream.allocImp,
&archive->stream.allocTempImp)) != SZ_OK)
{
SzArDbExFree(&archive->db, SzFreePhysicsFS);
__PHYSFS_platformClose(archive->stream.file);
lzma_archive_exit(archive);
return NULL; /* Error is set by lzma_err! */
} /* if */
len = archive->db.Database.NumFiles * sizeof (LZMAfile);
archive->files = (LZMAfile *) allocator.Malloc(len);
if (archive->files == NULL)
{
SzArDbExFree(&archive->db, SzFreePhysicsFS);
__PHYSFS_platformClose(archive->stream.file);
lzma_archive_exit(archive);
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
}
/*
* Init with 0 so we know when a folder is already cached
* Values will be set by LZMA_openRead()
*/
memset(archive->files, 0, len);
len = archive->db.Database.NumFolders * sizeof (LZMAfolder);
archive->folders = (LZMAfolder *) allocator.Malloc(len);
if (archive->folders == NULL)
{
SzArDbExFree(&archive->db, SzFreePhysicsFS);
__PHYSFS_platformClose(archive->stream.file);
lzma_archive_exit(archive);
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
}
/*
* Init with 0 so we know when a folder is already cached
* Values will be set by LZMA_read()
*/
memset(archive->folders, 0, len);
if(!lzma_files_init(archive))
{
SzArDbExFree(&archive->db, SzFreePhysicsFS);
__PHYSFS_platformClose(archive->stream.file);
lzma_archive_exit(archive);
BAIL_MACRO(ERR_UNKNOWN_ERROR, NULL);
}
return(archive);
} /* LZMA_openArchive */
/*
* Moved to seperate function so we can use alloca then immediately throw
* away the allocated stack space...
*/
static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata,
const char *odir, const char *str, size_t flen)
{
char *newstr = __PHYSFS_smallAlloc(flen + 1);
if (newstr == NULL)
return;
memcpy(newstr, str, flen);
newstr[flen] = '\0';
cb(callbackdata, odir, newstr);
__PHYSFS_smallFree(newstr);
} /* doEnumCallback */
static void LZMA_enumerateFiles(dvoid *opaque, const char *dname,
int omitSymLinks, PHYSFS_EnumFilesCallback cb,
const char *origdir, void *callbackdata)
{
size_t dlen = strlen(dname),
dlen_inc = dlen + ((dlen > 0) ? 1 : 0);
LZMAarchive *archive = (LZMAarchive *) opaque;
LZMAfile *file = NULL,
*lastFile = &archive->files[archive->db.Database.NumFiles];
if (dlen)
{
file = lzma_find_file(archive, dname);
if (file != NULL) /* if 'file' is NULL it should stay so, otherwise errors will not be handled */
file += 1;
}
else
{
file = archive->files;
}
BAIL_IF_MACRO(file == NULL, ERR_NO_SUCH_FILE, );
while (file < lastFile)
{
const char * fname = file->item->Name;
const char * dirNameEnd = fname + dlen_inc;
if (strncmp(dname, fname, dlen) != 0) /* Stop after mismatch, archive->files is sorted */
break;
if (strchr(dirNameEnd, '/')) /* Skip subdirs */
{
file++;
continue;
}
/* Do the actual callback... */
doEnumCallback(cb, callbackdata, origdir, dirNameEnd, strlen(dirNameEnd));
file++;
}
} /* LZMA_enumerateFiles */
static int LZMA_exists(dvoid *opaque, const char *name)
{
LZMAarchive *archive = (LZMAarchive *) opaque;
return(lzma_find_file(archive, name) != NULL);
} /* LZMA_exists */
static PHYSFS_sint64 LZMA_getLastModTime(dvoid *opaque,
const char *name,
int *fileExists)
{
LZMAarchive *archive = (LZMAarchive *) opaque;
LZMAfile *file = lzma_find_file(archive, name);
*fileExists = (file != NULL);
BAIL_IF_MACRO(file == NULL, NULL, -1);
BAIL_IF_MACRO(!file->item->IsLastWriteTimeDefined, NULL, -1); /* write-time may not be defined for every file */
return(lzma_filetime_to_unix_timestamp(&file->item->LastWriteTime));
} /* LZMA_getLastModTime */
static int LZMA_isDirectory(dvoid *opaque, const char *name, int *fileExists)
{
LZMAarchive *archive = (LZMAarchive *) opaque;
LZMAfile *file = lzma_find_file(archive, name);
*fileExists = (file != NULL);
return(file == NULL ? 0 : file->item->IsDirectory);
} /* LZMA_isDirectory */
static int LZMA_isSymLink(dvoid *opaque, const char *name, int *fileExists)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* LZMA_isSymLink */
static fvoid *LZMA_openRead(dvoid *opaque, const char *name, int *fileExists)
{
LZMAarchive *archive = (LZMAarchive *) opaque;
LZMAfile *file = lzma_find_file(archive, name);
*fileExists = (file != NULL);
BAIL_IF_MACRO(file == NULL, ERR_NO_SUCH_FILE, NULL);
BAIL_IF_MACRO(file->folder == NULL, ERR_NOT_A_FILE, NULL);
file->position = 0;
file->folder->references++; /* Increase refcount for automatic cleanup... */
return(file);
} /* LZMA_openRead */
static fvoid *LZMA_openWrite(dvoid *opaque, const char *filename)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* LZMA_openWrite */
static fvoid *LZMA_openAppend(dvoid *opaque, const char *filename)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* LZMA_openAppend */
static void LZMA_dirClose(dvoid *opaque)
{
LZMAarchive *archive = (LZMAarchive *) opaque;
PHYSFS_uint32 fileIndex = 0, numFiles = archive->db.Database.NumFiles;
for (fileIndex = 0; fileIndex < numFiles; fileIndex++)
{
LZMA_fileClose(&archive->files[fileIndex]);
} /* for */
SzArDbExFree(&archive->db, SzFreePhysicsFS);
__PHYSFS_platformClose(archive->stream.file);
lzma_archive_exit(archive);
} /* LZMA_dirClose */
static int LZMA_remove(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* LZMA_remove */
static int LZMA_mkdir(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* LZMA_mkdir */
const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_LZMA =
{
"7Z",
LZMA_ARCHIVE_DESCRIPTION,
"Dennis Schridde <devurandom@gmx.net>",
"http://icculus.org/physfs/",
};
const PHYSFS_Archiver __PHYSFS_Archiver_LZMA =
{
&__PHYSFS_ArchiveInfo_LZMA,
LZMA_isArchive, /* isArchive() method */
LZMA_openArchive, /* openArchive() method */
LZMA_enumerateFiles, /* enumerateFiles() method */
LZMA_exists, /* exists() method */
LZMA_isDirectory, /* isDirectory() method */
LZMA_isSymLink, /* isSymLink() method */
LZMA_getLastModTime, /* getLastModTime() method */
LZMA_openRead, /* openRead() method */
LZMA_openWrite, /* openWrite() method */
LZMA_openAppend, /* openAppend() method */
LZMA_remove, /* remove() method */
LZMA_mkdir, /* mkdir() method */
LZMA_dirClose, /* dirClose() method */
LZMA_read, /* read() method */
LZMA_write, /* write() method */
LZMA_eof, /* eof() method */
LZMA_tell, /* tell() method */
LZMA_seek, /* seek() method */
LZMA_fileLength, /* fileLength() method */
LZMA_fileClose /* fileClose() method */
};
#endif /* defined PHYSFS_SUPPORTS_7Z */
/* end of lzma.c ... */

View File

@@ -0,0 +1,471 @@
/*
* 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.
*/
#if (defined PHYSFS_SUPPORTS_MVL)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "physfs.h"
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
typedef struct
{
char name[13];
PHYSFS_uint32 startPos;
PHYSFS_uint32 size;
} MVLentry;
typedef struct
{
char *filename;
PHYSFS_sint64 last_mod_time;
PHYSFS_uint32 entryCount;
MVLentry *entries;
} MVLinfo;
typedef struct
{
void *handle;
MVLentry *entry;
PHYSFS_uint32 curPos;
} MVLfileinfo;
static void MVL_dirClose(dvoid *opaque)
{
MVLinfo *info = ((MVLinfo *) opaque);
allocator.Free(info->filename);
allocator.Free(info->entries);
allocator.Free(info);
} /* MVL_dirClose */
static PHYSFS_sint64 MVL_read(fvoid *opaque, void *buffer,
PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
{
MVLfileinfo *finfo = (MVLfileinfo *) opaque;
MVLentry *entry = finfo->entry;
PHYSFS_uint32 bytesLeft = entry->size - finfo->curPos;
PHYSFS_uint32 objsLeft = (bytesLeft / objSize);
PHYSFS_sint64 rc;
if (objsLeft < objCount)
objCount = objsLeft;
rc = __PHYSFS_platformRead(finfo->handle, buffer, objSize, objCount);
if (rc > 0)
finfo->curPos += (PHYSFS_uint32) (rc * objSize);
return(rc);
} /* MVL_read */
static PHYSFS_sint64 MVL_write(fvoid *opaque, const void *buffer,
PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
} /* MVL_write */
static int MVL_eof(fvoid *opaque)
{
MVLfileinfo *finfo = (MVLfileinfo *) opaque;
MVLentry *entry = finfo->entry;
return(finfo->curPos >= entry->size);
} /* MVL_eof */
static PHYSFS_sint64 MVL_tell(fvoid *opaque)
{
return(((MVLfileinfo *) opaque)->curPos);
} /* MVL_tell */
static int MVL_seek(fvoid *opaque, PHYSFS_uint64 offset)
{
MVLfileinfo *finfo = (MVLfileinfo *) opaque;
MVLentry *entry = finfo->entry;
int rc;
BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
rc = __PHYSFS_platformSeek(finfo->handle, entry->startPos + offset);
if (rc)
finfo->curPos = (PHYSFS_uint32) offset;
return(rc);
} /* MVL_seek */
static PHYSFS_sint64 MVL_fileLength(fvoid *opaque)
{
MVLfileinfo *finfo = (MVLfileinfo *) opaque;
return((PHYSFS_sint64) finfo->entry->size);
} /* MVL_fileLength */
static int MVL_fileClose(fvoid *opaque)
{
MVLfileinfo *finfo = (MVLfileinfo *) opaque;
BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0);
allocator.Free(finfo);
return(1);
} /* MVL_fileClose */
static int mvl_open(const char *filename, int forWriting,
void **fh, PHYSFS_uint32 *count)
{
PHYSFS_uint8 buf[4];
*fh = NULL;
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
*fh = __PHYSFS_platformOpenRead(filename);
BAIL_IF_MACRO(*fh == NULL, NULL, 0);
if (__PHYSFS_platformRead(*fh, buf, 4, 1) != 1)
goto openMvl_failed;
if (memcmp(buf, "DMVL", 4) != 0)
{
__PHYSFS_setError(ERR_UNSUPPORTED_ARCHIVE);
goto openMvl_failed;
} /* if */
if (__PHYSFS_platformRead(*fh, count, sizeof (PHYSFS_uint32), 1) != 1)
goto openMvl_failed;
*count = PHYSFS_swapULE32(*count);
return(1);
openMvl_failed:
if (*fh != NULL)
__PHYSFS_platformClose(*fh);
*count = -1;
*fh = NULL;
return(0);
} /* mvl_open */
static int MVL_isArchive(const char *filename, int forWriting)
{
void *fh;
PHYSFS_uint32 fileCount;
int retval = mvl_open(filename, forWriting, &fh, &fileCount);
if (fh != NULL)
__PHYSFS_platformClose(fh);
return(retval);
} /* MVL_isArchive */
static int mvl_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
{
if (one != two)
{
const MVLentry *a = (const MVLentry *) _a;
return(strcmp(a[one].name, a[two].name));
} /* if */
return 0;
} /* mvl_entry_cmp */
static void mvl_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
{
if (one != two)
{
MVLentry tmp;
MVLentry *first = &(((MVLentry *) _a)[one]);
MVLentry *second = &(((MVLentry *) _a)[two]);
memcpy(&tmp, first, sizeof (MVLentry));
memcpy(first, second, sizeof (MVLentry));
memcpy(second, &tmp, sizeof (MVLentry));
} /* if */
} /* mvl_entry_swap */
static int mvl_load_entries(const char *name, int forWriting, MVLinfo *info)
{
void *fh = NULL;
PHYSFS_uint32 fileCount;
PHYSFS_uint32 location = 8; /* sizeof sig. */
MVLentry *entry;
BAIL_IF_MACRO(!mvl_open(name, forWriting, &fh, &fileCount), NULL, 0);
info->entryCount = fileCount;
info->entries = (MVLentry *) allocator.Malloc(sizeof(MVLentry)*fileCount);
if (info->entries == NULL)
{
__PHYSFS_platformClose(fh);
BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
} /* if */
location += (17 * fileCount);
for (entry = info->entries; fileCount > 0; fileCount--, entry++)
{
if (__PHYSFS_platformRead(fh, &entry->name, 13, 1) != 1)
{
__PHYSFS_platformClose(fh);
return(0);
} /* if */
if (__PHYSFS_platformRead(fh, &entry->size, 4, 1) != 1)
{
__PHYSFS_platformClose(fh);
return(0);
} /* if */
entry->size = PHYSFS_swapULE32(entry->size);
entry->startPos = location;
location += entry->size;
} /* for */
__PHYSFS_platformClose(fh);
__PHYSFS_sort(info->entries, info->entryCount,
mvl_entry_cmp, mvl_entry_swap);
return(1);
} /* mvl_load_entries */
static void *MVL_openArchive(const char *name, int forWriting)
{
PHYSFS_sint64 modtime = __PHYSFS_platformGetLastModTime(name);
MVLinfo *info = (MVLinfo *) allocator.Malloc(sizeof (MVLinfo));
BAIL_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, NULL);
memset(info, '\0', sizeof (MVLinfo));
info->filename = (char *) allocator.Malloc(strlen(name) + 1);
GOTO_IF_MACRO(!info->filename, ERR_OUT_OF_MEMORY, MVL_openArchive_failed);
if (!mvl_load_entries(name, forWriting, info))
goto MVL_openArchive_failed;
strcpy(info->filename, name);
info->last_mod_time = modtime;
return(info);
MVL_openArchive_failed:
if (info != NULL)
{
if (info->filename != NULL)
allocator.Free(info->filename);
if (info->entries != NULL)
allocator.Free(info->entries);
allocator.Free(info);
} /* if */
return(NULL);
} /* MVL_openArchive */
static void MVL_enumerateFiles(dvoid *opaque, const char *dname,
int omitSymLinks, PHYSFS_EnumFilesCallback cb,
const char *origdir, void *callbackdata)
{
/* no directories in MVL files. */
if (*dname == '\0')
{
MVLinfo *info = ((MVLinfo *) opaque);
MVLentry *entry = info->entries;
PHYSFS_uint32 max = info->entryCount;
PHYSFS_uint32 i;
for (i = 0; i < max; i++, entry++)
cb(callbackdata, origdir, entry->name);
} /* if */
} /* MVL_enumerateFiles */
static MVLentry *mvl_find_entry(MVLinfo *info, const char *name)
{
char *ptr = strchr(name, '.');
MVLentry *a = info->entries;
PHYSFS_sint32 lo = 0;
PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
PHYSFS_sint32 middle;
int rc;
/*
* Rule out filenames to avoid unneeded processing...no dirs,
* big filenames, or extensions > 3 chars.
*/
BAIL_IF_MACRO((ptr) && (strlen(ptr) > 4), ERR_NO_SUCH_FILE, NULL);
BAIL_IF_MACRO(strlen(name) > 12, ERR_NO_SUCH_FILE, NULL);
BAIL_IF_MACRO(strchr(name, '/') != NULL, ERR_NO_SUCH_FILE, NULL);
while (lo <= hi)
{
middle = lo + ((hi - lo) / 2);
rc = __PHYSFS_stricmpASCII(name, a[middle].name);
if (rc == 0) /* found it! */
return(&a[middle]);
else if (rc > 0)
lo = middle + 1;
else
hi = middle - 1;
} /* while */
BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
} /* mvl_find_entry */
static int MVL_exists(dvoid *opaque, const char *name)
{
return(mvl_find_entry(((MVLinfo *) opaque), name) != NULL);
} /* MVL_exists */
static int MVL_isDirectory(dvoid *opaque, const char *name, int *fileExists)
{
*fileExists = MVL_exists(opaque, name);
return(0); /* never directories in a groupfile. */
} /* MVL_isDirectory */
static int MVL_isSymLink(dvoid *opaque, const char *name, int *fileExists)
{
*fileExists = MVL_exists(opaque, name);
return(0); /* never symlinks in a groupfile. */
} /* MVL_isSymLink */
static PHYSFS_sint64 MVL_getLastModTime(dvoid *opaque,
const char *name,
int *fileExists)
{
MVLinfo *info = ((MVLinfo *) opaque);
PHYSFS_sint64 retval = -1;
*fileExists = (mvl_find_entry(info, name) != NULL);
if (*fileExists) /* use time of MVL itself in the physical filesystem. */
retval = info->last_mod_time;
return(retval);
} /* MVL_getLastModTime */
static fvoid *MVL_openRead(dvoid *opaque, const char *fnm, int *fileExists)
{
MVLinfo *info = ((MVLinfo *) opaque);
MVLfileinfo *finfo;
MVLentry *entry;
entry = mvl_find_entry(info, fnm);
*fileExists = (entry != NULL);
BAIL_IF_MACRO(entry == NULL, NULL, NULL);
finfo = (MVLfileinfo *) allocator.Malloc(sizeof (MVLfileinfo));
BAIL_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, NULL);
finfo->handle = __PHYSFS_platformOpenRead(info->filename);
if ( (finfo->handle == NULL) ||
(!__PHYSFS_platformSeek(finfo->handle, entry->startPos)) )
{
allocator.Free(finfo);
return(NULL);
} /* if */
finfo->curPos = 0;
finfo->entry = entry;
return(finfo);
} /* MVL_openRead */
static fvoid *MVL_openWrite(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* MVL_openWrite */
static fvoid *MVL_openAppend(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* MVL_openAppend */
static int MVL_remove(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* MVL_remove */
static int MVL_mkdir(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* MVL_mkdir */
const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_MVL =
{
"MVL",
MVL_ARCHIVE_DESCRIPTION,
"Bradley Bell <btb@icculus.org>",
"http://icculus.org/physfs/",
};
const PHYSFS_Archiver __PHYSFS_Archiver_MVL =
{
&__PHYSFS_ArchiveInfo_MVL,
MVL_isArchive, /* isArchive() method */
MVL_openArchive, /* openArchive() method */
MVL_enumerateFiles, /* enumerateFiles() method */
MVL_exists, /* exists() method */
MVL_isDirectory, /* isDirectory() method */
MVL_isSymLink, /* isSymLink() method */
MVL_getLastModTime, /* getLastModTime() method */
MVL_openRead, /* openRead() method */
MVL_openWrite, /* openWrite() method */
MVL_openAppend, /* openAppend() method */
MVL_remove, /* remove() method */
MVL_mkdir, /* mkdir() method */
MVL_dirClose, /* dirClose() method */
MVL_read, /* read() method */
MVL_write, /* write() method */
MVL_eof, /* eof() method */
MVL_tell, /* tell() method */
MVL_seek, /* seek() method */
MVL_fileLength, /* fileLength() method */
MVL_fileClose /* fileClose() method */
};
#endif /* defined PHYSFS_SUPPORTS_MVL */
/* end of mvl.c ... */

View File

@@ -0,0 +1,633 @@
/*
* QPAK support routines for PhysicsFS.
*
* This archiver handles the archive format utilized by Quake 1 and 2.
* Quake3-based games use the PkZip/Info-Zip format (which our zip.c
* archiver handles).
*
* ========================================================================
*
* This format info (in more detail) comes from:
* http://debian.fmi.uni-sofia.bg/~sergei/cgsr/docs/pak.txt
*
* Quake PAK Format
*
* Header
* (4 bytes) signature = 'PACK'
* (4 bytes) directory offset
* (4 bytes) directory length
*
* Directory
* (56 bytes) file name
* (4 bytes) file position
* (4 bytes) file length
*
* ========================================================================
*
* Please see the file LICENSE.txt in the source's root directory.
*
* This file written by Ryan C. Gordon.
*/
#if (defined PHYSFS_SUPPORTS_QPAK)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "physfs.h"
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
#if 1 /* Make this case insensitive? */
#define QPAK_strcmp(x, y) __PHYSFS_stricmpASCII(x, y)
#define QPAK_strncmp(x, y, z) __PHYSFS_strnicmpASCII(x, y, z)
#else
#define QPAK_strcmp(x, y) strcmp(x, y)
#define QPAK_strncmp(x, y, z) strncmp(x, y, z)
#endif
typedef struct
{
char name[56];
PHYSFS_uint32 startPos;
PHYSFS_uint32 size;
} QPAKentry;
typedef struct
{
char *filename;
PHYSFS_sint64 last_mod_time;
PHYSFS_uint32 entryCount;
QPAKentry *entries;
} QPAKinfo;
typedef struct
{
void *handle;
QPAKentry *entry;
PHYSFS_uint32 curPos;
} QPAKfileinfo;
/* Magic numbers... */
#define QPAK_SIG 0x4b434150 /* "PACK" in ASCII. */
static void QPAK_dirClose(dvoid *opaque)
{
QPAKinfo *info = ((QPAKinfo *) opaque);
allocator.Free(info->filename);
allocator.Free(info->entries);
allocator.Free(info);
} /* QPAK_dirClose */
static PHYSFS_sint64 QPAK_read(fvoid *opaque, void *buffer,
PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
{
QPAKfileinfo *finfo = (QPAKfileinfo *) opaque;
QPAKentry *entry = finfo->entry;
PHYSFS_uint32 bytesLeft = entry->size - finfo->curPos;
PHYSFS_uint32 objsLeft = (bytesLeft / objSize);
PHYSFS_sint64 rc;
if (objsLeft < objCount)
objCount = objsLeft;
rc = __PHYSFS_platformRead(finfo->handle, buffer, objSize, objCount);
if (rc > 0)
finfo->curPos += (PHYSFS_uint32) (rc * objSize);
return(rc);
} /* QPAK_read */
static PHYSFS_sint64 QPAK_write(fvoid *opaque, const void *buffer,
PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
} /* QPAK_write */
static int QPAK_eof(fvoid *opaque)
{
QPAKfileinfo *finfo = (QPAKfileinfo *) opaque;
QPAKentry *entry = finfo->entry;
return(finfo->curPos >= entry->size);
} /* QPAK_eof */
static PHYSFS_sint64 QPAK_tell(fvoid *opaque)
{
return(((QPAKfileinfo *) opaque)->curPos);
} /* QPAK_tell */
static int QPAK_seek(fvoid *opaque, PHYSFS_uint64 offset)
{
QPAKfileinfo *finfo = (QPAKfileinfo *) opaque;
QPAKentry *entry = finfo->entry;
int rc;
BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
rc = __PHYSFS_platformSeek(finfo->handle, entry->startPos + offset);
if (rc)
finfo->curPos = (PHYSFS_uint32) offset;
return(rc);
} /* QPAK_seek */
static PHYSFS_sint64 QPAK_fileLength(fvoid *opaque)
{
QPAKfileinfo *finfo = (QPAKfileinfo *) opaque;
return((PHYSFS_sint64) finfo->entry->size);
} /* QPAK_fileLength */
static int QPAK_fileClose(fvoid *opaque)
{
QPAKfileinfo *finfo = (QPAKfileinfo *) opaque;
BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0);
allocator.Free(finfo);
return(1);
} /* QPAK_fileClose */
static int qpak_open(const char *filename, int forWriting,
void **fh, PHYSFS_uint32 *count)
{
PHYSFS_uint32 buf;
*fh = NULL;
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
*fh = __PHYSFS_platformOpenRead(filename);
BAIL_IF_MACRO(*fh == NULL, NULL, 0);
if (__PHYSFS_platformRead(*fh, &buf, sizeof (PHYSFS_uint32), 1) != 1)
goto openQpak_failed;
buf = PHYSFS_swapULE32(buf);
GOTO_IF_MACRO(buf != QPAK_SIG, ERR_UNSUPPORTED_ARCHIVE, openQpak_failed);
if (__PHYSFS_platformRead(*fh, &buf, sizeof (PHYSFS_uint32), 1) != 1)
goto openQpak_failed;
buf = PHYSFS_swapULE32(buf); /* directory table offset. */
if (__PHYSFS_platformRead(*fh, count, sizeof (PHYSFS_uint32), 1) != 1)
goto openQpak_failed;
*count = PHYSFS_swapULE32(*count);
/* corrupted archive? */
GOTO_IF_MACRO((*count % 64) != 0, ERR_CORRUPTED, openQpak_failed);
if (!__PHYSFS_platformSeek(*fh, buf))
goto openQpak_failed;
*count /= 64;
return(1);
openQpak_failed:
if (*fh != NULL)
__PHYSFS_platformClose(*fh);
*count = -1;
*fh = NULL;
return(0);
} /* qpak_open */
static int QPAK_isArchive(const char *filename, int forWriting)
{
void *fh;
PHYSFS_uint32 fileCount;
int retval = qpak_open(filename, forWriting, &fh, &fileCount);
if (fh != NULL)
__PHYSFS_platformClose(fh);
return(retval);
} /* QPAK_isArchive */
static int qpak_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
{
if (one != two)
{
const QPAKentry *a = (const QPAKentry *) _a;
return(QPAK_strcmp(a[one].name, a[two].name));
} /* if */
return 0;
} /* qpak_entry_cmp */
static void qpak_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
{
if (one != two)
{
QPAKentry tmp;
QPAKentry *first = &(((QPAKentry *) _a)[one]);
QPAKentry *second = &(((QPAKentry *) _a)[two]);
memcpy(&tmp, first, sizeof (QPAKentry));
memcpy(first, second, sizeof (QPAKentry));
memcpy(second, &tmp, sizeof (QPAKentry));
} /* if */
} /* qpak_entry_swap */
static int qpak_load_entries(const char *name, int forWriting, QPAKinfo *info)
{
void *fh = NULL;
PHYSFS_uint32 fileCount;
QPAKentry *entry;
BAIL_IF_MACRO(!qpak_open(name, forWriting, &fh, &fileCount), NULL, 0);
info->entryCount = fileCount;
info->entries = (QPAKentry*) allocator.Malloc(sizeof(QPAKentry)*fileCount);
if (info->entries == NULL)
{
__PHYSFS_platformClose(fh);
BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
} /* if */
for (entry = info->entries; fileCount > 0; fileCount--, entry++)
{
PHYSFS_uint32 loc;
if (__PHYSFS_platformRead(fh,&entry->name,sizeof(entry->name),1) != 1)
{
__PHYSFS_platformClose(fh);
return(0);
} /* if */
if (__PHYSFS_platformRead(fh,&loc,sizeof(loc),1) != 1)
{
__PHYSFS_platformClose(fh);
return(0);
} /* if */
if (__PHYSFS_platformRead(fh,&entry->size,sizeof(entry->size),1) != 1)
{
__PHYSFS_platformClose(fh);
return(0);
} /* if */
entry->size = PHYSFS_swapULE32(entry->size);
entry->startPos = PHYSFS_swapULE32(loc);
} /* for */
__PHYSFS_platformClose(fh);
__PHYSFS_sort(info->entries, info->entryCount,
qpak_entry_cmp, qpak_entry_swap);
return(1);
} /* qpak_load_entries */
static void *QPAK_openArchive(const char *name, int forWriting)
{
QPAKinfo *info = (QPAKinfo *) allocator.Malloc(sizeof (QPAKinfo));
PHYSFS_sint64 modtime = __PHYSFS_platformGetLastModTime(name);
BAIL_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, NULL);
memset(info, '\0', sizeof (QPAKinfo));
info->filename = (char *) allocator.Malloc(strlen(name) + 1);
if (info->filename == NULL)
{
__PHYSFS_setError(ERR_OUT_OF_MEMORY);
goto QPAK_openArchive_failed;
} /* if */
if (!qpak_load_entries(name, forWriting, info))
goto QPAK_openArchive_failed;
strcpy(info->filename, name);
info->last_mod_time = modtime;
return(info);
QPAK_openArchive_failed:
if (info != NULL)
{
if (info->filename != NULL)
allocator.Free(info->filename);
if (info->entries != NULL)
allocator.Free(info->entries);
allocator.Free(info);
} /* if */
return(NULL);
} /* QPAK_openArchive */
static PHYSFS_sint32 qpak_find_start_of_dir(QPAKinfo *info, const char *path,
int stop_on_first_find)
{
PHYSFS_sint32 lo = 0;
PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
PHYSFS_sint32 middle;
PHYSFS_uint32 dlen = strlen(path);
PHYSFS_sint32 retval = -1;
const char *name;
int rc;
if (*path == '\0') /* root dir? */
return(0);
if ((dlen > 0) && (path[dlen - 1] == '/')) /* ignore trailing slash. */
dlen--;
while (lo <= hi)
{
middle = lo + ((hi - lo) / 2);
name = info->entries[middle].name;
rc = QPAK_strncmp(path, name, dlen);
if (rc == 0)
{
char ch = name[dlen];
if (ch < '/') /* make sure this isn't just a substr match. */
rc = -1;
else if (ch > '/')
rc = 1;
else
{
if (stop_on_first_find) /* Just checking dir's existance? */
return(middle);
if (name[dlen + 1] == '\0') /* Skip initial dir entry. */
return(middle + 1);
/* there might be more entries earlier in the list. */
retval = middle;
hi = middle - 1;
} /* else */
} /* if */
if (rc > 0)
lo = middle + 1;
else
hi = middle - 1;
} /* while */
return(retval);
} /* qpak_find_start_of_dir */
/*
* Moved to seperate function so we can use alloca then immediately throw
* away the allocated stack space...
*/
static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata,
const char *odir, const char *str, PHYSFS_sint32 ln)
{
char *newstr = __PHYSFS_smallAlloc(ln + 1);
if (newstr == NULL)
return;
memcpy(newstr, str, ln);
newstr[ln] = '\0';
cb(callbackdata, odir, newstr);
__PHYSFS_smallFree(newstr);
} /* doEnumCallback */
static void QPAK_enumerateFiles(dvoid *opaque, const char *dname,
int omitSymLinks, PHYSFS_EnumFilesCallback cb,
const char *origdir, void *callbackdata)
{
QPAKinfo *info = ((QPAKinfo *) opaque);
PHYSFS_sint32 dlen, dlen_inc, max, i;
i = qpak_find_start_of_dir(info, dname, 0);
if (i == -1) /* no such directory. */
return;
dlen = strlen(dname);
if ((dlen > 0) && (dname[dlen - 1] == '/')) /* ignore trailing slash. */
dlen--;
dlen_inc = ((dlen > 0) ? 1 : 0) + dlen;
max = (PHYSFS_sint32) info->entryCount;
while (i < max)
{
char *add;
char *ptr;
PHYSFS_sint32 ln;
char *e = info->entries[i].name;
if ((dlen) && ((QPAK_strncmp(e, dname, dlen)) || (e[dlen] != '/')))
break; /* past end of this dir; we're done. */
add = e + dlen_inc;
ptr = strchr(add, '/');
ln = (PHYSFS_sint32) ((ptr) ? ptr-add : strlen(add));
doEnumCallback(cb, callbackdata, origdir, add, ln);
ln += dlen_inc; /* point past entry to children... */
/* increment counter and skip children of subdirs... */
while ((++i < max) && (ptr != NULL))
{
char *e_new = info->entries[i].name;
if ((QPAK_strncmp(e, e_new, ln) != 0) || (e_new[ln] != '/'))
break;
} /* while */
} /* while */
} /* QPAK_enumerateFiles */
/*
* This will find the QPAKentry associated with a path in platform-independent
* notation. Directories don't have QPAKentries associated with them, but
* (*isDir) will be set to non-zero if a dir was hit.
*/
static QPAKentry *qpak_find_entry(QPAKinfo *info, const char *path, int *isDir)
{
QPAKentry *a = info->entries;
PHYSFS_sint32 pathlen = strlen(path);
PHYSFS_sint32 lo = 0;
PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
PHYSFS_sint32 middle;
const char *thispath = NULL;
int rc;
while (lo <= hi)
{
middle = lo + ((hi - lo) / 2);
thispath = a[middle].name;
rc = QPAK_strncmp(path, thispath, pathlen);
if (rc > 0)
lo = middle + 1;
else if (rc < 0)
hi = middle - 1;
else /* substring match...might be dir or entry or nothing. */
{
if (isDir != NULL)
{
*isDir = (thispath[pathlen] == '/');
if (*isDir)
return(NULL);
} /* if */
if (thispath[pathlen] == '\0') /* found entry? */
return(&a[middle]);
/* adjust search params, try again. */
else if (thispath[pathlen] > '/')
hi = middle - 1;
else
lo = middle + 1;
} /* if */
} /* while */
if (isDir != NULL)
*isDir = 0;
BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
} /* qpak_find_entry */
static int QPAK_exists(dvoid *opaque, const char *name)
{
int isDir;
QPAKinfo *info = (QPAKinfo *) opaque;
QPAKentry *entry = qpak_find_entry(info, name, &isDir);
return((entry != NULL) || (isDir));
} /* QPAK_exists */
static int QPAK_isDirectory(dvoid *opaque, const char *name, int *fileExists)
{
QPAKinfo *info = (QPAKinfo *) opaque;
int isDir;
QPAKentry *entry = qpak_find_entry(info, name, &isDir);
*fileExists = ((isDir) || (entry != NULL));
if (isDir)
return(1); /* definitely a dir. */
BAIL_MACRO(ERR_NO_SUCH_FILE, 0);
} /* QPAK_isDirectory */
static int QPAK_isSymLink(dvoid *opaque, const char *name, int *fileExists)
{
*fileExists = QPAK_exists(opaque, name);
return(0); /* never symlinks in a quake pak. */
} /* QPAK_isSymLink */
static PHYSFS_sint64 QPAK_getLastModTime(dvoid *opaque,
const char *name,
int *fileExists)
{
int isDir;
QPAKinfo *info = ((QPAKinfo *) opaque);
PHYSFS_sint64 retval = -1;
QPAKentry *entry = qpak_find_entry(info, name, &isDir);
*fileExists = ((isDir) || (entry != NULL));
if (*fileExists) /* use time of QPAK itself in the physical filesystem. */
retval = info->last_mod_time;
return(retval);
} /* QPAK_getLastModTime */
static fvoid *QPAK_openRead(dvoid *opaque, const char *fnm, int *fileExists)
{
QPAKinfo *info = ((QPAKinfo *) opaque);
QPAKfileinfo *finfo;
QPAKentry *entry;
int isDir;
entry = qpak_find_entry(info, fnm, &isDir);
*fileExists = ((entry != NULL) || (isDir));
BAIL_IF_MACRO(isDir, ERR_NOT_A_FILE, NULL);
BAIL_IF_MACRO(entry == NULL, ERR_NO_SUCH_FILE, NULL);
finfo = (QPAKfileinfo *) allocator.Malloc(sizeof (QPAKfileinfo));
BAIL_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, NULL);
finfo->handle = __PHYSFS_platformOpenRead(info->filename);
if ( (finfo->handle == NULL) ||
(!__PHYSFS_platformSeek(finfo->handle, entry->startPos)) )
{
allocator.Free(finfo);
return(NULL);
} /* if */
finfo->curPos = 0;
finfo->entry = entry;
return(finfo);
} /* QPAK_openRead */
static fvoid *QPAK_openWrite(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* QPAK_openWrite */
static fvoid *QPAK_openAppend(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* QPAK_openAppend */
static int QPAK_remove(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* QPAK_remove */
static int QPAK_mkdir(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* QPAK_mkdir */
const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_QPAK =
{
"PAK",
QPAK_ARCHIVE_DESCRIPTION,
"Ryan C. Gordon <icculus@icculus.org>",
"http://icculus.org/physfs/",
};
const PHYSFS_Archiver __PHYSFS_Archiver_QPAK =
{
&__PHYSFS_ArchiveInfo_QPAK,
QPAK_isArchive, /* isArchive() method */
QPAK_openArchive, /* openArchive() method */
QPAK_enumerateFiles, /* enumerateFiles() method */
QPAK_exists, /* exists() method */
QPAK_isDirectory, /* isDirectory() method */
QPAK_isSymLink, /* isSymLink() method */
QPAK_getLastModTime, /* getLastModTime() method */
QPAK_openRead, /* openRead() method */
QPAK_openWrite, /* openWrite() method */
QPAK_openAppend, /* openAppend() method */
QPAK_remove, /* remove() method */
QPAK_mkdir, /* mkdir() method */
QPAK_dirClose, /* dirClose() method */
QPAK_read, /* read() method */
QPAK_write, /* write() method */
QPAK_eof, /* eof() method */
QPAK_tell, /* tell() method */
QPAK_seek, /* seek() method */
QPAK_fileLength, /* fileLength() method */
QPAK_fileClose /* fileClose() method */
};
#endif /* defined PHYSFS_SUPPORTS_QPAK */
/* end of qpak.c ... */

View File

@@ -0,0 +1,534 @@
/*
* WAD support routines for PhysicsFS.
*
* This driver handles DOOM engine archives ("wads").
* This format (but not this driver) was designed by id Software for use
* with the DOOM engine.
* The specs of the format are from the unofficial doom specs v1.666
* found here: http://www.gamers.org/dhs/helpdocs/dmsp1666.html
* The format of the archive: (from the specs)
*
* A WAD file has three parts:
* (1) a twelve-byte header
* (2) one or more "lumps"
* (3) a directory or "info table" that contains the names, offsets, and
* sizes of all the lumps in the WAD
*
* The header consists of three four-byte parts:
* (a) an ASCII string which must be either "IWAD" or "PWAD"
* (b) a 4-byte (long) integer which is the number of lumps in the wad
* (c) a long integer which is the file offset to the start of
* the directory
*
* The directory has one 16-byte entry for every lump. Each entry consists
* of three parts:
*
* (a) a long integer, the file offset to the start of the lump
* (b) a long integer, the size of the lump in bytes
* (c) an 8-byte ASCII string, the name of the lump, padded with zeros.
* For example, the "DEMO1" entry in hexadecimal would be
* (44 45 4D 4F 31 00 00 00)
*
* Note that there is no way to tell if an opened WAD archive is a
* IWAD or PWAD with this archiver.
* I couldn't think of a way to provide that information, without being too
* hacky.
* I don't think it's really that important though.
*
*
* Please see the file LICENSE.txt in the source's root directory.
*
* This file written by Travis Wells, based on the GRP archiver by
* Ryan C. Gordon.
*/
#if (defined PHYSFS_SUPPORTS_WAD)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "physfs.h"
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
typedef struct
{
char name[18];
PHYSFS_uint32 startPos;
PHYSFS_uint32 size;
} WADentry;
typedef struct
{
char *filename;
PHYSFS_sint64 last_mod_time;
PHYSFS_uint32 entryCount;
PHYSFS_uint32 entryOffset;
WADentry *entries;
} WADinfo;
typedef struct
{
void *handle;
WADentry *entry;
PHYSFS_uint32 curPos;
} WADfileinfo;
static void WAD_dirClose(dvoid *opaque)
{
WADinfo *info = ((WADinfo *) opaque);
allocator.Free(info->filename);
allocator.Free(info->entries);
allocator.Free(info);
} /* WAD_dirClose */
static PHYSFS_sint64 WAD_read(fvoid *opaque, void *buffer,
PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
{
WADfileinfo *finfo = (WADfileinfo *) opaque;
WADentry *entry = finfo->entry;
PHYSFS_uint32 bytesLeft = entry->size - finfo->curPos;
PHYSFS_uint32 objsLeft = (bytesLeft / objSize);
PHYSFS_sint64 rc;
if (objsLeft < objCount)
objCount = objsLeft;
rc = __PHYSFS_platformRead(finfo->handle, buffer, objSize, objCount);
if (rc > 0)
finfo->curPos += (PHYSFS_uint32) (rc * objSize);
return(rc);
} /* WAD_read */
static PHYSFS_sint64 WAD_write(fvoid *opaque, const void *buffer,
PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
} /* WAD_write */
static int WAD_eof(fvoid *opaque)
{
WADfileinfo *finfo = (WADfileinfo *) opaque;
WADentry *entry = finfo->entry;
return(finfo->curPos >= entry->size);
} /* WAD_eof */
static PHYSFS_sint64 WAD_tell(fvoid *opaque)
{
return(((WADfileinfo *) opaque)->curPos);
} /* WAD_tell */
static int WAD_seek(fvoid *opaque, PHYSFS_uint64 offset)
{
WADfileinfo *finfo = (WADfileinfo *) opaque;
WADentry *entry = finfo->entry;
int rc;
BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
rc = __PHYSFS_platformSeek(finfo->handle, entry->startPos + offset);
if (rc)
finfo->curPos = (PHYSFS_uint32) offset;
return(rc);
} /* WAD_seek */
static PHYSFS_sint64 WAD_fileLength(fvoid *opaque)
{
WADfileinfo *finfo = (WADfileinfo *) opaque;
return((PHYSFS_sint64) finfo->entry->size);
} /* WAD_fileLength */
static int WAD_fileClose(fvoid *opaque)
{
WADfileinfo *finfo = (WADfileinfo *) opaque;
BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0);
allocator.Free(finfo);
return(1);
} /* WAD_fileClose */
static int wad_open(const char *filename, int forWriting,
void **fh, PHYSFS_uint32 *count,PHYSFS_uint32 *offset)
{
PHYSFS_uint8 buf[4];
*fh = NULL;
BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
*fh = __PHYSFS_platformOpenRead(filename);
BAIL_IF_MACRO(*fh == NULL, NULL, 0);
if (__PHYSFS_platformRead(*fh, buf, 4, 1) != 1)
goto openWad_failed;
if (memcmp(buf, "IWAD", 4) != 0 && memcmp(buf, "PWAD", 4) != 0)
{
__PHYSFS_setError(ERR_UNSUPPORTED_ARCHIVE);
goto openWad_failed;
} /* if */
if (__PHYSFS_platformRead(*fh, count, sizeof (PHYSFS_uint32), 1) != 1)
goto openWad_failed;
*count = PHYSFS_swapULE32(*count);
if (__PHYSFS_platformRead(*fh, offset, sizeof (PHYSFS_uint32), 1) != 1)
goto openWad_failed;
*offset = PHYSFS_swapULE32(*offset);
return(1);
openWad_failed:
if (*fh != NULL)
__PHYSFS_platformClose(*fh);
*count = -1;
*fh = NULL;
return(0);
} /* wad_open */
static int WAD_isArchive(const char *filename, int forWriting)
{
void *fh;
PHYSFS_uint32 fileCount,offset;
int retval = wad_open(filename, forWriting, &fh, &fileCount,&offset);
if (fh != NULL)
__PHYSFS_platformClose(fh);
return(retval);
} /* WAD_isArchive */
static int wad_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
{
if (one != two)
{
const WADentry *a = (const WADentry *) _a;
return(strcmp(a[one].name, a[two].name));
} /* if */
return 0;
} /* wad_entry_cmp */
static void wad_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
{
if (one != two)
{
WADentry tmp;
WADentry *first = &(((WADentry *) _a)[one]);
WADentry *second = &(((WADentry *) _a)[two]);
memcpy(&tmp, first, sizeof (WADentry));
memcpy(first, second, sizeof (WADentry));
memcpy(second, &tmp, sizeof (WADentry));
} /* if */
} /* wad_entry_swap */
static int wad_load_entries(const char *name, int forWriting, WADinfo *info)
{
void *fh = NULL;
PHYSFS_uint32 fileCount;
PHYSFS_uint32 directoryOffset;
WADentry *entry;
char lastDirectory[9];
lastDirectory[8] = 0; /* Make sure lastDirectory stays null-terminated. */
BAIL_IF_MACRO(!wad_open(name, forWriting, &fh, &fileCount,&directoryOffset), NULL, 0);
info->entryCount = fileCount;
info->entries = (WADentry *) allocator.Malloc(sizeof(WADentry)*fileCount);
if (info->entries == NULL)
{
__PHYSFS_platformClose(fh);
BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
} /* if */
__PHYSFS_platformSeek(fh,directoryOffset);
for (entry = info->entries; fileCount > 0; fileCount--, entry++)
{
if (__PHYSFS_platformRead(fh, &entry->startPos, 4, 1) != 1)
{
__PHYSFS_platformClose(fh);
return(0);
} /* if */
if (__PHYSFS_platformRead(fh, &entry->size, 4, 1) != 1)
{
__PHYSFS_platformClose(fh);
return(0);
} /* if */
if (__PHYSFS_platformRead(fh, &entry->name, 8, 1) != 1)
{
__PHYSFS_platformClose(fh);
return(0);
} /* if */
entry->name[8] = '\0'; /* name might not be null-terminated in file. */
entry->size = PHYSFS_swapULE32(entry->size);
entry->startPos = PHYSFS_swapULE32(entry->startPos);
} /* for */
__PHYSFS_platformClose(fh);
__PHYSFS_sort(info->entries, info->entryCount,
wad_entry_cmp, wad_entry_swap);
return(1);
} /* wad_load_entries */
static void *WAD_openArchive(const char *name, int forWriting)
{
PHYSFS_sint64 modtime = __PHYSFS_platformGetLastModTime(name);
WADinfo *info = (WADinfo *) allocator.Malloc(sizeof (WADinfo));
BAIL_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, NULL);
memset(info, '\0', sizeof (WADinfo));
info->filename = (char *) allocator.Malloc(strlen(name) + 1);
GOTO_IF_MACRO(!info->filename, ERR_OUT_OF_MEMORY, WAD_openArchive_failed);
if (!wad_load_entries(name, forWriting, info))
goto WAD_openArchive_failed;
strcpy(info->filename, name);
info->last_mod_time = modtime;
return(info);
WAD_openArchive_failed:
if (info != NULL)
{
if (info->filename != NULL)
allocator.Free(info->filename);
if (info->entries != NULL)
allocator.Free(info->entries);
allocator.Free(info);
} /* if */
return(NULL);
} /* WAD_openArchive */
static void WAD_enumerateFiles(dvoid *opaque, const char *dname,
int omitSymLinks, PHYSFS_EnumFilesCallback cb,
const char *origdir, void *callbackdata)
{
WADinfo *info = ((WADinfo *) opaque);
WADentry *entry = info->entries;
PHYSFS_uint32 max = info->entryCount;
PHYSFS_uint32 i;
const char *name;
char *sep;
if (*dname == '\0') /* root directory enumeration? */
{
for (i = 0; i < max; i++, entry++)
{
name = entry->name;
if (strchr(name, '/') == NULL)
cb(callbackdata, origdir, name);
} /* for */
} /* if */
else
{
for (i = 0; i < max; i++, entry++)
{
name = entry->name;
sep = strchr(name, '/');
if (sep != NULL)
{
if (strncmp(dname, name, (sep - name)) == 0)
cb(callbackdata, origdir, sep + 1);
} /* if */
} /* for */
} /* else */
} /* WAD_enumerateFiles */
static WADentry *wad_find_entry(WADinfo *info, const char *name)
{
WADentry *a = info->entries;
PHYSFS_sint32 lo = 0;
PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
PHYSFS_sint32 middle;
int rc;
while (lo <= hi)
{
middle = lo + ((hi - lo) / 2);
rc = strcmp(name, a[middle].name);
if (rc == 0) /* found it! */
return(&a[middle]);
else if (rc > 0)
lo = middle + 1;
else
hi = middle - 1;
} /* while */
BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
} /* wad_find_entry */
static int WAD_exists(dvoid *opaque, const char *name)
{
return(wad_find_entry(((WADinfo *) opaque), name) != NULL);
} /* WAD_exists */
static int WAD_isDirectory(dvoid *opaque, const char *name, int *fileExists)
{
WADentry *entry = wad_find_entry(((WADinfo *) opaque), name);
if (entry != NULL)
{
char *n;
*fileExists = 1;
/* Can't be a directory if it's a subdirectory. */
if (strchr(entry->name, '/') != NULL)
return(0);
/* Check if it matches "MAP??" or "E?M?" ... */
n = entry->name;
if ((n[0] == 'E' && n[2] == 'M') ||
(n[0] == 'M' && n[1] == 'A' && n[2] == 'P' && n[6] == 0))
{
return(1);
} /* if */
return(0);
} /* if */
else
{
*fileExists = 0;
return(0);
} /* else */
} /* WAD_isDirectory */
static int WAD_isSymLink(dvoid *opaque, const char *name, int *fileExists)
{
*fileExists = WAD_exists(opaque, name);
return(0); /* never symlinks in a wad. */
} /* WAD_isSymLink */
static PHYSFS_sint64 WAD_getLastModTime(dvoid *opaque,
const char *name,
int *fileExists)
{
WADinfo *info = ((WADinfo *) opaque);
PHYSFS_sint64 retval = -1;
*fileExists = (wad_find_entry(info, name) != NULL);
if (*fileExists) /* use time of WAD itself in the physical filesystem. */
retval = info->last_mod_time;
return(retval);
} /* WAD_getLastModTime */
static fvoid *WAD_openRead(dvoid *opaque, const char *fnm, int *fileExists)
{
WADinfo *info = ((WADinfo *) opaque);
WADfileinfo *finfo;
WADentry *entry;
entry = wad_find_entry(info, fnm);
*fileExists = (entry != NULL);
BAIL_IF_MACRO(entry == NULL, NULL, NULL);
finfo = (WADfileinfo *) allocator.Malloc(sizeof (WADfileinfo));
BAIL_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, NULL);
finfo->handle = __PHYSFS_platformOpenRead(info->filename);
if ( (finfo->handle == NULL) ||
(!__PHYSFS_platformSeek(finfo->handle, entry->startPos)) )
{
allocator.Free(finfo);
return(NULL);
} /* if */
finfo->curPos = 0;
finfo->entry = entry;
return(finfo);
} /* WAD_openRead */
static fvoid *WAD_openWrite(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* WAD_openWrite */
static fvoid *WAD_openAppend(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
} /* WAD_openAppend */
static int WAD_remove(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* WAD_remove */
static int WAD_mkdir(dvoid *opaque, const char *name)
{
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* WAD_mkdir */
const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_WAD =
{
"WAD",
WAD_ARCHIVE_DESCRIPTION,
"Travis Wells <traviswells@mchsi.com>",
"http://www.3dmm2.com/doom/",
};
const PHYSFS_Archiver __PHYSFS_Archiver_WAD =
{
&__PHYSFS_ArchiveInfo_WAD,
WAD_isArchive, /* isArchive() method */
WAD_openArchive, /* openArchive() method */
WAD_enumerateFiles, /* enumerateFiles() method */
WAD_exists, /* exists() method */
WAD_isDirectory, /* isDirectory() method */
WAD_isSymLink, /* isSymLink() method */
WAD_getLastModTime, /* getLastModTime() method */
WAD_openRead, /* openRead() method */
WAD_openWrite, /* openWrite() method */
WAD_openAppend, /* openAppend() method */
WAD_remove, /* remove() method */
WAD_mkdir, /* mkdir() method */
WAD_dirClose, /* dirClose() method */
WAD_read, /* read() method */
WAD_write, /* write() method */
WAD_eof, /* eof() method */
WAD_tell, /* tell() method */
WAD_seek, /* seek() method */
WAD_fileLength, /* fileLength() method */
WAD_fileClose /* fileClose() method */
};
#endif /* defined PHYSFS_SUPPORTS_WAD */
/* end of wad.c ... */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,49 @@
#ifndef _INCL_PHYSFS_PLATFORMS
#define _INCL_PHYSFS_PLATFORMS
#ifndef __PHYSICSFS_INTERNAL__
#error Do not include this header from your applications.
#endif
/*
* These only define the platforms to determine which files in the platforms
* directory should be compiled. For example, technically BeOS can be called
* a "unix" system, but since it doesn't use unix.c, we don't define
* PHYSFS_PLATFORM_UNIX on that system.
*/
#if (defined __HAIKU__)
# define PHYSFS_PLATFORM_HAIKU
# define PHYSFS_PLATFORM_BEOS
# define PHYSFS_PLATFORM_POSIX
#elif ((defined __BEOS__) || (defined __beos__))
# define PHYSFS_PLATFORM_BEOS
# define PHYSFS_PLATFORM_POSIX
#elif (defined _WIN32_WCE) || (defined _WIN64_WCE)
# define PHYSFS_PLATFORM_POCKETPC
#elif (((defined _WIN32) || (defined _WIN64)) && (!defined __CYGWIN__))
# define PHYSFS_PLATFORM_WINDOWS
#elif (defined OS2)
# define PHYSFS_PLATFORM_OS2
#elif ((defined __MACH__) && (defined __APPLE__))
/* To check if iphone or not, we need to include this file */
# include <TargetConditionals.h>
# if ((TARGET_IPHONE_SIMULATOR) || (TARGET_OS_IPHONE))
# define PHYSFS_PLATFORM_UNIX
# define PHYSFS_PLATFORM_POSIX
# define PHYSFS_NO_CDROM_SUPPORT
# else
# define PHYSFS_PLATFORM_MACOSX
# define PHYSFS_PLATFORM_POSIX
# endif
#elif defined(macintosh)
# error Classic Mac OS support was dropped from PhysicsFS 2.0. Move to OS X.
#elif defined(unix)
# define PHYSFS_PLATFORM_UNIX
# define PHYSFS_PLATFORM_POSIX
#else
# error Unknown platform.
#endif
#endif /* include-once blocker. */

2221
project/jni/physfs/physfs.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,312 @@
/**
* PhysicsFS; a portable, flexible file i/o abstraction.
*
* Documentation is in physfs.h. It's verbose, honest. :)
*
* Please see the file LICENSE.txt in the source's root directory.
*
* This file written by Ryan C. Gordon.
*/
#include <stdio.h>
#include <stdlib.h>
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
#if (defined macintosh) && !(defined __MWERKS__)
#define __inline__
#endif
#if (defined _MSC_VER)
#define __inline__ __inline
#endif
#ifndef PHYSFS_Swap16
static __inline__ PHYSFS_uint16 PHYSFS_Swap16(PHYSFS_uint16 D)
{
return((D<<8)|(D>>8));
}
#endif
#ifndef PHYSFS_Swap32
static __inline__ PHYSFS_uint32 PHYSFS_Swap32(PHYSFS_uint32 D)
{
return((D<<24)|((D<<8)&0x00FF0000)|((D>>8)&0x0000FF00)|(D>>24));
}
#endif
#ifndef PHYSFS_NO_64BIT_SUPPORT
#ifndef PHYSFS_Swap64
static __inline__ PHYSFS_uint64 PHYSFS_Swap64(PHYSFS_uint64 val) {
PHYSFS_uint32 hi, lo;
/* Separate into high and low 32-bit values and swap them */
lo = (PHYSFS_uint32)(val&0xFFFFFFFF);
val >>= 32;
hi = (PHYSFS_uint32)(val&0xFFFFFFFF);
val = PHYSFS_Swap32(lo);
val <<= 32;
val |= PHYSFS_Swap32(hi);
return(val);
}
#endif
#else
#ifndef PHYSFS_Swap64
/* This is mainly to keep compilers from complaining in PHYSFS code.
If there is no real 64-bit datatype, then compilers will complain about
the fake 64-bit datatype that PHYSFS provides when it compiles user code.
*/
#define PHYSFS_Swap64(X) (X)
#endif
#endif /* PHYSFS_NO_64BIT_SUPPORT */
/* Byteswap item from the specified endianness to the native endianness */
#if PHYSFS_BYTEORDER == PHYSFS_LIL_ENDIAN
PHYSFS_uint16 PHYSFS_swapULE16(PHYSFS_uint16 x) { return(x); }
PHYSFS_sint16 PHYSFS_swapSLE16(PHYSFS_sint16 x) { return(x); }
PHYSFS_uint32 PHYSFS_swapULE32(PHYSFS_uint32 x) { return(x); }
PHYSFS_sint32 PHYSFS_swapSLE32(PHYSFS_sint32 x) { return(x); }
PHYSFS_uint64 PHYSFS_swapULE64(PHYSFS_uint64 x) { return(x); }
PHYSFS_sint64 PHYSFS_swapSLE64(PHYSFS_sint64 x) { return(x); }
PHYSFS_uint16 PHYSFS_swapUBE16(PHYSFS_uint16 x) { return(PHYSFS_Swap16(x)); }
PHYSFS_sint16 PHYSFS_swapSBE16(PHYSFS_sint16 x) { return(PHYSFS_Swap16(x)); }
PHYSFS_uint32 PHYSFS_swapUBE32(PHYSFS_uint32 x) { return(PHYSFS_Swap32(x)); }
PHYSFS_sint32 PHYSFS_swapSBE32(PHYSFS_sint32 x) { return(PHYSFS_Swap32(x)); }
PHYSFS_uint64 PHYSFS_swapUBE64(PHYSFS_uint64 x) { return(PHYSFS_Swap64(x)); }
PHYSFS_sint64 PHYSFS_swapSBE64(PHYSFS_sint64 x) { return(PHYSFS_Swap64(x)); }
#else
PHYSFS_uint16 PHYSFS_swapULE16(PHYSFS_uint16 x) { return(PHYSFS_Swap16(x)); }
PHYSFS_sint16 PHYSFS_swapSLE16(PHYSFS_sint16 x) { return(PHYSFS_Swap16(x)); }
PHYSFS_uint32 PHYSFS_swapULE32(PHYSFS_uint32 x) { return(PHYSFS_Swap32(x)); }
PHYSFS_sint32 PHYSFS_swapSLE32(PHYSFS_sint32 x) { return(PHYSFS_Swap32(x)); }
PHYSFS_uint64 PHYSFS_swapULE64(PHYSFS_uint64 x) { return(PHYSFS_Swap64(x)); }
PHYSFS_sint64 PHYSFS_swapSLE64(PHYSFS_sint64 x) { return(PHYSFS_Swap64(x)); }
PHYSFS_uint16 PHYSFS_swapUBE16(PHYSFS_uint16 x) { return(x); }
PHYSFS_sint16 PHYSFS_swapSBE16(PHYSFS_sint16 x) { return(x); }
PHYSFS_uint32 PHYSFS_swapUBE32(PHYSFS_uint32 x) { return(x); }
PHYSFS_sint32 PHYSFS_swapSBE32(PHYSFS_sint32 x) { return(x); }
PHYSFS_uint64 PHYSFS_swapUBE64(PHYSFS_uint64 x) { return(x); }
PHYSFS_sint64 PHYSFS_swapSBE64(PHYSFS_sint64 x) { return(x); }
#endif
int PHYSFS_readSLE16(PHYSFS_File *file, PHYSFS_sint16 *val)
{
PHYSFS_sint16 in;
BAIL_IF_MACRO(val == NULL, ERR_INVALID_ARGUMENT, 0);
BAIL_IF_MACRO(PHYSFS_read(file, &in, sizeof (in), 1) != 1, NULL, 0);
*val = PHYSFS_swapSLE16(in);
return(1);
} /* PHYSFS_readSLE16 */
int PHYSFS_readULE16(PHYSFS_File *file, PHYSFS_uint16 *val)
{
PHYSFS_uint16 in;
BAIL_IF_MACRO(val == NULL, ERR_INVALID_ARGUMENT, 0);
BAIL_IF_MACRO(PHYSFS_read(file, &in, sizeof (in), 1) != 1, NULL, 0);
*val = PHYSFS_swapULE16(in);
return(1);
} /* PHYSFS_readULE16 */
int PHYSFS_readSBE16(PHYSFS_File *file, PHYSFS_sint16 *val)
{
PHYSFS_sint16 in;
BAIL_IF_MACRO(val == NULL, ERR_INVALID_ARGUMENT, 0);
BAIL_IF_MACRO(PHYSFS_read(file, &in, sizeof (in), 1) != 1, NULL, 0);
*val = PHYSFS_swapSBE16(in);
return(1);
} /* PHYSFS_readSBE16 */
int PHYSFS_readUBE16(PHYSFS_File *file, PHYSFS_uint16 *val)
{
PHYSFS_uint16 in;
BAIL_IF_MACRO(val == NULL, ERR_INVALID_ARGUMENT, 0);
BAIL_IF_MACRO(PHYSFS_read(file, &in, sizeof (in), 1) != 1, NULL, 0);
*val = PHYSFS_swapUBE16(in);
return(1);
} /* PHYSFS_readUBE16 */
int PHYSFS_readSLE32(PHYSFS_File *file, PHYSFS_sint32 *val)
{
PHYSFS_sint32 in;
BAIL_IF_MACRO(val == NULL, ERR_INVALID_ARGUMENT, 0);
BAIL_IF_MACRO(PHYSFS_read(file, &in, sizeof (in), 1) != 1, NULL, 0);
*val = PHYSFS_swapSLE32(in);
return(1);
} /* PHYSFS_readSLE32 */
int PHYSFS_readULE32(PHYSFS_File *file, PHYSFS_uint32 *val)
{
PHYSFS_uint32 in;
BAIL_IF_MACRO(val == NULL, ERR_INVALID_ARGUMENT, 0);
BAIL_IF_MACRO(PHYSFS_read(file, &in, sizeof (in), 1) != 1, NULL, 0);
*val = PHYSFS_swapULE32(in);
return(1);
} /* PHYSFS_readULE32 */
int PHYSFS_readSBE32(PHYSFS_File *file, PHYSFS_sint32 *val)
{
PHYSFS_sint32 in;
BAIL_IF_MACRO(val == NULL, ERR_INVALID_ARGUMENT, 0);
BAIL_IF_MACRO(PHYSFS_read(file, &in, sizeof (in), 1) != 1, NULL, 0);
*val = PHYSFS_swapSBE32(in);
return(1);
} /* PHYSFS_readSBE32 */
int PHYSFS_readUBE32(PHYSFS_File *file, PHYSFS_uint32 *val)
{
PHYSFS_uint32 in;
BAIL_IF_MACRO(val == NULL, ERR_INVALID_ARGUMENT, 0);
BAIL_IF_MACRO(PHYSFS_read(file, &in, sizeof (in), 1) != 1, NULL, 0);
*val = PHYSFS_swapUBE32(in);
return(1);
} /* PHYSFS_readUBE32 */
int PHYSFS_readSLE64(PHYSFS_File *file, PHYSFS_sint64 *val)
{
PHYSFS_sint64 in;
BAIL_IF_MACRO(val == NULL, ERR_INVALID_ARGUMENT, 0);
BAIL_IF_MACRO(PHYSFS_read(file, &in, sizeof (in), 1) != 1, NULL, 0);
*val = PHYSFS_swapSLE64(in);
return(1);
} /* PHYSFS_readSLE64 */
int PHYSFS_readULE64(PHYSFS_File *file, PHYSFS_uint64 *val)
{
PHYSFS_uint64 in;
BAIL_IF_MACRO(val == NULL, ERR_INVALID_ARGUMENT, 0);
BAIL_IF_MACRO(PHYSFS_read(file, &in, sizeof (in), 1) != 1, NULL, 0);
*val = PHYSFS_swapULE64(in);
return(1);
} /* PHYSFS_readULE64 */
int PHYSFS_readSBE64(PHYSFS_File *file, PHYSFS_sint64 *val)
{
PHYSFS_sint64 in;
BAIL_IF_MACRO(val == NULL, ERR_INVALID_ARGUMENT, 0);
BAIL_IF_MACRO(PHYSFS_read(file, &in, sizeof (in), 1) != 1, NULL, 0);
*val = PHYSFS_swapSBE64(in);
return(1);
} /* PHYSFS_readSBE64 */
int PHYSFS_readUBE64(PHYSFS_File *file, PHYSFS_uint64 *val)
{
PHYSFS_uint64 in;
BAIL_IF_MACRO(val == NULL, ERR_INVALID_ARGUMENT, 0);
BAIL_IF_MACRO(PHYSFS_read(file, &in, sizeof (in), 1) != 1, NULL, 0);
*val = PHYSFS_swapUBE64(in);
return(1);
} /* PHYSFS_readUBE64 */
int PHYSFS_writeSLE16(PHYSFS_File *file, PHYSFS_sint16 val)
{
PHYSFS_sint16 out = PHYSFS_swapSLE16(val);
BAIL_IF_MACRO(PHYSFS_write(file, &out, sizeof (out), 1) != 1, NULL, 0);
return(1);
} /* PHYSFS_writeSLE16 */
int PHYSFS_writeULE16(PHYSFS_File *file, PHYSFS_uint16 val)
{
PHYSFS_uint16 out = PHYSFS_swapULE16(val);
BAIL_IF_MACRO(PHYSFS_write(file, &out, sizeof (out), 1) != 1, NULL, 0);
return(1);
} /* PHYSFS_writeULE16 */
int PHYSFS_writeSBE16(PHYSFS_File *file, PHYSFS_sint16 val)
{
PHYSFS_sint16 out = PHYSFS_swapSBE16(val);
BAIL_IF_MACRO(PHYSFS_write(file, &out, sizeof (out), 1) != 1, NULL, 0);
return(1);
} /* PHYSFS_writeSBE16 */
int PHYSFS_writeUBE16(PHYSFS_File *file, PHYSFS_uint16 val)
{
PHYSFS_uint16 out = PHYSFS_swapUBE16(val);
BAIL_IF_MACRO(PHYSFS_write(file, &out, sizeof (out), 1) != 1, NULL, 0);
return(1);
} /* PHYSFS_writeUBE16 */
int PHYSFS_writeSLE32(PHYSFS_File *file, PHYSFS_sint32 val)
{
PHYSFS_sint32 out = PHYSFS_swapSLE32(val);
BAIL_IF_MACRO(PHYSFS_write(file, &out, sizeof (out), 1) != 1, NULL, 0);
return(1);
} /* PHYSFS_writeSLE32 */
int PHYSFS_writeULE32(PHYSFS_File *file, PHYSFS_uint32 val)
{
PHYSFS_uint32 out = PHYSFS_swapULE32(val);
BAIL_IF_MACRO(PHYSFS_write(file, &out, sizeof (out), 1) != 1, NULL, 0);
return(1);
} /* PHYSFS_writeULE32 */
int PHYSFS_writeSBE32(PHYSFS_File *file, PHYSFS_sint32 val)
{
PHYSFS_sint32 out = PHYSFS_swapSBE32(val);
BAIL_IF_MACRO(PHYSFS_write(file, &out, sizeof (out), 1) != 1, NULL, 0);
return(1);
} /* PHYSFS_writeSBE32 */
int PHYSFS_writeUBE32(PHYSFS_File *file, PHYSFS_uint32 val)
{
PHYSFS_uint32 out = PHYSFS_swapUBE32(val);
BAIL_IF_MACRO(PHYSFS_write(file, &out, sizeof (out), 1) != 1, NULL, 0);
return(1);
} /* PHYSFS_writeUBE32 */
int PHYSFS_writeSLE64(PHYSFS_File *file, PHYSFS_sint64 val)
{
PHYSFS_sint64 out = PHYSFS_swapSLE64(val);
BAIL_IF_MACRO(PHYSFS_write(file, &out, sizeof (out), 1) != 1, NULL, 0);
return(1);
} /* PHYSFS_writeSLE64 */
int PHYSFS_writeULE64(PHYSFS_File *file, PHYSFS_uint64 val)
{
PHYSFS_uint64 out = PHYSFS_swapULE64(val);
BAIL_IF_MACRO(PHYSFS_write(file, &out, sizeof (out), 1) != 1, NULL, 0);
return(1);
} /* PHYSFS_writeULE64 */
int PHYSFS_writeSBE64(PHYSFS_File *file, PHYSFS_sint64 val)
{
PHYSFS_sint64 out = PHYSFS_swapSBE64(val);
BAIL_IF_MACRO(PHYSFS_write(file, &out, sizeof (out), 1) != 1, NULL, 0);
return(1);
} /* PHYSFS_writeSBE64 */
int PHYSFS_writeUBE64(PHYSFS_File *file, PHYSFS_uint64 val)
{
PHYSFS_uint64 out = PHYSFS_swapUBE64(val);
BAIL_IF_MACRO(PHYSFS_write(file, &out, sizeof (out), 1) != 1, NULL, 0);
return(1);
} /* PHYSFS_writeUBE64 */
/* end of physfs_byteorder.c ... */

View File

@@ -0,0 +1,460 @@
#include "physfs.h"
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
/*
* From rfc3629, the UTF-8 spec:
* http://www.ietf.org/rfc/rfc3629.txt
*
* Char. number range | UTF-8 octet sequence
* (hexadecimal) | (binary)
* --------------------+---------------------------------------------
* 0000 0000-0000 007F | 0xxxxxxx
* 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
* 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
* 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
*/
/*
* This may not be the best value, but it's one that isn't represented
* in Unicode (0x10FFFF is the largest codepoint value). We return this
* value from utf8codepoint() if there's bogus bits in the
* stream. utf8codepoint() will turn this value into something
* reasonable (like a question mark), for text that wants to try to recover,
* whereas utf8valid() will use the value to determine if a string has bad
* bits.
*/
#define UNICODE_BOGUS_CHAR_VALUE 0xFFFFFFFF
/*
* This is the codepoint we currently return when there was bogus bits in a
* UTF-8 string. May not fly in Asian locales?
*/
#define UNICODE_BOGUS_CHAR_CODEPOINT '?'
static PHYSFS_uint32 utf8codepoint(const char **_str)
{
const char *str = *_str;
PHYSFS_uint32 retval = 0;
PHYSFS_uint32 octet = (PHYSFS_uint32) ((PHYSFS_uint8) *str);
PHYSFS_uint32 octet2, octet3, octet4;
if (octet == 0) /* null terminator, end of string. */
return 0;
else if (octet < 128) /* one octet char: 0 to 127 */
{
(*_str)++; /* skip to next possible start of codepoint. */
return(octet);
} /* else if */
else if ((octet > 127) && (octet < 192)) /* bad (starts with 10xxxxxx). */
{
/*
* Apparently each of these is supposed to be flagged as a bogus
* char, instead of just resyncing to the next valid codepoint.
*/
(*_str)++; /* skip to next possible start of codepoint. */
return UNICODE_BOGUS_CHAR_VALUE;
} /* else if */
else if (octet < 224) /* two octets */
{
octet -= (128+64);
octet2 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
if ((octet2 & (128+64)) != 128) /* Format isn't 10xxxxxx? */
return UNICODE_BOGUS_CHAR_VALUE;
*_str += 2; /* skip to next possible start of codepoint. */
retval = ((octet << 6) | (octet2 - 128));
if ((retval >= 0x80) && (retval <= 0x7FF))
return retval;
} /* else if */
else if (octet < 240) /* three octets */
{
octet -= (128+64+32);
octet2 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
if ((octet2 & (128+64)) != 128) /* Format isn't 10xxxxxx? */
return UNICODE_BOGUS_CHAR_VALUE;
octet3 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
if ((octet3 & (128+64)) != 128) /* Format isn't 10xxxxxx? */
return UNICODE_BOGUS_CHAR_VALUE;
*_str += 3; /* skip to next possible start of codepoint. */
retval = ( ((octet << 12)) | ((octet2-128) << 6) | ((octet3-128)) );
/* There are seven "UTF-16 surrogates" that are illegal in UTF-8. */
switch (retval)
{
case 0xD800:
case 0xDB7F:
case 0xDB80:
case 0xDBFF:
case 0xDC00:
case 0xDF80:
case 0xDFFF:
return UNICODE_BOGUS_CHAR_VALUE;
} /* switch */
/* 0xFFFE and 0xFFFF are illegal, too, so we check them at the edge. */
if ((retval >= 0x800) && (retval <= 0xFFFD))
return retval;
} /* else if */
else if (octet < 248) /* four octets */
{
octet -= (128+64+32+16);
octet2 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
if ((octet2 & (128+64)) != 128) /* Format isn't 10xxxxxx? */
return UNICODE_BOGUS_CHAR_VALUE;
octet3 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
if ((octet3 & (128+64)) != 128) /* Format isn't 10xxxxxx? */
return UNICODE_BOGUS_CHAR_VALUE;
octet4 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
if ((octet4 & (128+64)) != 128) /* Format isn't 10xxxxxx? */
return UNICODE_BOGUS_CHAR_VALUE;
*_str += 4; /* skip to next possible start of codepoint. */
retval = ( ((octet << 18)) | ((octet2 - 128) << 12) |
((octet3 - 128) << 6) | ((octet4 - 128)) );
if ((retval >= 0x10000) && (retval <= 0x10FFFF))
return retval;
} /* else if */
/*
* Five and six octet sequences became illegal in rfc3629.
* We throw the codepoint away, but parse them to make sure we move
* ahead the right number of bytes and don't overflow the buffer.
*/
else if (octet < 252) /* five octets */
{
octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */
return UNICODE_BOGUS_CHAR_VALUE;
octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */
return UNICODE_BOGUS_CHAR_VALUE;
octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */
return UNICODE_BOGUS_CHAR_VALUE;
octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */
return UNICODE_BOGUS_CHAR_VALUE;
*_str += 5; /* skip to next possible start of codepoint. */
return UNICODE_BOGUS_CHAR_VALUE;
} /* else if */
else /* six octets */
{
octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */
return UNICODE_BOGUS_CHAR_VALUE;
octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */
return UNICODE_BOGUS_CHAR_VALUE;
octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */
return UNICODE_BOGUS_CHAR_VALUE;
octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */
return UNICODE_BOGUS_CHAR_VALUE;
octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */
return UNICODE_BOGUS_CHAR_VALUE;
*_str += 6; /* skip to next possible start of codepoint. */
return UNICODE_BOGUS_CHAR_VALUE;
} /* else if */
return UNICODE_BOGUS_CHAR_VALUE;
} /* utf8codepoint */
void PHYSFS_utf8ToUcs4(const char *src, PHYSFS_uint32 *dst, PHYSFS_uint64 len)
{
len -= sizeof (PHYSFS_uint32); /* save room for null char. */
while (len >= sizeof (PHYSFS_uint32))
{
PHYSFS_uint32 cp = utf8codepoint(&src);
if (cp == 0)
break;
else if (cp == UNICODE_BOGUS_CHAR_VALUE)
cp = UNICODE_BOGUS_CHAR_CODEPOINT;
*(dst++) = cp;
len -= sizeof (PHYSFS_uint32);
} /* while */
*dst = 0;
} /* PHYSFS_utf8ToUcs4 */
void PHYSFS_utf8ToUcs2(const char *src, PHYSFS_uint16 *dst, PHYSFS_uint64 len)
{
len -= sizeof (PHYSFS_uint16); /* save room for null char. */
while (len >= sizeof (PHYSFS_uint16))
{
PHYSFS_uint32 cp = utf8codepoint(&src);
if (cp == 0)
break;
else if (cp == UNICODE_BOGUS_CHAR_VALUE)
cp = UNICODE_BOGUS_CHAR_CODEPOINT;
/* !!! BLUESKY: UTF-16 surrogates? */
if (cp > 0xFFFF)
cp = UNICODE_BOGUS_CHAR_CODEPOINT;
*(dst++) = cp;
len -= sizeof (PHYSFS_uint16);
} /* while */
*dst = 0;
} /* PHYSFS_utf8ToUcs2 */
static void utf8fromcodepoint(PHYSFS_uint32 cp, char **_dst, PHYSFS_uint64 *_len)
{
char *dst = *_dst;
PHYSFS_uint64 len = *_len;
if (len == 0)
return;
if (cp > 0x10FFFF)
cp = UNICODE_BOGUS_CHAR_CODEPOINT;
else if ((cp == 0xFFFE) || (cp == 0xFFFF)) /* illegal values. */
cp = UNICODE_BOGUS_CHAR_CODEPOINT;
else
{
/* There are seven "UTF-16 surrogates" that are illegal in UTF-8. */
switch (cp)
{
case 0xD800:
case 0xDB7F:
case 0xDB80:
case 0xDBFF:
case 0xDC00:
case 0xDF80:
case 0xDFFF:
cp = UNICODE_BOGUS_CHAR_CODEPOINT;
} /* switch */
} /* else */
/* Do the encoding... */
if (cp < 0x80)
{
*(dst++) = (char) cp;
len--;
} /* if */
else if (cp < 0x800)
{
if (len < 2)
len = 0;
else
{
*(dst++) = (char) ((cp >> 6) | 128 | 64);
*(dst++) = (char) (cp & 0x3F) | 128;
len -= 2;
} /* else */
} /* else if */
else if (cp < 0x10000)
{
if (len < 3)
len = 0;
else
{
*(dst++) = (char) ((cp >> 12) | 128 | 64 | 32);
*(dst++) = (char) ((cp >> 6) & 0x3F) | 128;
*(dst++) = (char) (cp & 0x3F) | 128;
len -= 3;
} /* else */
} /* else if */
else
{
if (len < 4)
len = 0;
else
{
*(dst++) = (char) ((cp >> 18) | 128 | 64 | 32 | 16);
*(dst++) = (char) ((cp >> 12) & 0x3F) | 128;
*(dst++) = (char) ((cp >> 6) & 0x3F) | 128;
*(dst++) = (char) (cp & 0x3F) | 128;
len -= 4;
} /* else if */
} /* else */
*_dst = dst;
*_len = len;
} /* utf8fromcodepoint */
#define UTF8FROMTYPE(typ, src, dst, len) \
if (len == 0) return; \
len--; \
while (len) \
{ \
const PHYSFS_uint32 cp = (PHYSFS_uint32) ((typ) (*(src++))); \
if (cp == 0) break; \
utf8fromcodepoint(cp, &dst, &len); \
} \
*dst = '\0'; \
void PHYSFS_utf8FromUcs4(const PHYSFS_uint32 *src, char *dst, PHYSFS_uint64 len)
{
UTF8FROMTYPE(PHYSFS_uint32, src, dst, len);
} /* PHYSFS_utf8FromUcs4 */
void PHYSFS_utf8FromUcs2(const PHYSFS_uint16 *src, char *dst, PHYSFS_uint64 len)
{
UTF8FROMTYPE(PHYSFS_uint64, src, dst, len);
} /* PHYSFS_utf8FromUcs4 */
/* latin1 maps to unicode codepoints directly, we just utf-8 encode it. */
void PHYSFS_utf8FromLatin1(const char *src, char *dst, PHYSFS_uint64 len)
{
UTF8FROMTYPE(PHYSFS_uint8, src, dst, len);
} /* PHYSFS_utf8FromLatin1 */
#undef UTF8FROMTYPE
typedef struct CaseFoldMapping
{
PHYSFS_uint32 from;
PHYSFS_uint32 to0;
PHYSFS_uint32 to1;
PHYSFS_uint32 to2;
} CaseFoldMapping;
typedef struct CaseFoldHashBucket
{
const PHYSFS_uint8 count;
const CaseFoldMapping *list;
} CaseFoldHashBucket;
#include "physfs_casefolding.h"
static void locate_case_fold_mapping(const PHYSFS_uint32 from,
PHYSFS_uint32 *to)
{
PHYSFS_uint32 i;
const PHYSFS_uint8 hashed = ((from ^ (from >> 8)) & 0xFF);
const CaseFoldHashBucket *bucket = &case_fold_hash[hashed];
const CaseFoldMapping *mapping = bucket->list;
for (i = 0; i < bucket->count; i++, mapping++)
{
if (mapping->from == from)
{
to[0] = mapping->to0;
to[1] = mapping->to1;
to[2] = mapping->to2;
return;
} /* if */
} /* for */
/* Not found...there's no remapping for this codepoint. */
to[0] = from;
to[1] = 0;
to[2] = 0;
} /* locate_case_fold_mapping */
static int utf8codepointcmp(const PHYSFS_uint32 cp1, const PHYSFS_uint32 cp2)
{
PHYSFS_uint32 folded1[3], folded2[3];
locate_case_fold_mapping(cp1, folded1);
locate_case_fold_mapping(cp2, folded2);
return ( (folded1[0] == folded2[0]) &&
(folded1[1] == folded2[1]) &&
(folded1[2] == folded2[2]) );
} /* utf8codepointcmp */
int __PHYSFS_utf8strcasecmp(const char *str1, const char *str2)
{
while (1)
{
const PHYSFS_uint32 cp1 = utf8codepoint(&str1);
const PHYSFS_uint32 cp2 = utf8codepoint(&str2);
if (!utf8codepointcmp(cp1, cp2)) return 0;
if (cp1 == 0) return 1;
} /* while */
return 0; /* shouldn't hit this. */
} /* __PHYSFS_utf8strcasecmp */
int __PHYSFS_utf8strnicmp(const char *str1, const char *str2, PHYSFS_uint32 n)
{
while (n > 0)
{
const PHYSFS_uint32 cp1 = utf8codepoint(&str1);
const PHYSFS_uint32 cp2 = utf8codepoint(&str2);
if (!utf8codepointcmp(cp1, cp2)) return 0;
if (cp1 == 0) return 1;
n--;
} /* while */
return 1; /* matched to n chars. */
} /* __PHYSFS_utf8strnicmp */
int __PHYSFS_stricmpASCII(const char *str1, const char *str2)
{
while (1)
{
const char ch1 = *(str1++);
const char ch2 = *(str2++);
const char cp1 = ((ch1 >= 'A') && (ch1 <= 'Z')) ? (ch1+32) : ch1;
const char cp2 = ((ch2 >= 'A') && (ch2 <= 'Z')) ? (ch2+32) : ch2;
if (cp1 < cp2)
return -1;
else if (cp1 > cp2)
return 1;
else if (cp1 == 0) /* they're both null chars? */
return 0;
} /* while */
return 0; /* shouldn't hit this. */
} /* __PHYSFS_stricmpASCII */
int __PHYSFS_strnicmpASCII(const char *str1, const char *str2, PHYSFS_uint32 n)
{
while (n-- > 0)
{
const char ch1 = *(str1++);
const char ch2 = *(str2++);
const char cp1 = ((ch1 >= 'A') && (ch1 <= 'Z')) ? (ch1+32) : ch1;
const char cp2 = ((ch2 >= 'A') && (ch2 <= 'Z')) ? (ch2+32) : ch2;
if (cp1 < cp2)
return -1;
else if (cp1 > cp2)
return 1;
else if (cp1 == 0) /* they're both null chars? */
return 0;
} /* while */
return 0;
} /* __PHYSFS_stricmpASCII */
/* end of physfs_unicode.c ... */

View File

@@ -0,0 +1,256 @@
/*
* BeOS platform-dependent 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_platforms.h"
#ifdef PHYSFS_PLATFORM_BEOS
#ifdef PHYSFS_PLATFORM_HAIKU
#include <os/kernel/OS.h>
#include <os/app/Roster.h>
#include <os/storage/Volume.h>
#include <os/storage/VolumeRoster.h>
#include <os/storage/Directory.h>
#include <os/storage/Entry.h>
#include <os/storage/Path.h>
#include <os/kernel/fs_info.h>
#include <os/device/scsi.h>
#include <os/support/Locker.h>
#else
#include <be/kernel/OS.h>
#include <be/app/Roster.h>
#include <be/storage/Volume.h>
#include <be/storage/VolumeRoster.h>
#include <be/storage/Directory.h>
#include <be/storage/Entry.h>
#include <be/storage/Path.h>
#include <be/kernel/fs_info.h>
#include <be/device/scsi.h>
#include <be/support/Locker.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "physfs_internal.h"
int __PHYSFS_platformInit(void)
{
return(1); /* always succeed. */
} /* __PHYSFS_platformInit */
int __PHYSFS_platformDeinit(void)
{
return(1); /* always succeed. */
} /* __PHYSFS_platformDeinit */
static char *getMountPoint(const char *devname)
{
BVolumeRoster mounts;
BVolume vol;
mounts.Rewind();
while (mounts.GetNextVolume(&vol) == B_NO_ERROR)
{
fs_info fsinfo;
fs_stat_dev(vol.Device(), &fsinfo);
if (strcmp(devname, fsinfo.device_name) == 0)
{
//char buf[B_FILE_NAME_LENGTH];
BDirectory directory;
BEntry entry;
BPath path;
status_t rc;
rc = vol.GetRootDirectory(&directory);
BAIL_IF_MACRO(rc < B_OK, strerror(rc), NULL);
rc = directory.GetEntry(&entry);
BAIL_IF_MACRO(rc < B_OK, strerror(rc), NULL);
rc = entry.GetPath(&path);
BAIL_IF_MACRO(rc < B_OK, strerror(rc), NULL);
const char *str = path.Path();
BAIL_IF_MACRO(str == NULL, ERR_OS_ERROR, NULL); /* ?! */
char *retval = (char *) allocator.Malloc(strlen(str) + 1);
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
strcpy(retval, str);
return(retval);
} /* if */
} /* while */
return(NULL);
} /* getMountPoint */
/*
* This function is lifted from Simple Directmedia Layer (SDL):
* http://www.libsdl.org/
*/
static void tryDir(const char *d, PHYSFS_StringCallback callback, void *data)
{
BDirectory dir;
dir.SetTo(d);
if (dir.InitCheck() != B_NO_ERROR)
return;
dir.Rewind();
BEntry entry;
while (dir.GetNextEntry(&entry) >= 0)
{
BPath path;
const char *name;
entry_ref e;
if (entry.GetPath(&path) != B_NO_ERROR)
continue;
name = path.Path();
if (entry.GetRef(&e) != B_NO_ERROR)
continue;
if (entry.IsDirectory())
{
if (strcmp(e.name, "floppy") != 0)
tryDir(name, callback, data);
} /* if */
else
{
bool add_it = false;
int devfd;
device_geometry g;
if (strcmp(e.name, "raw") == 0) /* ignore partitions. */
{
int devfd = open(name, O_RDONLY);
if (devfd >= 0)
{
if (ioctl(devfd, B_GET_GEOMETRY, &g, sizeof(g)) >= 0)
{
if (g.device_type == B_CD)
{
char *mntpnt = getMountPoint(name);
if (mntpnt != NULL)
{
callback(data, mntpnt);
allocator.Free(mntpnt); /* !!! FIXME: lose this malloc! */
} /* if */
} /* if */
} /* if */
} /* if */
} /* if */
close(devfd);
} /* else */
} /* while */
} /* tryDir */
void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
{
tryDir("/dev/disk", cb, data);
} /* __PHYSFS_platformDetectAvailableCDs */
static team_id getTeamID(void)
{
thread_info info;
thread_id tid = find_thread(NULL);
get_thread_info(tid, &info);
return(info.team);
} /* getTeamID */
char *__PHYSFS_platformCalcBaseDir(const char *argv0)
{
image_info info;
int32 cookie = 0;
while (get_next_image_info(0, &cookie, &info) == B_OK) {
if (info.type == B_APP_IMAGE)
break;
}
BEntry entry(info.name, true);
BPath path;
status_t rc = entry.GetPath(&path); /* (path) now has binary's path. */
assert(rc == B_OK);
rc = path.GetParent(&path); /* chop filename, keep directory. */
assert(rc == B_OK);
const char *str = path.Path();
assert(str != NULL);
char *retval = (char *) allocator.Malloc(strlen(str) + 1);
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
strcpy(retval, str);
return(retval);
} /* __PHYSFS_platformCalcBaseDir */
PHYSFS_uint64 __PHYSFS_platformGetThreadID(void)
{
return((PHYSFS_uint64) find_thread(NULL));
} /* __PHYSFS_platformGetThreadID */
char *__PHYSFS_platformRealPath(const char *path)
{
BPath normalized(path, NULL, true); /* force normalization of path. */
const char *resolved_path = normalized.Path();
BAIL_IF_MACRO(resolved_path == NULL, ERR_NO_SUCH_FILE, NULL);
char *retval = (char *) allocator.Malloc(strlen(resolved_path) + 1);
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
strcpy(retval, resolved_path);
return(retval);
} /* __PHYSFS_platformRealPath */
char *__PHYSFS_platformCurrentDir(void)
{
return(__PHYSFS_platformRealPath(".")); /* let BPath sort it out. */
} /* __PHYSFS_platformCurrentDir */
void *__PHYSFS_platformCreateMutex(void)
{
return(new BLocker("PhysicsFS lock", true));
} /* __PHYSFS_platformCreateMutex */
void __PHYSFS_platformDestroyMutex(void *mutex)
{
delete ((BLocker *) mutex);
} /* __PHYSFS_platformDestroyMutex */
int __PHYSFS_platformGrabMutex(void *mutex)
{
return ((BLocker *) mutex)->Lock() ? 1 : 0;
} /* __PHYSFS_platformGrabMutex */
void __PHYSFS_platformReleaseMutex(void *mutex)
{
((BLocker *) mutex)->Unlock();
} /* __PHYSFS_platformReleaseMutex */
int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
{
return(0); /* just use malloc() and friends. */
} /* __PHYSFS_platformSetDefaultAllocator */
#endif /* PHYSFS_PLATFORM_BEOS */
/* end of beos.cpp ... */

View File

@@ -0,0 +1,396 @@
/*
* Mac OS X 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_platforms.h"
#ifdef PHYSFS_PLATFORM_MACOSX
#include <Carbon/Carbon.h>
#include <IOKit/storage/IOMedia.h>
#include <IOKit/storage/IOCDMedia.h>
#include <IOKit/storage/IODVDMedia.h>
#include <sys/mount.h>
/* Seems to get defined in some system header... */
#ifdef Free
#undef Free
#endif
#include "physfs_internal.h"
/* Wrap PHYSFS_Allocator in a CFAllocator... */
static CFAllocatorRef cfallocator = NULL;
CFStringRef cfallocDesc(const void *info)
{
return(CFStringCreateWithCString(cfallocator, "PhysicsFS",
kCFStringEncodingASCII));
} /* cfallocDesc */
static void *cfallocMalloc(CFIndex allocSize, CFOptionFlags hint, void *info)
{
return allocator.Malloc(allocSize);
} /* cfallocMalloc */
static void cfallocFree(void *ptr, void *info)
{
allocator.Free(ptr);
} /* cfallocFree */
static void *cfallocRealloc(void *ptr, CFIndex newsize,
CFOptionFlags hint, void *info)
{
if ((ptr == NULL) || (newsize <= 0))
return NULL; /* ADC docs say you should always return NULL here. */
return allocator.Realloc(ptr, newsize);
} /* cfallocRealloc */
int __PHYSFS_platformInit(void)
{
/* set up a CFAllocator, so Carbon can use the physfs allocator, too. */
CFAllocatorContext ctx;
memset(&ctx, '\0', sizeof (ctx));
ctx.copyDescription = cfallocDesc;
ctx.allocate = cfallocMalloc;
ctx.reallocate = cfallocRealloc;
ctx.deallocate = cfallocFree;
cfallocator = CFAllocatorCreate(kCFAllocatorUseContext, &ctx);
BAIL_IF_MACRO(cfallocator == NULL, ERR_OUT_OF_MEMORY, 0);
return(1); /* success. */
} /* __PHYSFS_platformInit */
int __PHYSFS_platformDeinit(void)
{
CFRelease(cfallocator);
cfallocator = NULL;
return(1); /* always succeed. */
} /* __PHYSFS_platformDeinit */
/* CD-ROM detection code... */
/*
* Code based on sample from Apple Developer Connection:
* http://developer.apple.com/samplecode/Sample_Code/Devices_and_Hardware/Disks/VolumeToBSDNode/VolumeToBSDNode.c.htm
*/
static int darwinIsWholeMedia(io_service_t service)
{
int retval = 0;
CFTypeRef wholeMedia;
if (!IOObjectConformsTo(service, kIOMediaClass))
return(0);
wholeMedia = IORegistryEntryCreateCFProperty(service,
CFSTR(kIOMediaWholeKey),
cfallocator, 0);
if (wholeMedia == NULL)
return(0);
retval = CFBooleanGetValue(wholeMedia);
CFRelease(wholeMedia);
return retval;
} /* darwinIsWholeMedia */
static int darwinIsMountedDisc(char *bsdName, mach_port_t masterPort)
{
int retval = 0;
CFMutableDictionaryRef matchingDict;
kern_return_t rc;
io_iterator_t iter;
io_service_t service;
if ((matchingDict = IOBSDNameMatching(masterPort, 0, bsdName)) == NULL)
return(0);
rc = IOServiceGetMatchingServices(masterPort, matchingDict, &iter);
if ((rc != KERN_SUCCESS) || (!iter))
return(0);
service = IOIteratorNext(iter);
IOObjectRelease(iter);
if (!service)
return(0);
rc = IORegistryEntryCreateIterator(service, kIOServicePlane,
kIORegistryIterateRecursively | kIORegistryIterateParents, &iter);
if (!iter)
return(0);
if (rc != KERN_SUCCESS)
{
IOObjectRelease(iter);
return(0);
} /* if */
IOObjectRetain(service); /* add an extra object reference... */
do
{
if (darwinIsWholeMedia(service))
{
if ( (IOObjectConformsTo(service, kIOCDMediaClass)) ||
(IOObjectConformsTo(service, kIODVDMediaClass)) )
{
retval = 1;
} /* if */
} /* if */
IOObjectRelease(service);
} while ((service = IOIteratorNext(iter)) && (!retval));
IOObjectRelease(iter);
IOObjectRelease(service);
return(retval);
} /* darwinIsMountedDisc */
void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
{
const char *devPrefix = "/dev/";
const int prefixLen = strlen(devPrefix);
mach_port_t masterPort = 0;
struct statfs *mntbufp;
int i, mounts;
if (IOMasterPort(MACH_PORT_NULL, &masterPort) != KERN_SUCCESS)
BAIL_MACRO(ERR_OS_ERROR, ) /*return void*/;
mounts = getmntinfo(&mntbufp, MNT_WAIT); /* NOT THREAD SAFE! */
for (i = 0; i < mounts; i++)
{
char *dev = mntbufp[i].f_mntfromname;
char *mnt = mntbufp[i].f_mntonname;
if (strncmp(dev, devPrefix, prefixLen) != 0) /* a virtual device? */
continue;
dev += prefixLen;
if (darwinIsMountedDisc(dev, masterPort))
cb(data, mnt);
} /* for */
} /* __PHYSFS_platformDetectAvailableCDs */
static char *convertCFString(CFStringRef cfstr)
{
CFIndex len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr),
kCFStringEncodingUTF8) + 1;
char *retval = (char *) allocator.Malloc(len);
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
if (CFStringGetCString(cfstr, retval, len, kCFStringEncodingUTF8))
{
/* shrink overallocated buffer if possible... */
CFIndex newlen = strlen(retval) + 1;
if (newlen < len)
{
void *ptr = allocator.Realloc(retval, newlen);
if (ptr != NULL)
retval = (char *) ptr;
} /* if */
} /* if */
else /* probably shouldn't fail, but just in case... */
{
allocator.Free(retval);
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
} /* else */
return(retval);
} /* convertCFString */
char *__PHYSFS_platformCalcBaseDir(const char *argv0)
{
ProcessSerialNumber psn = { 0, kCurrentProcess };
FSRef fsref;
CFRange cfrange;
CFURLRef cfurl = NULL;
CFStringRef cfstr = NULL;
CFMutableStringRef cfmutstr = NULL;
char *retval = NULL;
BAIL_IF_MACRO(GetProcessBundleLocation(&psn, &fsref) != noErr, NULL, NULL);
cfurl = CFURLCreateFromFSRef(cfallocator, &fsref);
BAIL_IF_MACRO(cfurl == NULL, NULL, NULL);
cfstr = CFURLCopyFileSystemPath(cfurl, kCFURLPOSIXPathStyle);
CFRelease(cfurl);
BAIL_IF_MACRO(cfstr == NULL, NULL, NULL);
cfmutstr = CFStringCreateMutableCopy(cfallocator, 0, cfstr);
CFRelease(cfstr);
BAIL_IF_MACRO(cfmutstr == NULL, NULL, NULL);
/* Find last dirsep so we can chop the binary's filename from the path. */
cfrange = CFStringFind(cfmutstr, CFSTR("/"), kCFCompareBackwards);
if (cfrange.location == kCFNotFound)
{
assert(0); /* shouldn't ever hit this... */
CFRelease(cfmutstr);
return(NULL);
} /* if */
/* chop the "/exename" from the end of the path string... */
cfrange.length = CFStringGetLength(cfmutstr) - cfrange.location;
CFStringDelete(cfmutstr, cfrange);
/* If we're an Application Bundle, chop everything but the base. */
cfrange = CFStringFind(cfmutstr, CFSTR("/Contents/MacOS"),
kCFCompareCaseInsensitive |
kCFCompareBackwards |
kCFCompareAnchored);
if (cfrange.location != kCFNotFound)
CFStringDelete(cfmutstr, cfrange); /* chop that, too. */
retval = convertCFString(cfmutstr);
CFRelease(cfmutstr);
return(retval); /* whew. */
} /* __PHYSFS_platformCalcBaseDir */
/* !!! FIXME */
#define osxerr(x) x
char *__PHYSFS_platformRealPath(const char *path)
{
/* The symlink and relative path resolving happens in FSPathMakeRef() */
FSRef fsref;
CFURLRef cfurl = NULL;
CFStringRef cfstr = NULL;
char *retval = NULL;
OSStatus rc = osxerr(FSPathMakeRef((UInt8 *) path, &fsref, NULL));
BAIL_IF_MACRO(rc != noErr, NULL, NULL);
/* Now get it to spit out a full path. */
cfurl = CFURLCreateFromFSRef(cfallocator, &fsref);
BAIL_IF_MACRO(cfurl == NULL, ERR_OUT_OF_MEMORY, NULL);
cfstr = CFURLCopyFileSystemPath(cfurl, kCFURLPOSIXPathStyle);
CFRelease(cfurl);
BAIL_IF_MACRO(cfstr == NULL, ERR_OUT_OF_MEMORY, NULL);
retval = convertCFString(cfstr);
CFRelease(cfstr);
return(retval);
} /* __PHYSFS_platformRealPath */
char *__PHYSFS_platformCurrentDir(void)
{
return(__PHYSFS_platformRealPath(".")); /* let CFURL sort it out. */
} /* __PHYSFS_platformCurrentDir */
/* Platform allocator uses default CFAllocator at PHYSFS_init() time. */
static CFAllocatorRef cfallocdef = NULL;
static int macosxAllocatorInit(void)
{
int retval = 0;
cfallocdef = CFAllocatorGetDefault();
retval = (cfallocdef != NULL);
if (retval)
CFRetain(cfallocdef);
return(retval);
} /* macosxAllocatorInit */
static void macosxAllocatorDeinit(void)
{
if (cfallocdef != NULL)
{
CFRelease(cfallocdef);
cfallocdef = NULL;
} /* if */
} /* macosxAllocatorDeinit */
static void *macosxAllocatorMalloc(PHYSFS_uint64 s)
{
BAIL_IF_MACRO(__PHYSFS_ui64FitsAddressSpace(s), ERR_OUT_OF_MEMORY, NULL);
return(CFAllocatorAllocate(cfallocdef, (CFIndex) s, 0));
} /* macosxAllocatorMalloc */
static void *macosxAllocatorRealloc(void *ptr, PHYSFS_uint64 s)
{
BAIL_IF_MACRO(__PHYSFS_ui64FitsAddressSpace(s), ERR_OUT_OF_MEMORY, NULL);
return(CFAllocatorReallocate(cfallocdef, ptr, (CFIndex) s, 0));
} /* macosxAllocatorRealloc */
static void macosxAllocatorFree(void *ptr)
{
CFAllocatorDeallocate(cfallocdef, ptr);
} /* macosxAllocatorFree */
int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
{
allocator.Init = macosxAllocatorInit;
allocator.Deinit = macosxAllocatorDeinit;
allocator.Malloc = macosxAllocatorMalloc;
allocator.Realloc = macosxAllocatorRealloc;
allocator.Free = macosxAllocatorFree;
return(1); /* return non-zero: we're supplying custom allocator. */
} /* __PHYSFS_platformSetDefaultAllocator */
PHYSFS_uint64 __PHYSFS_platformGetThreadID(void)
{
return( (PHYSFS_uint64) ((size_t) MPCurrentTaskID()) );
} /* __PHYSFS_platformGetThreadID */
void *__PHYSFS_platformCreateMutex(void)
{
MPCriticalRegionID m = NULL;
if (osxerr(MPCreateCriticalRegion(&m)) != noErr)
return NULL;
return m;
} /* __PHYSFS_platformCreateMutex */
void __PHYSFS_platformDestroyMutex(void *mutex)
{
MPCriticalRegionID m = (MPCriticalRegionID) mutex;
MPDeleteCriticalRegion(m);
} /* __PHYSFS_platformDestroyMutex */
int __PHYSFS_platformGrabMutex(void *mutex)
{
MPCriticalRegionID m = (MPCriticalRegionID) mutex;
if (MPEnterCriticalRegion(m, kDurationForever) != noErr)
return(0);
return(1);
} /* __PHYSFS_platformGrabMutex */
void __PHYSFS_platformReleaseMutex(void *mutex)
{
MPCriticalRegionID m = (MPCriticalRegionID) mutex;
MPExitCriticalRegion(m);
} /* __PHYSFS_platformReleaseMutex */
#endif /* PHYSFS_PLATFORM_MACOSX */
/* end of macosx.c ... */

View File

@@ -0,0 +1,702 @@
/*
* OS/2 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_platforms.h"
#ifdef PHYSFS_PLATFORM_OS2
#define INCL_DOSSEMAPHORES
#define INCL_DOSDATETIME
#define INCL_DOSFILEMGR
#define INCL_DOSMODULEMGR
#define INCL_DOSERRORS
#define INCL_DOSPROCESS
#define INCL_DOSDEVICES
#define INCL_DOSDEVIOCTL
#define INCL_DOSMISC
#include <os2.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include "physfs_internal.h"
const char *__PHYSFS_platformDirSeparator = "\\";
static const char *get_os2_error_string(APIRET rc)
{
switch (rc)
{
case NO_ERROR: return(NULL); /* not an error. */
case ERROR_INTERRUPT: return(NULL); /* not an error. */
case ERROR_TIMEOUT: return(NULL); /* not an error. */
case ERROR_NOT_ENOUGH_MEMORY: return(ERR_OUT_OF_MEMORY);
case ERROR_FILE_NOT_FOUND: return(ERR_NO_SUCH_FILE);
case ERROR_PATH_NOT_FOUND: return(ERR_NO_SUCH_PATH);
case ERROR_ACCESS_DENIED: return(ERR_ACCESS_DENIED);
case ERROR_NOT_DOS_DISK: return(ERR_NOT_A_DOS_DISK);
case ERROR_SHARING_VIOLATION: return(ERR_SHARING_VIOLATION);
case ERROR_CANNOT_MAKE: return(ERR_CANNOT_MAKE);
case ERROR_DEVICE_IN_USE: return(ERR_DEV_IN_USE);
case ERROR_OPEN_FAILED: return(ERR_OPEN_FAILED);
case ERROR_DISK_FULL: return(ERR_DISK_FULL);
case ERROR_PIPE_BUSY: return(ERR_PIPE_BUSY);
case ERROR_SHARING_BUFFER_EXCEEDED: return(ERR_SHARING_BUF_EXCEEDED);
case ERROR_FILENAME_EXCED_RANGE: return(ERR_BAD_FILENAME);
case ERROR_META_EXPANSION_TOO_LONG: return(ERR_BAD_FILENAME);
case ERROR_TOO_MANY_HANDLES: return(ERR_TOO_MANY_HANDLES);
case ERROR_TOO_MANY_OPEN_FILES: return(ERR_TOO_MANY_HANDLES);
case ERROR_NO_MORE_SEARCH_HANDLES: return(ERR_TOO_MANY_HANDLES);
case ERROR_SEEK_ON_DEVICE: return(ERR_SEEK_ERROR);
case ERROR_NEGATIVE_SEEK: return(ERR_SEEK_OUT_OF_RANGE);
/*!!! FIXME: Where did this go? case ERROR_DEL_CURRENT_DIRECTORY: return(ERR_DEL_CWD);*/
case ERROR_WRITE_PROTECT: return(ERR_WRITE_PROTECT_ERROR);
case ERROR_WRITE_FAULT: return(ERR_WRITE_FAULT);
case ERROR_LOCK_VIOLATION: return(ERR_LOCK_VIOLATION);
case ERROR_GEN_FAILURE: return(ERR_GEN_FAILURE);
case ERROR_UNCERTAIN_MEDIA: return(ERR_UNCERTAIN_MEDIA);
case ERROR_PROTECTION_VIOLATION: return(ERR_PROT_VIOLATION);
case ERROR_BROKEN_PIPE: return(ERR_BROKEN_PIPE);
case ERROR_INVALID_PARAMETER:
case ERROR_INVALID_NAME:
case ERROR_INVALID_DRIVE:
case ERROR_INVALID_HANDLE:
case ERROR_INVALID_FUNCTION:
case ERROR_INVALID_LEVEL:
case ERROR_INVALID_CATEGORY:
case ERROR_DUPLICATE_NAME:
case ERROR_BUFFER_OVERFLOW:
case ERROR_BAD_LENGTH:
case ERROR_BAD_DRIVER_LEVEL:
case ERROR_DIRECT_ACCESS_HANDLE:
case ERROR_NOT_OWNER:
return(ERR_PHYSFS_BAD_OS_CALL);
default: return(ERR_OS2_GENERIC);
} /* switch */
return(NULL);
} /* get_os2_error_string */
static APIRET os2err(APIRET retval)
{
char buf[128];
const char *err = get_os2_error_string(retval);
if (err == ERR_OS2_GENERIC)
{
snprintf(buf, sizeof (buf), ERR_OS2_GENERIC, (int) retval);
err = buf;
} /* if */
if (err != NULL)
__PHYSFS_setError(err);
return(retval);
} /* os2err */
/* (be gentle, this function isn't very robust.) */
static void cvt_path_to_correct_case(char *buf)
{
char *fname = buf + 3; /* point to first element. */
char *ptr = strchr(fname, '\\'); /* find end of first element. */
buf[0] = toupper(buf[0]); /* capitalize drive letter. */
/*
* Go through each path element, and enumerate its parent dir until
* a case-insensitive match is found. If one is (and it SHOULD be)
* then overwrite the original element with the correct case.
* If there's an error, or the path has vanished for some reason, it
* won't hurt to have the original case, so we just keep going.
*/
while (fname != NULL)
{
char spec[CCHMAXPATH];
FILEFINDBUF3 fb;
HDIR hdir = HDIR_CREATE;
ULONG count = 1;
APIRET rc;
*(fname - 1) = '\0'; /* isolate parent dir string. */
strcpy(spec, buf); /* copy isolated parent dir... */
strcat(spec, "\\*.*"); /* ...and add wildcard search spec. */
if (ptr != NULL) /* isolate element to find (fname is the start). */
*ptr = '\0';
rc = DosFindFirst(spec, &hdir, FILE_DIRECTORY,
&fb, sizeof (fb), &count, FIL_STANDARD);
if (rc == NO_ERROR)
{
while (count == 1) /* while still entries to enumerate... */
{
if (__PHYSFS_stricmpASCII(fb.achName, fname) == 0)
{
strcpy(fname, fb.achName);
break; /* there it is. Overwrite and stop searching. */
} /* if */
DosFindNext(hdir, &fb, sizeof (fb), &count);
} /* while */
DosFindClose(hdir);
} /* if */
*(fname - 1) = '\\'; /* unisolate parent dir. */
fname = ptr; /* point to next element. */
if (ptr != NULL)
{
*ptr = '\\'; /* unisolate element. */
ptr = strchr(++fname, '\\'); /* find next element. */
} /* if */
} /* while */
} /* cvt_file_to_correct_case */
static char *baseDir = NULL;
int __PHYSFS_platformInit(void)
{
char buf[CCHMAXPATH];
APIRET rc;
PTIB ptib;
PPIB ppib;
PHYSFS_sint32 len;
assert(baseDir == NULL);
BAIL_IF_MACRO(os2err(DosGetInfoBlocks(&ptib, &ppib)) != NO_ERROR, NULL, 0);
rc = DosQueryModuleName(ppib->pib_hmte, sizeof (buf), (PCHAR) buf);
BAIL_IF_MACRO(os2err(rc) != NO_ERROR, NULL, 0);
/* chop off filename, leave path. */
for (len = strlen(buf) - 1; len >= 0; len--)
{
if (buf[len] == '\\')
{
buf[len] = '\0';
break;
} /* if */
} /* for */
assert(len > 0); /* should have been a "x:\\" on the front on string. */
/* The string is capitalized! Figure out the REAL case... */
cvt_path_to_correct_case(buf);
baseDir = (char *) allocator.Malloc(len + 1);
BAIL_IF_MACRO(baseDir == NULL, ERR_OUT_OF_MEMORY, 0);
strcpy(baseDir, buf);
return(1); /* success. */
} /* __PHYSFS_platformInit */
int __PHYSFS_platformDeinit(void)
{
assert(baseDir != NULL);
allocator.Free(baseDir);
baseDir = NULL;
return(1); /* success. */
} /* __PHYSFS_platformDeinit */
static int disc_is_inserted(ULONG drive)
{
int rc;
char buf[20];
DosError(FERR_DISABLEHARDERR | FERR_DISABLEEXCEPTION);
rc = DosQueryFSInfo(drive + 1, FSIL_VOLSER, buf, sizeof (buf));
DosError(FERR_ENABLEHARDERR | FERR_ENABLEEXCEPTION);
return(rc == NO_ERROR);
} /* is_cdrom_inserted */
/* looks like "CD01" in ASCII (littleendian)...used for an ioctl. */
#define CD01 0x31304443
static int is_cdrom_drive(ULONG drive)
{
PHYSFS_uint32 param, data;
ULONG ul1, ul2;
APIRET rc;
HFILE hfile = NULLHANDLE;
char drivename[3] = { 'A' + drive, ':', '\0' };
rc = DosOpen(drivename, &hfile, &ul1, 0, 0,
OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW,
OPEN_FLAGS_DASD | OPEN_FLAGS_FAIL_ON_ERROR |
OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYNONE, NULL);
BAIL_IF_MACRO(rc != NO_ERROR, NULL, 0);
data = 0;
param = PHYSFS_swapULE32(CD01);
ul1 = ul2 = sizeof (PHYSFS_uint32);
rc = DosDevIOCtl(hfile, IOCTL_CDROMDISK, CDROMDISK_GETDRIVER,
&param, sizeof (param), &ul1, &data, sizeof (data), &ul2);
DosClose(hfile);
return((rc == NO_ERROR) && (PHYSFS_swapULE32(data) == CD01));
} /* is_cdrom_drive */
void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
{
ULONG dummy = 0;
ULONG drivemap = 0;
ULONG i, bit;
APIRET rc = DosQueryCurrentDisk(&dummy, &drivemap);
if (os2err(rc) != NO_ERROR)
return;
for (i = 0, bit = 1; i < 26; i++, bit <<= 1)
{
if (drivemap & bit) /* this logical drive exists. */
{
if ((is_cdrom_drive(i)) && (disc_is_inserted(i)))
{
char drive[4] = "x:\\";
drive[0] = ('A' + i);
cb(data, drive);
} /* if */
} /* if */
} /* for */
} /* __PHYSFS_platformDetectAvailableCDs */
char *__PHYSFS_platformCalcBaseDir(const char *argv0)
{
char *retval = (char *) allocator.Malloc(strlen(baseDir) + 1);
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
strcpy(retval, baseDir); /* calculated at init time. */
return(retval);
} /* __PHYSFS_platformCalcBaseDir */
char *__PHYSFS_platformGetUserName(void)
{
return(NULL); /* (*shrug*) */
} /* __PHYSFS_platformGetUserName */
char *__PHYSFS_platformGetUserDir(void)
{
return(__PHYSFS_platformCalcBaseDir(NULL));
} /* __PHYSFS_platformGetUserDir */
int __PHYSFS_platformExists(const char *fname)
{
FILESTATUS3 fs;
APIRET rc = DosQueryPathInfo(fname, FIL_STANDARD, &fs, sizeof (fs));
return(os2err(rc) == NO_ERROR);
} /* __PHYSFS_platformExists */
int __PHYSFS_platformIsSymLink(const char *fname)
{
return(0); /* no symlinks in OS/2. */
} /* __PHYSFS_platformIsSymlink */
int __PHYSFS_platformIsDirectory(const char *fname)
{
FILESTATUS3 fs;
APIRET rc = DosQueryPathInfo(fname, FIL_STANDARD, &fs, sizeof (fs));
BAIL_IF_MACRO(os2err(rc) != NO_ERROR, NULL, 0)
return((fs.attrFile & FILE_DIRECTORY) != 0);
} /* __PHYSFS_platformIsDirectory */
/* !!! FIXME: can we lose the malloc here? */
char *__PHYSFS_platformCvtToDependent(const char *prepend,
const char *dirName,
const char *append)
{
int len = ((prepend) ? strlen(prepend) : 0) +
((append) ? strlen(append) : 0) +
strlen(dirName) + 1;
char *retval = allocator.Malloc(len);
char *p;
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
if (prepend)
strcpy(retval, prepend);
else
retval[0] = '\0';
strcat(retval, dirName);
if (append)
strcat(retval, append);
for (p = strchr(retval, '/'); p != NULL; p = strchr(p + 1, '/'))
*p = '\\';
return(retval);
} /* __PHYSFS_platformCvtToDependent */
void __PHYSFS_platformEnumerateFiles(const char *dirname,
int omitSymLinks,
PHYSFS_EnumFilesCallback callback,
const char *origdir,
void *callbackdata)
{
char spec[CCHMAXPATH];
FILEFINDBUF3 fb;
HDIR hdir = HDIR_CREATE;
ULONG count = 1;
APIRET rc;
if (strlen(dirname) > sizeof (spec) - 5)
{
__PHYSFS_setError(ERR_BAD_FILENAME);
return;
} /* if */
strcpy(spec, dirname);
strcat(spec, (spec[strlen(spec) - 1] != '\\') ? "\\*.*" : "*.*");
rc = DosFindFirst(spec, &hdir,
FILE_DIRECTORY | FILE_ARCHIVED |
FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM,
&fb, sizeof (fb), &count, FIL_STANDARD);
if (os2err(rc) != NO_ERROR)
return;
while (count == 1)
{
if ((strcmp(fb.achName, ".") != 0) && (strcmp(fb.achName, "..") != 0))
callback(callbackdata, origdir, fb.achName);
DosFindNext(hdir, &fb, sizeof (fb), &count);
} /* while */
DosFindClose(hdir);
} /* __PHYSFS_platformEnumerateFiles */
char *__PHYSFS_platformCurrentDir(void)
{
char *retval;
ULONG currentDisk;
ULONG dummy;
ULONG pathSize = 0;
APIRET rc;
BYTE byte;
rc = DosQueryCurrentDisk(&currentDisk, &dummy);
BAIL_IF_MACRO(os2err(rc) != NO_ERROR, NULL, NULL);
/* The first call just tells us how much space we need for the string. */
rc = DosQueryCurrentDir(currentDisk, &byte, &pathSize);
pathSize++; /* Add space for null terminator. */
retval = (char *) allocator.Malloc(pathSize + 3); /* plus "x:\\" */
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
/* Actually get the string this time. */
rc = DosQueryCurrentDir(currentDisk, (PBYTE) (retval + 3), &pathSize);
if (os2err(rc) != NO_ERROR)
{
allocator.Free(retval);
return(NULL);
} /* if */
retval[0] = ('A' + (currentDisk - 1));
retval[1] = ':';
retval[2] = '\\';
return(retval);
} /* __PHYSFS_platformCurrentDir */
char *__PHYSFS_platformRealPath(const char *path)
{
char buf[CCHMAXPATH];
char *retval;
APIRET rc = DosQueryPathInfo(path, FIL_QUERYFULLNAME, buf, sizeof (buf));
BAIL_IF_MACRO(os2err(rc) != NO_ERROR, NULL, NULL);
retval = (char *) allocator.Malloc(strlen(buf) + 1);
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
strcpy(retval, buf);
return(retval);
} /* __PHYSFS_platformRealPath */
int __PHYSFS_platformMkDir(const char *path)
{
return(os2err(DosCreateDir(path, NULL)) == NO_ERROR);
} /* __PHYSFS_platformMkDir */
void *__PHYSFS_platformOpenRead(const char *filename)
{
ULONG actionTaken = 0;
HFILE hfile = NULLHANDLE;
/*
* File must be opened SHARE_DENYWRITE and ACCESS_READONLY, otherwise
* DosQueryFileInfo() will fail if we try to get a file length, etc.
*/
os2err(DosOpen(filename, &hfile, &actionTaken, 0, FILE_NORMAL,
OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW,
OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NO_LOCALITY |
OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYWRITE |
OPEN_ACCESS_READONLY, NULL));
return((void *) hfile);
} /* __PHYSFS_platformOpenRead */
void *__PHYSFS_platformOpenWrite(const char *filename)
{
ULONG actionTaken = 0;
HFILE hfile = NULLHANDLE;
/*
* File must be opened SHARE_DENYWRITE and ACCESS_READWRITE, otherwise
* DosQueryFileInfo() will fail if we try to get a file length, etc.
*/
os2err(DosOpen(filename, &hfile, &actionTaken, 0, FILE_NORMAL,
OPEN_ACTION_REPLACE_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW,
OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NO_LOCALITY |
OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYWRITE |
OPEN_ACCESS_READWRITE, NULL));
return((void *) hfile);
} /* __PHYSFS_platformOpenWrite */
void *__PHYSFS_platformOpenAppend(const char *filename)
{
ULONG dummy = 0;
HFILE hfile = NULLHANDLE;
APIRET rc;
/*
* File must be opened SHARE_DENYWRITE and ACCESS_READWRITE, otherwise
* DosQueryFileInfo() will fail if we try to get a file length, etc.
*/
rc = os2err(DosOpen(filename, &hfile, &dummy, 0, FILE_NORMAL,
OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW,
OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NO_LOCALITY |
OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYWRITE |
OPEN_ACCESS_READWRITE, NULL));
if (rc == NO_ERROR)
{
if (os2err(DosSetFilePtr(hfile, 0, FILE_END, &dummy)) != NO_ERROR)
{
DosClose(hfile);
hfile = NULLHANDLE;
} /* if */
} /* if */
return((void *) hfile);
} /* __PHYSFS_platformOpenAppend */
PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
PHYSFS_uint32 size, PHYSFS_uint32 count)
{
HFILE hfile = (HFILE) opaque;
PHYSFS_sint64 retval;
ULONG br;
for (retval = 0; retval < count; retval++)
{
os2err(DosRead(hfile, buffer, size, &br));
if (br < size)
{
DosSetFilePtr(hfile, -br, FILE_CURRENT, &br); /* try to cleanup. */
return(retval);
} /* if */
buffer = (void *) ( ((char *) buffer) + size );
} /* for */
return(retval);
} /* __PHYSFS_platformRead */
PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
PHYSFS_uint32 size, PHYSFS_uint32 count)
{
HFILE hfile = (HFILE) opaque;
PHYSFS_sint64 retval;
ULONG bw;
for (retval = 0; retval < count; retval++)
{
os2err(DosWrite(hfile, buffer, size, &bw));
if (bw < size)
{
DosSetFilePtr(hfile, -bw, FILE_CURRENT, &bw); /* try to cleanup. */
return(retval);
} /* if */
buffer = (void *) ( ((char *) buffer) + size );
} /* for */
return(retval);
} /* __PHYSFS_platformWrite */
int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos)
{
ULONG dummy;
HFILE hfile = (HFILE) opaque;
LONG dist = (LONG) pos;
/* hooray for 32-bit filesystem limits! :) */
BAIL_IF_MACRO((PHYSFS_uint64) dist != pos, ERR_SEEK_OUT_OF_RANGE, 0);
return(os2err(DosSetFilePtr(hfile, dist, FILE_BEGIN, &dummy)) == NO_ERROR);
} /* __PHYSFS_platformSeek */
PHYSFS_sint64 __PHYSFS_platformTell(void *opaque)
{
ULONG pos;
HFILE hfile = (HFILE) opaque;
APIRET rc = os2err(DosSetFilePtr(hfile, 0, FILE_CURRENT, &pos));
BAIL_IF_MACRO(rc != NO_ERROR, NULL, -1);
return((PHYSFS_sint64) pos);
} /* __PHYSFS_platformTell */
PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
{
FILESTATUS3 fs;
HFILE hfile = (HFILE) opaque;
APIRET rc = DosQueryFileInfo(hfile, FIL_STANDARD, &fs, sizeof (fs));
BAIL_IF_MACRO(os2err(rc) != NO_ERROR, NULL, -1);
return((PHYSFS_sint64) fs.cbFile);
} /* __PHYSFS_platformFileLength */
int __PHYSFS_platformEOF(void *opaque)
{
PHYSFS_sint64 len, pos;
len = __PHYSFS_platformFileLength(opaque);
BAIL_IF_MACRO(len == -1, NULL, 1); /* (*shrug*) */
pos = __PHYSFS_platformTell(opaque);
BAIL_IF_MACRO(pos == -1, NULL, 1); /* (*shrug*) */
return(pos >= len);
} /* __PHYSFS_platformEOF */
int __PHYSFS_platformFlush(void *opaque)
{
return(os2err(DosResetBuffer((HFILE) opaque)) == NO_ERROR);
} /* __PHYSFS_platformFlush */
int __PHYSFS_platformClose(void *opaque)
{
return(os2err(DosClose((HFILE) opaque)) == NO_ERROR);
} /* __PHYSFS_platformClose */
int __PHYSFS_platformDelete(const char *path)
{
if (__PHYSFS_platformIsDirectory(path))
return(os2err(DosDeleteDir(path)) == NO_ERROR);
return(os2err(DosDelete(path)) == NO_ERROR);
} /* __PHYSFS_platformDelete */
PHYSFS_sint64 __PHYSFS_platformGetLastModTime(const char *fname)
{
PHYSFS_sint64 retval;
struct tm tm;
FILESTATUS3 fs;
APIRET rc = DosQueryPathInfo(fname, FIL_STANDARD, &fs, sizeof (fs));
BAIL_IF_MACRO(os2err(rc) != NO_ERROR, NULL, -1);
/* Convert to a format that mktime() can grok... */
tm.tm_sec = ((PHYSFS_uint32) fs.ftimeLastWrite.twosecs) * 2;
tm.tm_min = fs.ftimeLastWrite.minutes;
tm.tm_hour = fs.ftimeLastWrite.hours;
tm.tm_mday = fs.fdateLastWrite.day;
tm.tm_mon = fs.fdateLastWrite.month;
tm.tm_year = ((PHYSFS_uint32) fs.fdateLastWrite.year) + 80;
tm.tm_wday = -1 /*st_localtz.wDayOfWeek*/;
tm.tm_yday = -1;
tm.tm_isdst = -1;
/* Convert to a format PhysicsFS can grok... */
retval = (PHYSFS_sint64) mktime(&tm);
BAIL_IF_MACRO(retval == -1, strerror(errno), -1);
return(retval);
} /* __PHYSFS_platformGetLastModTime */
PHYSFS_uint64 __PHYSFS_platformGetThreadID(void)
{
PTIB ptib;
PPIB ppib;
/*
* Allegedly, this API never fails, but we'll punt and return a
* default value (zero might as well do) if it does.
*/
BAIL_IF_MACRO(os2err(DosGetInfoBlocks(&ptib, &ppib)) != NO_ERROR, 0, 0);
return((PHYSFS_uint64) ptib->tib_ordinal);
} /* __PHYSFS_platformGetThreadID */
void *__PHYSFS_platformCreateMutex(void)
{
HMTX hmtx = NULLHANDLE;
os2err(DosCreateMutexSem(NULL, &hmtx, 0, 0));
return((void *) hmtx);
} /* __PHYSFS_platformCreateMutex */
void __PHYSFS_platformDestroyMutex(void *mutex)
{
DosCloseMutexSem((HMTX) mutex);
} /* __PHYSFS_platformDestroyMutex */
int __PHYSFS_platformGrabMutex(void *mutex)
{
/* Do _NOT_ call os2err() (which sets the physfs error msg) in here! */
return(DosRequestMutexSem((HMTX) mutex, SEM_INDEFINITE_WAIT) == NO_ERROR);
} /* __PHYSFS_platformGrabMutex */
void __PHYSFS_platformReleaseMutex(void *mutex)
{
DosReleaseMutexSem((HMTX) mutex);
} /* __PHYSFS_platformReleaseMutex */
/* !!! FIXME: Don't use C runtime for allocators? */
int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
{
return(0); /* just use malloc() and friends. */
} /* __PHYSFS_platformSetDefaultAllocator */
#endif /* PHYSFS_PLATFORM_OS2 */
/* end of os2.c ... */

View File

@@ -0,0 +1,608 @@
/*
* PocketPC 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_platforms.h"
#ifdef PHYSFS_PLATFORM_POCKETPC
#include <stdio.h>
#include <windows.h>
#include "physfs_internal.h"
#define INVALID_FILE_ATTRIBUTES 0xFFFFFFFF
#define INVALID_SET_FILE_POINTER 0xFFFFFFFF
typedef struct
{
HANDLE handle;
int readonly;
} winCEfile;
const char *__PHYSFS_platformDirSeparator = "\\";
static char *userDir = NULL;
/*
* Figure out what the last failing Win32 API call was, and
* generate a human-readable string for the error message.
*
* The return value is a static buffer that is overwritten with
* each call to this function.
*/
static const char *win32strerror(void)
{
static TCHAR msgbuf[255];
TCHAR *ptr = msgbuf;
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
msgbuf,
sizeof (msgbuf) / sizeof (TCHAR),
NULL
);
/* chop off newlines. */
for (ptr = msgbuf; *ptr; ptr++)
{
if ((*ptr == '\n') || (*ptr == '\r'))
{
*ptr = ' ';
break;
} /* if */
} /* for */
return((const char *) msgbuf);
} /* win32strerror */
/* !!! FIXME: need to check all of these for NULLs. */
#define UTF8_TO_UNICODE_STACK_MACRO(w_assignto, str) { \
if (str == NULL) \
w_assignto = NULL; \
else { \
const PHYSFS_uint64 len = (PHYSFS_uint64) ((strlen(str) * 4) + 1); \
w_assignto = (char *) __PHYSFS_smallAlloc(len); \
PHYSFS_uc2fromutf8(str, (PHYSFS_uint16 *) w_assignto, len); \
} \
} \
static char *getExePath()
{
DWORD buflen;
int success = 0;
TCHAR *ptr = NULL;
TCHAR *retval = (TCHAR*) allocator.Malloc(sizeof (TCHAR) * (MAX_PATH + 1));
char *charretval;
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
retval[0] = _T('\0');
/* !!! FIXME: don't preallocate here? */
/* !!! FIXME: use smallAlloc? */
buflen = GetModuleFileName(NULL, retval, MAX_PATH + 1);
if (buflen <= 0)
__PHYSFS_setError(win32strerror());
else
{
retval[buflen] = '\0'; /* does API always null-terminate this? */
ptr = retval+buflen;
while( ptr != retval )
{
if( *ptr != _T('\\') )
*ptr-- = _T('\0');
else
break;
} /* while */
success = 1;
} /* else */
if (!success)
{
allocator.Free(retval);
return(NULL); /* physfs error message will be set, above. */
} /* if */
buflen = (buflen * 4) + 1;
charretval = (char *) allocator.Malloc(buflen);
if (charretval != NULL)
PHYSFS_utf8fromucs2((const PHYSFS_uint16 *) retval, charretval, buflen);
allocator.Free(retval);
return(charretval); /* w00t. */
} /* getExePath */
int __PHYSFS_platformInit(void)
{
userDir = getExePath();
BAIL_IF_MACRO(userDir == NULL, NULL, 0); /* failed? */
return(1); /* always succeed. */
} /* __PHYSFS_platformInit */
int __PHYSFS_platformDeinit(void)
{
allocator.Free(userDir);
return(1); /* always succeed. */
} /* __PHYSFS_platformDeinit */
void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
{
/* no-op on this platform. */
} /* __PHYSFS_platformDetectAvailableCDs */
char *__PHYSFS_platformCalcBaseDir(const char *argv0)
{
return(getExePath());
} /* __PHYSFS_platformCalcBaseDir */
char *__PHYSFS_platformGetUserName(void)
{
BAIL_MACRO(ERR_NOT_IMPLEMENTED, NULL);
} /* __PHYSFS_platformGetUserName */
char *__PHYSFS_platformGetUserDir(void)
{
return userDir;
BAIL_MACRO(ERR_NOT_IMPLEMENTED, NULL);
} /* __PHYSFS_platformGetUserDir */
PHYSFS_uint64 __PHYSFS_platformGetThreadID(void)
{
return(1); /* single threaded. */
} /* __PHYSFS_platformGetThreadID */
int __PHYSFS_platformExists(const char *fname)
{
int retval = 0;
wchar_t *w_fname = NULL;
UTF8_TO_UNICODE_STACK_MACRO(w_fname, fname);
if (w_fname != NULL)
retval = (GetFileAttributes(w_fname) != INVALID_FILE_ATTRIBUTES);
__PHYSFS_smallFree(w_fname);
return(retval);
} /* __PHYSFS_platformExists */
int __PHYSFS_platformIsSymLink(const char *fname)
{
BAIL_MACRO(ERR_NOT_IMPLEMENTED, 0);
} /* __PHYSFS_platformIsSymlink */
int __PHYSFS_platformIsDirectory(const char *fname)
{
int retval = 0;
wchar_t *w_fname = NULL;
UTF8_TO_UNICODE_STACK_MACRO(w_fname, fname);
if (w_fname != NULL)
retval = ((GetFileAttributes(w_fname) & FILE_ATTRIBUTE_DIRECTORY) != 0);
__PHYSFS_smallFree(w_fname);
return(retval);
} /* __PHYSFS_platformIsDirectory */
char *__PHYSFS_platformCvtToDependent(const char *prepend,
const char *dirName,
const char *append)
{
int len = ((prepend) ? strlen(prepend) : 0) +
((append) ? strlen(append) : 0) +
strlen(dirName) + 1;
char *retval = (char *) allocator.Malloc(len);
char *p;
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
if (prepend)
strcpy(retval, prepend);
else
retval[0] = '\0';
strcat(retval, dirName);
if (append)
strcat(retval, append);
for (p = strchr(retval, '/'); p != NULL; p = strchr(p + 1, '/'))
*p = '\\';
return(retval);
} /* __PHYSFS_platformCvtToDependent */
static int doEnumCallback(const wchar_t *w_fname)
{
const PHYSFS_uint64 len = (PHYSFS_uint64) ((wcslen(w_fname) * 4) + 1);
char *str = (char *) __PHYSFS_smallAlloc(len);
PHYSFS_utf8fromucs2((const PHYSFS_uint16 *) w_fname, str, len);
callback(callbackdata, origdir, str);
__PHYSFS_smallFree(str);
return 1;
} /* doEnumCallback */
void __PHYSFS_platformEnumerateFiles(const char *dirname,
int omitSymLinks,
PHYSFS_EnumFilesCallback callback,
const char *origdir,
void *callbackdata)
{
HANDLE dir;
WIN32_FIND_DATA ent;
char *SearchPath;
wchar_t *w_SearchPath;
size_t len = strlen(dirname);
/* Allocate a new string for path, maybe '\\', "*", and NULL terminator */
SearchPath = (char *) __PHYSFS_smallAlloc(len + 3);
BAIL_IF_MACRO(SearchPath == NULL, ERR_OUT_OF_MEMORY, NULL);
/* Copy current dirname */
strcpy(SearchPath, dirname);
/* if there's no '\\' at the end of the path, stick one in there. */
if (SearchPath[len - 1] != '\\')
{
SearchPath[len++] = '\\';
SearchPath[len] = '\0';
} /* if */
/* Append the "*" to the end of the string */
strcat(SearchPath, "*");
UTF8_TO_UNICODE_STACK_MACRO(w_SearchPath, SearchPath);
__PHYSFS_smallFree(SearchPath);
dir = FindFirstFile(w_SearchPath, &ent);
__PHYSFS_smallFree(w_SearchPath);
if (dir == INVALID_HANDLE_VALUE)
return;
do
{
const char *str = NULL;
if (wcscmp(ent.cFileName, L".") == 0)
continue;
if (wcscmp(ent.cFileName, L"..") == 0)
continue;
if (!doEnumCallback(ent.cFileName))
break;
} while (FindNextFile(dir, &ent) != 0);
FindClose(dir);
} /* __PHYSFS_platformEnumerateFiles */
char *__PHYSFS_platformCurrentDir(void)
{
return("\\");
} /* __PHYSFS_platformCurrentDir */
char *__PHYSFS_platformRealPath(const char *path)
{
char *retval = (char *) allocator.Malloc(strlen(path) + 1);
strcpy(retval,path);
return(retval);
} /* __PHYSFS_platformRealPath */
int __PHYSFS_platformMkDir(const char *path)
{
int retval = 0;
wchar_t *w_path = NULL;
UTF8_TO_UNICODE_STACK_MACRO(w_path, path);
if (w_path != NULL)
{
retval = CreateDirectory(w_path, NULL);
__PHYSFS_smallFree(w_fname);
} /* if */
return(retval);
} /* __PHYSFS_platformMkDir */
static void *doOpen(const char *fname, DWORD mode, DWORD creation, int rdonly)
{
HANDLE fileHandle;
winCEfile *retval;
wchar_t *w_fname = NULL;
UTF8_TO_UNICODE_STACK_MACRO(w_fname, fname);
fileHandle = CreateFile(w_fname, mode, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, creation, FILE_ATTRIBUTE_NORMAL, NULL);
__PHYSFS_smallFree(w_fname);
BAIL_IF_MACRO(fileHandle == INVALID_HANDLE_VALUE, win32strerror(), NULL);
retval = (winCEfile *) allocator.Malloc(sizeof (winCEfile));
if (retval == NULL)
{
CloseHandle(fileHandle);
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
} /* if */
retval->readonly = rdonly;
retval->handle = fileHandle;
return(retval);
} /* doOpen */
void *__PHYSFS_platformOpenRead(const char *filename)
{
return(doOpen(filename, GENERIC_READ, OPEN_EXISTING, 1));
} /* __PHYSFS_platformOpenRead */
void *__PHYSFS_platformOpenWrite(const char *filename)
{
return(doOpen(filename, GENERIC_WRITE, CREATE_ALWAYS, 0));
} /* __PHYSFS_platformOpenWrite */
void *__PHYSFS_platformOpenAppend(const char *filename)
{
void *retval = doOpen(filename, GENERIC_WRITE, OPEN_ALWAYS, 0);
if (retval != NULL)
{
HANDLE h = ((winCEfile *) retval)->handle;
if (SetFilePointer(h, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
{
const char *err = win32strerror();
CloseHandle(h);
allocator.Free(retval);
BAIL_MACRO(err, NULL);
} /* if */
} /* if */
return(retval);
} /* __PHYSFS_platformOpenAppend */
PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
PHYSFS_uint32 size, PHYSFS_uint32 count)
{
HANDLE Handle = ((winCEfile *) opaque)->handle;
DWORD CountOfBytesRead;
PHYSFS_sint64 retval;
/* Read data from the file */
/*!!! - uint32 might be a greater # than DWORD */
if (!ReadFile(Handle, buffer, count * size, &CountOfBytesRead, NULL))
{
retval = -1;
} /* if */
else
{
/* Return the number of "objects" read. */
/* !!! - What if not the right amount of bytes was read to make an object? */
retval = CountOfBytesRead / size;
} /* else */
return(retval);
} /* __PHYSFS_platformRead */
PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
PHYSFS_uint32 size, PHYSFS_uint32 count)
{
HANDLE Handle = ((winCEfile *) opaque)->handle;
DWORD CountOfBytesWritten;
PHYSFS_sint64 retval;
/* Read data from the file */
/*!!! - uint32 might be a greater # than DWORD */
if (!WriteFile(Handle, buffer, count * size, &CountOfBytesWritten, NULL))
{
retval = -1;
} /* if */
else
{
/* Return the number of "objects" read. */
/*!!! - What if not the right number of bytes was written? */
retval = CountOfBytesWritten / size;
} /* else */
return(retval);
} /* __PHYSFS_platformWrite */
int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos)
{
HANDLE Handle = ((winCEfile *) opaque)->handle;
DWORD HighOrderPos;
DWORD rc;
/* Get the high order 32-bits of the position */
//HighOrderPos = HIGHORDER_UINT64(pos);
HighOrderPos = (unsigned long)(pos>>32);
/*!!! SetFilePointer needs a signed 64-bit value. */
/* Move pointer "pos" count from start of file */
rc = SetFilePointer(Handle, (unsigned long)(pos&0x00000000ffffffff),
&HighOrderPos, FILE_BEGIN);
if ((rc == INVALID_SET_FILE_POINTER) && (GetLastError() != NO_ERROR))
{
BAIL_MACRO(win32strerror(), 0);
}
return(1); /* No error occured */
} /* __PHYSFS_platformSeek */
PHYSFS_sint64 __PHYSFS_platformTell(void *opaque)
{
HANDLE Handle = ((winCEfile *) opaque)->handle;
DWORD HighPos = 0;
DWORD LowPos;
PHYSFS_sint64 retval;
/* Get current position */
LowPos = SetFilePointer(Handle, 0, &HighPos, FILE_CURRENT);
if ((LowPos == INVALID_SET_FILE_POINTER) && (GetLastError() != NO_ERROR))
{
BAIL_MACRO(win32strerror(), 0);
} /* if */
else
{
/* Combine the high/low order to create the 64-bit position value */
retval = (((PHYSFS_uint64) HighPos) << 32) | LowPos;
//assert(retval >= 0);
} /* else */
return(retval);
} /* __PHYSFS_platformTell */
PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
{
HANDLE Handle = ((winCEfile *) opaque)->handle;
DWORD SizeHigh;
DWORD SizeLow;
PHYSFS_sint64 retval;
SizeLow = GetFileSize(Handle, &SizeHigh);
if ((SizeLow == INVALID_SET_FILE_POINTER) && (GetLastError() != NO_ERROR))
{
BAIL_MACRO(win32strerror(), -1);
} /* if */
else
{
/* Combine the high/low order to create the 64-bit position value */
retval = (((PHYSFS_uint64) SizeHigh) << 32) | SizeLow;
//assert(retval >= 0);
} /* else */
return(retval);
} /* __PHYSFS_platformFileLength */
int __PHYSFS_platformEOF(void *opaque)
{
PHYSFS_sint64 FilePosition;
int retval = 0;
/* Get the current position in the file */
if ((FilePosition = __PHYSFS_platformTell(opaque)) != 0)
{
/* Non-zero if EOF is equal to the file length */
retval = FilePosition == __PHYSFS_platformFileLength(opaque);
} /* if */
return(retval);
} /* __PHYSFS_platformEOF */
int __PHYSFS_platformFlush(void *opaque)
{
winCEfile *fh = ((winCEfile *) opaque);
if (!fh->readonly)
BAIL_IF_MACRO(!FlushFileBuffers(fh->handle), win32strerror(), 0);
return(1);
} /* __PHYSFS_platformFlush */
int __PHYSFS_platformClose(void *opaque)
{
HANDLE Handle = ((winCEfile *) opaque)->handle;
BAIL_IF_MACRO(!CloseHandle(Handle), win32strerror(), 0);
allocator.Free(opaque);
return(1);
} /* __PHYSFS_platformClose */
int __PHYSFS_platformDelete(const char *path)
{
wchar_t *w_path = NULL;
UTF8_TO_UNICODE_STACK_MACRO(w_path, path);
/* If filename is a folder */
if (GetFileAttributes(w_path) == FILE_ATTRIBUTE_DIRECTORY)
{
int retval = !RemoveDirectory(w_path);
__PHYSFS_smallFree(w_path);
BAIL_IF_MACRO(retval, win32strerror(), 0);
} /* if */
else
{
int retval = !DeleteFile(w_path);
__PHYSFS_smallFree(w_path);
BAIL_IF_MACRO(retval, win32strerror(), 0);
} /* else */
return(1); /* if you got here, it worked. */
} /* __PHYSFS_platformDelete */
/*
* !!! FIXME: why aren't we using Critical Sections instead of Mutexes?
* !!! FIXME: mutexes on Windows are for cross-process sync. CritSects are
* !!! FIXME: mutexes for threads in a single process and are faster.
*/
void *__PHYSFS_platformCreateMutex(void)
{
return((void *) CreateMutex(NULL, FALSE, NULL));
} /* __PHYSFS_platformCreateMutex */
void __PHYSFS_platformDestroyMutex(void *mutex)
{
CloseHandle((HANDLE) mutex);
} /* __PHYSFS_platformDestroyMutex */
int __PHYSFS_platformGrabMutex(void *mutex)
{
return(WaitForSingleObject((HANDLE) mutex, INFINITE) != WAIT_FAILED);
} /* __PHYSFS_platformGrabMutex */
void __PHYSFS_platformReleaseMutex(void *mutex)
{
ReleaseMutex((HANDLE) mutex);
} /* __PHYSFS_platformReleaseMutex */
PHYSFS_sint64 __PHYSFS_platformGetLastModTime(const char *fname)
{
BAIL_MACRO(ERR_NOT_IMPLEMENTED, -1);
} /* __PHYSFS_platformGetLastModTime */
/* !!! FIXME: Don't use C runtime for allocators? */
int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
{
return(0); /* just use malloc() and friends. */
} /* __PHYSFS_platformSetDefaultAllocator */
#endif /* PHYSFS_PLATFORM_POCKETPC */
/* end of pocketpc.c ... */

View File

@@ -0,0 +1,424 @@
/*
* Posix-esque 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_platforms.h"
#ifdef PHYSFS_PLATFORM_POSIX
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#ifdef PHYSFS_HAVE_LLSEEK
#include <linux/unistd.h>
#endif
#include "physfs_internal.h"
const char *__PHYSFS_platformDirSeparator = "/";
char *__PHYSFS_platformCopyEnvironmentVariable(const char *varname)
{
const char *envr = getenv(varname);
char *retval = NULL;
if (envr != NULL)
{
retval = (char *) allocator.Malloc(strlen(envr) + 1);
if (retval != NULL)
strcpy(retval, envr);
} /* if */
return(retval);
} /* __PHYSFS_platformCopyEnvironmentVariable */
static char *getUserNameByUID(void)
{
uid_t uid = getuid();
struct passwd *pw;
char *retval = NULL;
pw = getpwuid(uid);
if ((pw != NULL) && (pw->pw_name != NULL))
{
retval = (char *) allocator.Malloc(strlen(pw->pw_name) + 1);
if (retval != NULL)
strcpy(retval, pw->pw_name);
} /* if */
return(retval);
} /* getUserNameByUID */
static char *getUserDirByUID(void)
{
uid_t uid = getuid();
struct passwd *pw;
char *retval = NULL;
pw = getpwuid(uid);
if ((pw != NULL) && (pw->pw_dir != NULL))
{
retval = (char *) allocator.Malloc(strlen(pw->pw_dir) + 1);
if (retval != NULL)
strcpy(retval, pw->pw_dir);
} /* if */
return(retval);
} /* getUserDirByUID */
char *__PHYSFS_platformGetUserName(void)
{
char *retval = getUserNameByUID();
if (retval == NULL)
retval = __PHYSFS_platformCopyEnvironmentVariable("USER");
return(retval);
} /* __PHYSFS_platformGetUserName */
char *__PHYSFS_platformGetUserDir(void)
{
char *retval = __PHYSFS_platformCopyEnvironmentVariable("HOME");
/* if the environment variable was set, make sure it's really a dir. */
if (retval != NULL)
{
struct stat statbuf;
if ((stat(retval, &statbuf) == -1) || (S_ISDIR(statbuf.st_mode) == 0))
{
allocator.Free(retval);
retval = NULL;
} /* if */
} /* if */
if (retval == NULL)
retval = getUserDirByUID();
return(retval);
} /* __PHYSFS_platformGetUserDir */
int __PHYSFS_platformExists(const char *fname)
{
struct stat statbuf;
BAIL_IF_MACRO(lstat(fname, &statbuf) == -1, strerror(errno), 0);
return(1);
} /* __PHYSFS_platformExists */
int __PHYSFS_platformIsSymLink(const char *fname)
{
struct stat statbuf;
BAIL_IF_MACRO(lstat(fname, &statbuf) == -1, strerror(errno), 0);
return( (S_ISLNK(statbuf.st_mode)) ? 1 : 0 );
} /* __PHYSFS_platformIsSymlink */
int __PHYSFS_platformIsDirectory(const char *fname)
{
struct stat statbuf;
BAIL_IF_MACRO(stat(fname, &statbuf) == -1, strerror(errno), 0);
return( (S_ISDIR(statbuf.st_mode)) ? 1 : 0 );
} /* __PHYSFS_platformIsDirectory */
char *__PHYSFS_platformCvtToDependent(const char *prepend,
const char *dirName,
const char *append)
{
int len = ((prepend) ? strlen(prepend) : 0) +
((append) ? strlen(append) : 0) +
strlen(dirName) + 1;
char *retval = (char *) allocator.Malloc(len);
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
/* platform-independent notation is Unix-style already. :) */
if (prepend)
strcpy(retval, prepend);
else
retval[0] = '\0';
strcat(retval, dirName);
if (append)
strcat(retval, append);
return(retval);
} /* __PHYSFS_platformCvtToDependent */
void __PHYSFS_platformEnumerateFiles(const char *dirname,
int omitSymLinks,
PHYSFS_EnumFilesCallback callback,
const char *origdir,
void *callbackdata)
{
DIR *dir;
struct dirent *ent;
int bufsize = 0;
char *buf = NULL;
int dlen = 0;
if (omitSymLinks) /* !!! FIXME: this malloc sucks. */
{
dlen = strlen(dirname);
bufsize = dlen + 256;
buf = (char *) allocator.Malloc(bufsize);
if (buf == NULL)
return;
strcpy(buf, dirname);
if (buf[dlen - 1] != '/')
{
buf[dlen++] = '/';
buf[dlen] = '\0';
} /* if */
} /* if */
errno = 0;
dir = opendir(dirname);
if (dir == NULL)
{
allocator.Free(buf);
return;
} /* if */
while ((ent = readdir(dir)) != NULL)
{
if (strcmp(ent->d_name, ".") == 0)
continue;
if (strcmp(ent->d_name, "..") == 0)
continue;
if (omitSymLinks)
{
char *p;
int len = strlen(ent->d_name) + dlen + 1;
if (len > bufsize)
{
p = (char *) allocator.Realloc(buf, len);
if (p == NULL)
continue;
buf = p;
bufsize = len;
} /* if */
strcpy(buf + dlen, ent->d_name);
if (__PHYSFS_platformIsSymLink(buf))
continue;
} /* if */
callback(callbackdata, origdir, ent->d_name);
} /* while */
allocator.Free(buf);
closedir(dir);
} /* __PHYSFS_platformEnumerateFiles */
int __PHYSFS_platformMkDir(const char *path)
{
int rc;
errno = 0;
rc = mkdir(path, S_IRWXU);
BAIL_IF_MACRO(rc == -1, strerror(errno), 0);
return(1);
} /* __PHYSFS_platformMkDir */
static void *doOpen(const char *filename, int mode)
{
const int appending = (mode & O_APPEND);
int fd;
int *retval;
errno = 0;
/* O_APPEND doesn't actually behave as we'd like. */
mode &= ~O_APPEND;
fd = open(filename, mode, S_IRUSR | S_IWUSR);
BAIL_IF_MACRO(fd < 0, strerror(errno), NULL);
if (appending)
{
if (lseek(fd, 0, SEEK_END) < 0)
{
close(fd);
BAIL_MACRO(strerror(errno), NULL);
} /* if */
} /* if */
retval = (int *) allocator.Malloc(sizeof (int));
if (retval == NULL)
{
close(fd);
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
} /* if */
*retval = fd;
return((void *) retval);
} /* doOpen */
void *__PHYSFS_platformOpenRead(const char *filename)
{
return(doOpen(filename, O_RDONLY));
} /* __PHYSFS_platformOpenRead */
void *__PHYSFS_platformOpenWrite(const char *filename)
{
return(doOpen(filename, O_WRONLY | O_CREAT | O_TRUNC));
} /* __PHYSFS_platformOpenWrite */
void *__PHYSFS_platformOpenAppend(const char *filename)
{
return(doOpen(filename, O_WRONLY | O_CREAT | O_APPEND));
} /* __PHYSFS_platformOpenAppend */
PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
PHYSFS_uint32 size, PHYSFS_uint32 count)
{
int fd = *((int *) opaque);
int max = size * count;
int rc = read(fd, buffer, max);
BAIL_IF_MACRO(rc == -1, strerror(errno), rc);
assert(rc <= max);
if ((rc < max) && (size > 1))
lseek(fd, -(rc % size), SEEK_CUR); /* rollback to object boundary. */
return(rc / size);
} /* __PHYSFS_platformRead */
PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
PHYSFS_uint32 size, PHYSFS_uint32 count)
{
int fd = *((int *) opaque);
int max = size * count;
int rc = write(fd, (void *) buffer, max);
BAIL_IF_MACRO(rc == -1, strerror(errno), rc);
assert(rc <= max);
if ((rc < max) && (size > 1))
lseek(fd, -(rc % size), SEEK_CUR); /* rollback to object boundary. */
return(rc / size);
} /* __PHYSFS_platformWrite */
int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos)
{
int fd = *((int *) opaque);
#ifdef PHYSFS_HAVE_LLSEEK
unsigned long offset_high = ((pos >> 32) & 0xFFFFFFFF);
unsigned long offset_low = (pos & 0xFFFFFFFF);
loff_t retoffset;
int rc = llseek(fd, offset_high, offset_low, &retoffset, SEEK_SET);
BAIL_IF_MACRO(rc == -1, strerror(errno), 0);
#else
BAIL_IF_MACRO(lseek(fd, (int) pos, SEEK_SET) == -1, strerror(errno), 0);
#endif
return(1);
} /* __PHYSFS_platformSeek */
PHYSFS_sint64 __PHYSFS_platformTell(void *opaque)
{
int fd = *((int *) opaque);
PHYSFS_sint64 retval;
#ifdef PHYSFS_HAVE_LLSEEK
loff_t retoffset;
int rc = llseek(fd, 0, &retoffset, SEEK_CUR);
BAIL_IF_MACRO(rc == -1, strerror(errno), -1);
retval = (PHYSFS_sint64) retoffset;
#else
retval = (PHYSFS_sint64) lseek(fd, 0, SEEK_CUR);
BAIL_IF_MACRO(retval == -1, strerror(errno), -1);
#endif
return(retval);
} /* __PHYSFS_platformTell */
PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
{
int fd = *((int *) opaque);
struct stat statbuf;
BAIL_IF_MACRO(fstat(fd, &statbuf) == -1, strerror(errno), -1);
return((PHYSFS_sint64) statbuf.st_size);
} /* __PHYSFS_platformFileLength */
int __PHYSFS_platformEOF(void *opaque)
{
PHYSFS_sint64 pos = __PHYSFS_platformTell(opaque);
PHYSFS_sint64 len = __PHYSFS_platformFileLength(opaque);
return(pos >= len);
} /* __PHYSFS_platformEOF */
int __PHYSFS_platformFlush(void *opaque)
{
int fd = *((int *) opaque);
BAIL_IF_MACRO(fsync(fd) == -1, strerror(errno), 0);
return(1);
} /* __PHYSFS_platformFlush */
int __PHYSFS_platformClose(void *opaque)
{
int fd = *((int *) opaque);
BAIL_IF_MACRO(close(fd) == -1, strerror(errno), 0);
allocator.Free(opaque);
return(1);
} /* __PHYSFS_platformClose */
int __PHYSFS_platformDelete(const char *path)
{
BAIL_IF_MACRO(remove(path) == -1, strerror(errno), 0);
return(1);
} /* __PHYSFS_platformDelete */
PHYSFS_sint64 __PHYSFS_platformGetLastModTime(const char *fname)
{
struct stat statbuf;
BAIL_IF_MACRO(stat(fname, &statbuf) < 0, strerror(errno), -1);
return statbuf.st_mtime;
} /* __PHYSFS_platformGetLastModTime */
#endif /* PHYSFS_PLATFORM_POSIX */
/* end of posix.c ... */

View File

@@ -0,0 +1,446 @@
/*
* Unix 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_platforms.h"
#ifdef PHYSFS_PLATFORM_UNIX
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <dirent.h>
#include <time.h>
#include <errno.h>
#if (!defined PHYSFS_NO_THREAD_SUPPORT)
#include <pthread.h>
#endif
#ifdef PHYSFS_HAVE_SYS_UCRED_H
# ifdef PHYSFS_HAVE_MNTENT_H
# undef PHYSFS_HAVE_MNTENT_H /* don't do both... */
# endif
# include <sys/ucred.h>
# include <sys/mount.h>
#endif
#ifdef PHYSFS_HAVE_MNTENT_H
#include <mntent.h>
#endif
#include "physfs_internal.h"
#ifndef MAXPATHLEN
#define MAXPATHLEN 1024
#endif
int __PHYSFS_platformInit(void)
{
return(1); /* always succeed. */
} /* __PHYSFS_platformInit */
int __PHYSFS_platformDeinit(void)
{
return(1); /* always succeed. */
} /* __PHYSFS_platformDeinit */
#ifdef PHYSFS_NO_CDROM_SUPPORT
/* Stub version for platforms without CD-ROM support. */
void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
{
} /* __PHYSFS_platformDetectAvailableCDs */
#elif (defined PHYSFS_HAVE_SYS_UCRED_H)
void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
{
int i;
struct statfs *mntbufp = NULL;
int mounts = getmntinfo(&mntbufp, MNT_WAIT);
for (i = 0; i < mounts; i++)
{
int add_it = 0;
if (strcmp(mntbufp[i].f_fstypename, "iso9660") == 0)
add_it = 1;
else if (strcmp( mntbufp[i].f_fstypename, "cd9660") == 0)
add_it = 1;
/* add other mount types here */
if (add_it)
cb(data, mntbufp[i].f_mntonname);
} /* for */
} /* __PHYSFS_platformDetectAvailableCDs */
#elif (defined PHYSFS_HAVE_MNTENT_H)
void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
{
FILE *mounts = NULL;
struct mntent *ent = NULL;
mounts = setmntent("/etc/mtab", "r");
BAIL_IF_MACRO(mounts == NULL, ERR_IO_ERROR, /*return void*/);
while ( (ent = getmntent(mounts)) != NULL )
{
int add_it = 0;
if (strcmp(ent->mnt_type, "iso9660") == 0)
add_it = 1;
else if (strcmp(ent->mnt_type, "udf") == 0)
add_it = 1;
/* !!! FIXME: these might pick up floppy drives, right? */
else if (strcmp(ent->mnt_type, "auto") == 0)
add_it = 1;
else if (strcmp(ent->mnt_type, "supermount") == 0)
add_it = 1;
/* add other mount types here */
if (add_it)
cb(data, ent->mnt_dir);
} /* while */
endmntent(mounts);
} /* __PHYSFS_platformDetectAvailableCDs */
#endif
/* this is in posix.c ... */
extern char *__PHYSFS_platformCopyEnvironmentVariable(const char *varname);
/*
* See where program (bin) resides in the $PATH specified by (envr).
* returns a copy of the first element in envr that contains it, or NULL
* if it doesn't exist or there were other problems. PHYSFS_SetError() is
* called if we have a problem.
*
* (envr) will be scribbled over, and you are expected to allocator.Free() the
* return value when you're done with it.
*/
static char *findBinaryInPath(const char *bin, char *envr)
{
size_t alloc_size = 0;
char *exe = NULL;
char *start = envr;
char *ptr;
BAIL_IF_MACRO(bin == NULL, ERR_INVALID_ARGUMENT, NULL);
BAIL_IF_MACRO(envr == NULL, ERR_INVALID_ARGUMENT, NULL);
do
{
size_t size;
ptr = strchr(start, ':'); /* find next $PATH separator. */
if (ptr)
*ptr = '\0';
size = strlen(start) + strlen(bin) + 2;
if (size > alloc_size)
{
char *x = (char *) allocator.Realloc(exe, size);
if (x == NULL)
{
if (exe != NULL)
allocator.Free(exe);
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
} /* if */
alloc_size = size;
exe = x;
} /* if */
/* build full binary path... */
strcpy(exe, start);
if ((exe[0] == '\0') || (exe[strlen(exe) - 1] != '/'))
strcat(exe, "/");
strcat(exe, bin);
if (access(exe, X_OK) == 0) /* Exists as executable? We're done. */
{
strcpy(exe, start); /* i'm lazy. piss off. */
return(exe);
} /* if */
start = ptr + 1; /* start points to beginning of next element. */
} while (ptr != NULL);
if (exe != NULL)
allocator.Free(exe);
return(NULL); /* doesn't exist in path. */
} /* findBinaryInPath */
static char *readSymLink(const char *path)
{
ssize_t len = 64;
ssize_t rc = -1;
char *retval = NULL;
while (1)
{
char *ptr = (char *) allocator.Realloc(retval, (size_t) len);
if (ptr == NULL)
break; /* out of memory. */
retval = ptr;
rc = readlink(path, retval, len);
if (rc == -1)
break; /* not a symlink, i/o error, etc. */
else if (rc < len)
{
retval[rc] = '\0'; /* readlink doesn't null-terminate. */
return retval; /* we're good to go. */
} /* else if */
len *= 2; /* grow buffer, try again. */
} /* while */
if (retval != NULL)
allocator.Free(retval);
return NULL;
} /* readSymLink */
char *__PHYSFS_platformCalcBaseDir(const char *argv0)
{
char *retval = NULL;
char *envr = NULL;
/* fast path: default behaviour can handle this. */
if ( (argv0 != NULL) && (strchr(argv0, '/') != NULL) )
return(NULL); /* higher level will parse out real path from argv0. */
/*
* Try to avoid using argv0 unless forced to. If there's a Linux-like
* /proc filesystem, you can get the full path to the current process from
* the /proc/self/exe symlink.
*/
retval = readSymLink("/proc/self/exe");
if (retval == NULL)
{
/* older kernels don't have /proc/self ... try PID version... */
const unsigned long long pid = (unsigned long long) getpid();
char path[64];
const int rc = (int) snprintf(path,sizeof(path),"/proc/%llu/exe",pid);
if ( (rc > 0) && (rc < sizeof(path)) )
retval = readSymLink(path);
} /* if */
if (retval != NULL) /* chop off filename. */
{
char *ptr = strrchr(retval, '/');
if (ptr != NULL)
*ptr = '\0';
} /* if */
if ((retval == NULL) && (argv0 != NULL))
{
/* If there's no dirsep on argv0, then look through $PATH for it. */
envr = __PHYSFS_platformCopyEnvironmentVariable("PATH");
BAIL_IF_MACRO(!envr, NULL, NULL);
retval = findBinaryInPath(argv0, envr);
allocator.Free(envr);
} /* if */
if (retval != NULL)
{
/* try to shrink buffer... */
char *ptr = (char *) allocator.Realloc(retval, strlen(retval) + 1);
if (ptr != NULL)
retval = ptr; /* oh well if it failed. */
} /* if */
return(retval);
} /* __PHYSFS_platformCalcBaseDir */
char *__PHYSFS_platformRealPath(const char *path)
{
char resolved_path[MAXPATHLEN];
char *retval = NULL;
errno = 0;
BAIL_IF_MACRO(!realpath(path, resolved_path), strerror(errno), NULL);
retval = (char *) allocator.Malloc(strlen(resolved_path) + 1);
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
strcpy(retval, resolved_path);
return(retval);
} /* __PHYSFS_platformRealPath */
char *__PHYSFS_platformCurrentDir(void)
{
/*
* This can't just do platformRealPath("."), since that would eventually
* just end up calling back into here.
*/
int allocSize = 0;
char *retval = NULL;
char *ptr;
do
{
allocSize += 100;
ptr = (char *) allocator.Realloc(retval, allocSize);
if (ptr == NULL)
{
if (retval != NULL)
allocator.Free(retval);
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
} /* if */
retval = ptr;
ptr = getcwd(retval, allocSize);
} while (ptr == NULL && errno == ERANGE);
if (ptr == NULL && errno)
{
/*
* getcwd() failed for some reason, for example current
* directory not existing.
*/
if (retval != NULL)
allocator.Free(retval);
BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
} /* if */
return(retval);
} /* __PHYSFS_platformCurrentDir */
int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
{
return(0); /* just use malloc() and friends. */
} /* __PHYSFS_platformSetDefaultAllocator */
#if (defined PHYSFS_NO_THREAD_SUPPORT)
PHYSFS_uint64 __PHYSFS_platformGetThreadID(void) { return(0x0001); }
void *__PHYSFS_platformCreateMutex(void) { return((void *) 0x0001); }
void __PHYSFS_platformDestroyMutex(void *mutex) {}
int __PHYSFS_platformGrabMutex(void *mutex) { return(1); }
void __PHYSFS_platformReleaseMutex(void *mutex) {}
#else
typedef struct
{
pthread_mutex_t mutex;
pthread_t owner;
PHYSFS_uint32 count;
} PthreadMutex;
/* Just in case; this is a panic value. */
#if ((!defined SIZEOF_INT) || (SIZEOF_INT <= 0))
# define SIZEOF_INT 4
#endif
#if (SIZEOF_INT == 4)
# define PHTREAD_TO_UI64(thr) ( (PHYSFS_uint64) ((PHYSFS_uint32) (thr)) )
#elif (SIZEOF_INT == 2)
# define PHTREAD_TO_UI64(thr) ( (PHYSFS_uint64) ((PHYSFS_uint16) (thr)) )
#elif (SIZEOF_INT == 1)
# define PHTREAD_TO_UI64(thr) ( (PHYSFS_uint64) ((PHYSFS_uint8) (thr)) )
#else
# define PHTREAD_TO_UI64(thr) ((PHYSFS_uint64) (thr))
#endif
PHYSFS_uint64 __PHYSFS_platformGetThreadID(void)
{
return(PHTREAD_TO_UI64(pthread_self()));
} /* __PHYSFS_platformGetThreadID */
void *__PHYSFS_platformCreateMutex(void)
{
int rc;
PthreadMutex *m = (PthreadMutex *) allocator.Malloc(sizeof (PthreadMutex));
BAIL_IF_MACRO(m == NULL, ERR_OUT_OF_MEMORY, NULL);
rc = pthread_mutex_init(&m->mutex, NULL);
if (rc != 0)
{
allocator.Free(m);
BAIL_MACRO(strerror(rc), NULL);
} /* if */
m->count = 0;
m->owner = (pthread_t) 0xDEADBEEF;
return((void *) m);
} /* __PHYSFS_platformCreateMutex */
void __PHYSFS_platformDestroyMutex(void *mutex)
{
PthreadMutex *m = (PthreadMutex *) mutex;
/* Destroying a locked mutex is a bug, but we'll try to be helpful. */
if ((m->owner == pthread_self()) && (m->count > 0))
pthread_mutex_unlock(&m->mutex);
pthread_mutex_destroy(&m->mutex);
allocator.Free(m);
} /* __PHYSFS_platformDestroyMutex */
int __PHYSFS_platformGrabMutex(void *mutex)
{
PthreadMutex *m = (PthreadMutex *) mutex;
pthread_t tid = pthread_self();
if (m->owner != tid)
{
if (pthread_mutex_lock(&m->mutex) != 0)
return(0);
m->owner = tid;
} /* if */
m->count++;
return(1);
} /* __PHYSFS_platformGrabMutex */
void __PHYSFS_platformReleaseMutex(void *mutex)
{
PthreadMutex *m = (PthreadMutex *) mutex;
if (m->owner == pthread_self())
{
if (--m->count == 0)
{
m->owner = (pthread_t) 0xDEADBEEF;
pthread_mutex_unlock(&m->mutex);
} /* if */
} /* if */
} /* __PHYSFS_platformReleaseMutex */
#endif /* !PHYSFS_NO_THREAD_SUPPORT */
#endif /* PHYSFS_PLATFORM_UNIX */
/* end of unix.c ... */

File diff suppressed because it is too large Load Diff