Compare commits

..

97 Commits

Author SHA1 Message Date
Ryan C. Gordon 9266e773d3
unix: Better base dir calculation for Solaris.
This idea came from https://github.com/libsdl-org/SDL/pull/6681 (thanks!)
2022-11-27 21:45:11 -05:00
Ryan C. Gordon fdd38a3f8a
Bumped main branch to to 3.2.0!
(This will, hopefully, become PhysicsFS 4.0, eventually.)
2022-09-30 16:14:24 -04:00
Ryan C. Gordon 6a7625cd77 apple: macOS 12.0 deprecated things called "master" for "main".
Try to look for the new name in the process's namespace before falling back
to the old one (and giving up on CD-ROM detection if everything falls apart).

iOS has PHYSFS_NO_CDROM_SUPPORT defined, so this isn't used there.
2022-09-29 14:13:33 -04:00
Ozkan Sezer 49662cd826 minor update to endian macros from SDL. 2022-09-29 18:55:04 +03:00
Ryan C. Gordon 4d9bcc3d1a
atomic: __PHYSFS_ATOMIC_(DECR|INCR) should return final value.
Fixes #46.
2022-09-29 10:53:18 -04:00
Ryan C. Gordon 496817a9e8
PHYSFS_mkdir() should allow symlinks in the mounted writeDir itself.
Fixes #47.
2022-09-29 10:27:23 -04:00
Ozkan Sezer 0d4e9aac45 silenced a -Wunused-but-set-variable warning. 2022-06-16 14:55:50 +03:00
Ozkan Sezer 65195f9c1a define MINIZ_LITTLE_ENDIAN based on PHYSFS_BYTEORDER. 2022-06-15 23:10:00 +03:00
Ozkan Sezer fb0901b10f silence a -Wint-in-bool-context warning:
In file included from /home/runner/work/physfs/physfs/src/physfs.c:12:
/home/runner/work/physfs/physfs/src/physfs.c: In function ‘openDirectory’:
/home/runner/work/physfs/physfs/src/physfs.c:929:40: warning: ?: using integer constants in boolean context [-Wint-in-bool-context]
  929 |     BAIL_IF(!retval, claimed ? errcode : PHYSFS_ERR_UNSUPPORTED, NULL);
      |                      ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
/home/runner/work/physfs/physfs/src/physfs_internal.h:273:44: note: in definition of macro ‘BAIL_IF’
  273 | #define BAIL_IF(c, e, r) do { if (c) { if (e) PHYSFS_setErrorCode(e); return r; } } while (0)
      |                                            ^

Closes https://github.com/icculus/physfs/issues/44
2022-06-15 20:56:28 +03:00
Ryan C. Gordon f0c7367b0f
Update endian detection from latest in SDL2.
Fixes #43.
2022-06-15 13:54:21 -04:00
Ozkan Sezer e32221a104 cmake: add -Wall to CFLAGS for gcc and clang. 2022-06-15 08:56:28 +03:00
Ozkan Sezer cfbbb255a2 minor warning fixes 2022-06-15 08:56:02 +03:00
Anonymous Maarten 2a90b1f469 cmake: collapse MSVC and MINGW into WIN32 2022-06-15 08:29:50 +03:00
Anonymous Maarten 88ef84c053 Make sure `pthread is not linked against when building with MinGW
Co-authored-by: Ryan C. Gordon <icculus@icculus.org>
2022-06-15 08:29:50 +03:00
Anonymous Maarten 9bc66b6469 add Windows CI 2022-06-15 08:29:50 +03:00
Anonymous Maarten aabb732caf cmake: fix warnings + use target_include_directories 2022-06-15 08:29:50 +03:00
Ryan C. Gordon 6925c1067d
Bumped copyright for 2022. 2022-05-20 23:27:26 -04:00
Ryan C. Gordon 64807353df
cmake: Don't try to use readline if you don't also have curses.
Fixes #17.
2022-05-20 23:19:41 -04:00
Ryan C. Gordon ed4ab15524
zip: workaround Windows Explorer bug.
If you edit a zip file with Windows Explorer, it will rewrite the entire
central directory, setting all files version_needed field to 2.0/MS-DOS,
but it won't touch files that it doesn't plan to alter, so you might end
up with a local header that doesn't match the central directory details.

We aren't currently using the version_needed information, so now we just
favor the local header's copy of it in case we ever need it, and don't
complain if the central directory doesn't match.

Fixes #24.
2022-05-20 22:22:55 -04:00
Ryan C. Gordon 48e7c2e3af
root: Fix string handling of paths from PHYSFS_setRoot.
Fixes #4.
2022-05-20 22:06:33 -04:00
Ryan C. Gordon 497934818b
Fixed memory leak when closing a DirHandle with a root (thanks, jajiradai!).
Fixes #3.
2022-05-20 21:27:46 -04:00
Ryan C. Gordon 17b691b0ea
Let several archives be case-insensitive.
(and several more probably _should_ be but I don't have the details on
them at the moment. But now it's just changing a 1 to a 0 to fix those!)
2022-05-20 17:36:06 -04:00
Ozkan Sezer 14691399cd disable dllexport from static builds.
Closes https://github.com/icculus/physfs/pull/15 .
2022-04-16 20:10:02 +03:00
Ozkan Sezer 20e90ed3c4 fix wording in os2.yml 2022-04-16 20:08:20 +03:00
Ozkan Sezer eec3f7f79a cmake: set os2 dll name to 'physfs'
not libphysfs, because of os2 limitation.
2022-04-16 11:42:50 -04:00
Ryan C. Gordon 3a3c552e50
ci: Fix OS/2 building.
Copy and pasted from SDL a little too quickly.  :)
2022-04-16 11:30:19 -04:00
Ryan C. Gordon b975bb679b
ci: Wire up OS/2 builds to GitHub Actions. 2022-04-16 11:24:53 -04:00
Ozkan Sezer 0ae9467685 physfs_platform_os2.c: eliminated signedness warnings. 2022-04-16 10:52:01 -04:00
Ozkan Sezer cd2e055454 added __PHYSFS_ATOMIC_INCR and __PHYSFS_ATOMIC_DECR for watcom compiler 2022-04-16 10:52:01 -04:00
Ozkan Sezer 141dccb087 added a watcom makefile targeting os2 2022-04-16 10:52:01 -04:00
Ozkan Sezer 3abe069870 fixed os2 symbol exports 2022-04-16 10:52:01 -04:00
Ozkan Sezer 02b6a7f084 fixed windows symbol exports 2022-04-16 10:52:01 -04:00
Ryan C. Gordon 045ee2cb7f
cmake: Moved the install stuff around a little. 2022-04-15 20:45:21 -04:00
Ryan C. Gordon a329a35993
cmake: Don't use the oldschool `endif(SAME_THING_AS_IF_LINE)` syntax. 2022-04-15 20:39:39 -04:00
Semphris 7305ee92a2 Added option to disable the installer 2022-04-15 20:25:10 -04:00
past-due a0dfe220ff physfs_platform_windows.c: Use newer APIs when permitted by _WIN32_WINNT 2021-10-16 10:30:47 -04:00
alfadur b3cca6a026 add 0x10000 properly 2021-09-10 10:01:31 -04:00
alfadur 8eab55d173 add missing bit to UTF-16 surrogate pair conversion 2021-09-10 10:01:31 -04:00
Arthur Brianville (Ybalrid) 23690f316d Add option to turn off the build of the documentation if Doxygen was found 2021-09-02 22:15:03 -04:00
pastdue b8fa8fdcac physfs_platform_posix.c: Use O_CLOEXEC / FD_CLOEXEC 2021-07-12 11:52:35 -04:00
pastdue a9cb20772b physfs_platform_posix.c: Retry on EINTR 2021-07-12 11:52:35 -04:00
James Le Cuirot d8ba1a935c Use the GNUInstallDirs CMake module to respect installation locations
Apparently use of LIB_SUFFIX is now discouraged. GNUInstallDirs does a
better job of setting a default.

The libdir of ${prefix}/lib in the pkg-config file caused warnings,
and possibly even failures, when linking on multilib systems where
/usr/lib is for 32-bit libraries rather than 64-bit libraries.
2021-07-11 19:00:28 -04:00
Ryan C. Gordon 0145431345
cmake: fixed "dist" target to use git instead of Mercurial. 2021-06-30 23:53:21 -04:00
Ryan C. Gordon b7410d673e
Updated a URL to point to github.com 2021-06-30 23:39:12 -04:00
Ryan C. Gordon fdf308fa88
Renamed .hgignore -> .gitignore 2021-06-30 23:32:32 -04:00
Matthew Albrecht d24ce15922 Include alloca.h on Solaris and Linux platforms. 2021-06-30 08:52:57 -04:00
Ryan C. Gordon 69a7428787
Initial CI setup... 2021-06-29 13:22:39 -04:00
Ryan C. Gordon ebe02ceb02
Create FUNDING.yml 2021-06-29 13:20:53 -04:00
Ryan C. Gordon 9b83066716
Reformat LICENSE.txt so GitHub sees it as zlib. 2021-06-29 13:19:59 -04:00
Ryan C. Gordon 13f00546a9
Bumped copyright for 2021. 2021-06-29 13:18:47 -04:00
Ryan C. Gordon 5ea6ba7557 msvc: Move stdarg.h include ahead of __PHYSFS_msvc_vsnprintf declaration. 2021-04-29 15:00:16 -04:00
Ryan C. Gordon 009be5ab20 Enable arm64 for non-Windows targets (thanks, pastdue!).
Co-authored-by: Victor Romero <romerosanchezv@gmail.com>
2021-01-18 18:33:00 -05:00
Ryan C. Gordon 55c3d9f9d8 android: PhysicsFS now has actual Android support.
This compiled and worked on Android before, if you didn't care about
PHYSFS_getBaseDir() and PHYSFS_getPrefDir() being useful. Now you can pass
PHYSFS_init() some necessary Android objects to solve this. Passing NULL
to PHYSFS_init is acceptable and will simply report "/" for the base dir and
prefdir, under the assumption that the app queried the OS for these directly
instead.
2020-06-12 03:37:58 -04:00
Ryan C. Gordon 22297e7ea2 7z: Make error handling a little more robust. 2020-05-17 01:41:52 -04:00
Ryan C. Gordon 00599b7dac 7z: copy/paste error in error checking, found by static analysis.
This was clearly copied from a previous line but wasn't updated with the
correct condition to check, so if malloc() failed, it would dereference NULL
instead of reporting an error.
2020-05-17 01:26:31 -04:00
Ryan C. Gordon 3169a5e9d3 buildbot-emscripten.sh: Look for the SDK at /emsdk by default. 2020-05-16 23:30:16 -04:00
Ryan C. Gordon 101ec3c831 buildbot-checker.sh: Just require scan-build to be in the $PATH. 2020-05-16 23:29:44 -04:00
Ryan C. Gordon e3231d1cb0 Modern buildbot vocabulary is "worker," not "slave." 2020-05-16 23:29:03 -04:00
Ryan C. Gordon 9d61fadd3e Have static analysis script use Ninja. 2020-05-12 15:49:53 -04:00
Ryan C. Gordon 235e31c420 Fixed mishandling of an allocation failure in PHYSFS_openRead().
(Static analysis caught this one! Thanks clang!)
2020-05-12 15:19:01 -04:00
Ryan C. Gordon 291cad07b7 Testing a fix for emscripten buildbot script. 2020-05-12 13:49:46 -04:00
Ryan C. Gordon 0d1df744ba Minor style fix in docs/INSTALL.txt 2020-05-12 01:04:09 -04:00
Ryan C. Gordon 08dc47a72b Update copyright for 2020. 2020-05-12 00:52:56 -04:00
Ryan C. Gordon 1daf787fb2 extras: Cleaning up some scripts to work with the newly-recreated buildbot. 2020-05-12 00:32:00 -04:00
Ryan C. Gordon 56aaae4949 Corrected example code for PHYSFS_enumerate in physfs.h 2019-08-24 21:06:54 -04:00
Ryan C. Gordon 19ea59109d Fixed comment typo. 2019-06-07 23:46:55 -04:00
Ryan C. Gordon a8180f0e4c hog: Added support for HOG2 (Descent 3) archives. 2019-06-07 22:27:48 -04:00
Ryan C. Gordon 9cb45dc6cb cmake: Minimum CMake version is now 2.8.12.
(transplanted from de1ea3b2cfc45ce921b5571a637b3b747173184f)
2019-05-20 23:38:12 -04:00
Kevin d'Orange 8791811909 CMake: made install step export the targets 2019-04-19 12:33:08 +02:00
Ryan C. Gordon f94ce0613d Fixed compiler warning. 2019-03-18 14:28:46 -04:00
Ryan C. Gordon 6b0839051f windows: Workaround for WinXP systems.
(transplanted from c8f3bbd689d6b71b84c11db74275ea3d56fef961)
2019-03-18 13:36:16 -04:00
Ryan C. Gordon 5cbb460bcd Only flush file handles on close if they were opened for writing. 2019-03-18 11:27:26 -04:00
Ryan C. Gordon e549fe0e0f Added some whitespace to test a fix to revision control. 2019-02-10 16:00:39 -05:00
Ryan C. Gordon 736d0b371a Updated copyright year for 2019. 2019-02-10 15:56:21 -05:00
Ryan C. Gordon 28ac5794b1 cmake: Special build target names ("dist" "docs" "uninstall") can be renamed. 2019-02-10 15:45:01 -05:00
Ryan C. Gordon 500033f37d Allow builds to opt-out or opt-in to specific archivers, whichever's easier. 2019-01-26 03:00:29 -05:00
Ryan C. Gordon b57d8960e8 Fixed some compiler warnings. 2018-11-28 00:23:08 -05:00
Ryan C. Gordon 5786a58628 PHYSFS_flush() shouldn't call PHYSFS_Io::flush().
The former is meant to send PhysicsFS-buffered data to the PHYSFS_Io's
implementation, the latter is meant to tell the OS to definitely make sure the
data is safely written to disk (or at least, that's what it does in practice).

This was making PHYSFS_setBuffer()'d handles _slower_, since they would end
up blocking whenever the buffer was full until the data made the full trip to
physical media, instead of just letting the OS do its own buffering.

Now we still PHYSFS_Io::flush() on PHYSFS_close(), like this has always
worked. That might also be overkill, but that remains a historical artifact
of trying to keep the underlying file handle usable if pending writes fail
for possibly-recoverable reasons (which isn't guaranteed if you just close()
it, at least as far as I remember).
2018-11-27 23:53:33 -05:00
Ryan C. Gordon 73d66441e3 Added PHYSFS_setRoot(). 2018-10-17 23:44:02 -04:00
Ryan C. Gordon 7d194a8a62 windows: Workaround GetUserProfileDirectory's API change in Win10 build 1809.
(transplanted from ece6769c0676c2d4e8a5893a1acebd0f65456817)
2018-10-03 22:40:57 -04:00
Ryan C. Gordon 8ce294a458 PHYSFS_setWriteDir() shouldn't create an empty file if the dir doesn't exist. 2018-05-16 19:54:51 -04:00
Ryan C. Gordon 15dd00659a Fix up physfs.h for compilers that are sensitive about preprocessor defines.
(transplanted from db8f944df5c56f0244229813203fb5b24e8d9968)
2018-04-19 10:06:38 -04:00
Ryan C. Gordon 7394c07d6b apple: Patched to compile with older (mac 10.7) SDKs (thanks, Ken and Ryan!). 2018-03-24 00:19:59 -04:00
Ryan C. Gordon 0bad12d401 ignorecase: Don't crash if enumeration returned a NULL pointer.
(transplanted from f83d05e87212a5c7e377f3b205e6d70fc42772d4)
2018-03-09 14:50:37 -05:00
Ryan C. Gordon 89d4809f28 Updated copyright date. 2018-03-08 12:21:45 -05:00
Ryan C. Gordon ea90a92016 7zip: don't forget to destroy the PHYSFS_Io when closing the archive! 2018-03-08 11:47:42 -05:00
Ryan C. Gordon 3597a7b69a Call the default branch "3.1.0" to avoid confusion.
This way, if someone builds the default branch instead of stable-3.0, we'll
be able to distinguish.

No immediate plans for a format 3.1 effort at the moment, though.
2018-03-08 11:51:46 -05:00
Ryan C. Gordon c86895264b Remove deprecated PHYSFS_getLastError() from all the extras (thanks, Rob!). 2018-02-20 10:26:33 -05:00
Ryan C. Gordon 47b0e834dc Patched physfsrwops to compile against SDL 1.2 (thanks, Rob!).
(transplanted from 540be489d50f9fe29f1f517202b6a9d199f36a2a)
2017-11-11 08:53:23 -05:00
Ryan C. Gordon 90dfc49f6d Added tag release-3.0.1 for changeset fa8e38bcc354 2017-10-26 14:38:35 -04:00
Ryan C. Gordon a45afc5d50 Catch access to paths that are just "." or ".." without any path separator. 2017-10-26 14:37:16 -04:00
Ryan C. Gordon 62d24e228f Fixed mounting a symlink to a real directory. 2017-10-26 14:21:36 -04:00
Ryan C. Gordon 26db9376da Fixed some infinite loops that a maliciously-crafted .iso can trigger.
These bugs exposed by American Fuzzy Lop (AFL), a powerful fuzzer.

http://lcamtuf.coredump.cx/afl/
2017-10-23 14:58:54 -04:00
Ryan C. Gordon 1c7945461d Don't allow NULL filenames to be mounted.
Regardless of what the 3.0.0 documentation says, PhysicsFS never handled this
correctly, so now we check for it so you can't get into crashy situations.

Corrected documentation to reflect reality.
2017-10-23 12:40:59 -04:00
Ryan C. Gordon f5e5b586c7 Fixed crash when duplicating PHYSFS_Io for zipfiles. 2017-10-23 12:16:51 -04:00
Ryan C. Gordon fbb8ce7e2d Added some notes on API documentation. 2017-09-27 16:13:00 -04:00
Ryan C. Gordon 347bb7b6c8 Tagging 3.0.0 release 2017-09-27 15:58:44 -04:00
43 changed files with 1086 additions and 428 deletions

2
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,2 @@
github: [icculus]
patreon: icculus

30
.github/workflows/main.yml vendored Normal file
View File

@ -0,0 +1,30 @@
name: Build
on: [push, pull_request]
jobs:
Build:
name: ${{ matrix.platform.name }}
runs-on: ${{ matrix.platform.os }}
strategy:
matrix:
platform: # !!! FIXME: figure out an efficient way to get SDL2 on the Windows/Mac bots.
- { name: Linux, os: ubuntu-20.04, flags: -GNinja }
- { name: MinGW, os: windows-latest, flags: -GNinja -DCMAKE_C_COMPILER=x86_64-w64-mingw32-gcc -DCMAKE_SYSTEM_NAME=Windows }
- { name: Windows, os: windows-latest }
- { name: MacOS, os: macos-latest }
steps:
- name: Setup Linux dependencies
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install ninja-build
- name: Setup MinGW dependencies
if: contains(matrix.platform.name, 'MinGW')
run: choco install ninja
- name: Get PhysicsFS sources
uses: actions/checkout@v2
- name: Configure CMake
run: cmake -B build ${{ matrix.platform.flags }}
- name: Build
run: cmake --build build/

20
.github/workflows/os2.yml vendored Normal file
View File

@ -0,0 +1,20 @@
name: Build (OS/2)
on: [push, pull_request]
jobs:
os2:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: open-watcom/setup-watcom@v0
- name: Build physfs.dll
run: |
cd src
wmake -f Makefile.os2
cd ..
- name: distclean
run: |
cd src
wmake -f Makefile.os2 distclean
cd ..

View File

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

View File

@ -9,27 +9,29 @@
# compile, using preprocessor checks for platform-specific bits instead of # compile, using preprocessor checks for platform-specific bits instead of
# testing in here. # testing in here.
cmake_minimum_required(VERSION 2.8.4) set(PHYSFS_VERSION 3.3.0)
project(PhysicsFS) cmake_minimum_required(VERSION 3.0)
set(PHYSFS_VERSION 3.0.2)
project(PhysicsFS VERSION ${PHYSFS_VERSION} LANGUAGES C )
include(GNUInstallDirs)
# Increment this if/when we break backwards compatibility. # Increment this if/when we break backwards compatibility.
set(PHYSFS_SOVERSION 1) set(PHYSFS_SOVERSION 1)
# I hate that they define "WIN32" ... we're about to move to Win64...I hope! set(PHYSFS_M_SRCS)
if(WIN32 AND NOT WINDOWS) set(PHYSFS_CPP_SRCS)
set(WINDOWS TRUE)
endif()
include_directories(./src) # I hate that they define "WIN32" ... we're about to move to Win64...I hope!
if(APPLE) if(APPLE)
set(OTHER_LDFLAGS ${OTHER_LDFLAGS} "-framework IOKit -framework Foundation") set(OTHER_LDFLAGS ${OTHER_LDFLAGS} "-framework IOKit -framework Foundation")
set(PHYSFS_M_SRCS src/physfs_platform_apple.m) list(APPEND PHYSFS_M_SRCS src/physfs_platform_apple.m)
endif() endif()
if(CMAKE_COMPILER_IS_GNUCC) if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall)
# Don't use -rpath. # Don't use -rpath.
set(CMAKE_SKIP_RPATH ON CACHE BOOL "Skip RPATH" FORCE) set(CMAKE_SKIP_RPATH ON CACHE BOOL "Skip RPATH" FORCE)
endif() endif()
@ -42,10 +44,10 @@ endif()
if(HAIKU) if(HAIKU)
# We add this explicitly, since we don't want CMake to think this # We add this explicitly, since we don't want CMake to think this
# is a C++ project unless we're on Haiku. # is a C++ project unless we're on Haiku.
set(PHYSFS_CPP_SRCS src/physfs_platform_haiku.cpp) list(APPEND PHYSFS_CPP_SRCS src/physfs_platform_haiku.cpp)
find_library(BE_LIBRARY be) find_library(BE_LIBRARY be)
find_library(ROOT_LIBRARY root) find_library(ROOT_LIBRARY root)
set(OPTIONAL_LIBRARY_LIBS ${OPTIONAL_LIBRARY_LIBS} ${BE_LIBRARY} ${ROOT_LIBRARY}) list(APPEND OPTIONAL_LIBRARY_LIBS ${BE_LIBRARY} ${ROOT_LIBRARY})
endif() endif()
if(CMAKE_SYSTEM_NAME STREQUAL "WindowsPhone" OR CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") if(CMAKE_SYSTEM_NAME STREQUAL "WindowsPhone" OR CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
@ -53,16 +55,20 @@ if(CMAKE_SYSTEM_NAME STREQUAL "WindowsPhone" OR CMAKE_SYSTEM_NAME STREQUAL "Wind
endif() endif()
if(WINRT) if(WINRT)
set(PHYSFS_CPP_SRCS src/physfs_platform_winrt.cpp) list(APPEND PHYSFS_CPP_SRCS src/physfs_platform_winrt.cpp)
endif() endif()
if(UNIX AND NOT WINDOWS AND NOT APPLE) # (MingW and such might be UNIX _and_ WINDOWS!) if(UNIX AND NOT WIN32 AND NOT APPLE) # (MingW and such might be UNIX _and_ WINDOWS!)
find_library(PTHREAD_LIBRARY pthread) find_library(PTHREAD_LIBRARY pthread)
if(PTHREAD_LIBRARY) if(PTHREAD_LIBRARY)
set(OPTIONAL_LIBRARY_LIBS ${OPTIONAL_LIBRARY_LIBS} ${PTHREAD_LIBRARY}) set(OPTIONAL_LIBRARY_LIBS ${OPTIONAL_LIBRARY_LIBS} ${PTHREAD_LIBRARY})
endif() endif()
endif() endif()
if(PHYSFS_CPP_SRCS)
enable_language(CXX)
endif()
# Almost everything is "compiled" here, but things that don't apply to the # 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 # 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 # another project or bring up a new build system: just compile all the source
@ -76,6 +82,7 @@ set(PHYSFS_SRCS
src/physfs_platform_windows.c src/physfs_platform_windows.c
src/physfs_platform_os2.c src/physfs_platform_os2.c
src/physfs_platform_qnx.c src/physfs_platform_qnx.c
src/physfs_platform_android.c
src/physfs_archiver_dir.c src/physfs_archiver_dir.c
src/physfs_archiver_unpacked.c src/physfs_archiver_unpacked.c
src/physfs_archiver_grp.c src/physfs_archiver_grp.c
@ -151,6 +158,8 @@ endif()
option(PHYSFS_BUILD_STATIC "Build static library" TRUE) option(PHYSFS_BUILD_STATIC "Build static library" TRUE)
if(PHYSFS_BUILD_STATIC) if(PHYSFS_BUILD_STATIC)
add_library(physfs-static STATIC ${PHYSFS_SRCS}) add_library(physfs-static STATIC ${PHYSFS_SRCS})
add_library(PhysFS::PhysFS-static ALIAS physfs-static)
set_target_properties(physfs-static PROPERTIES EXPORT_NAME PhysFS-static)
# Don't rename this on Windows, since DLLs will also produce an import # Don't rename this on Windows, since DLLs will also produce an import
# library named "physfs.lib" which would conflict; Unix tend to like the # library named "physfs.lib" which would conflict; Unix tend to like the
# same library name with a different extension for static libs, but # same library name with a different extension for static libs, but
@ -163,23 +172,34 @@ if(PHYSFS_BUILD_STATIC)
set_target_properties(physfs-static PROPERTIES VS_WINRT_COMPONENT True) set_target_properties(physfs-static PROPERTIES VS_WINRT_COMPONENT True)
set_target_properties(physfs-static PROPERTIES STATIC_LIBRARY_FLAGS "/ignore:4264") set_target_properties(physfs-static PROPERTIES STATIC_LIBRARY_FLAGS "/ignore:4264")
endif() endif()
if(WIN32 OR WINRT OR OS2)
# no dll exports from the static library
target_compile_definitions(physfs-static PRIVATE "PHYSFS_STATIC")
endif()
target_include_directories(physfs-static PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>")
target_link_libraries(physfs-static PRIVATE ${OPTIONAL_LIBRARY_LIBS} ${OTHER_LDFLAGS})
set(PHYSFS_LIB_TARGET physfs-static) set(PHYSFS_LIB_TARGET physfs-static)
set(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";physfs-static") list(APPEND PHYSFS_INSTALL_TARGETS "physfs-static")
endif() endif()
option(PHYSFS_BUILD_SHARED "Build shared library" TRUE) option(PHYSFS_BUILD_SHARED "Build shared library" TRUE)
if(PHYSFS_BUILD_SHARED) if(PHYSFS_BUILD_SHARED)
add_library(physfs SHARED ${PHYSFS_SRCS}) add_library(physfs SHARED ${PHYSFS_SRCS})
add_library(PhysFS::PhysFS ALIAS physfs)
set_target_properties(physfs PROPERTIES MACOSX_RPATH 1) set_target_properties(physfs PROPERTIES MACOSX_RPATH 1)
set_target_properties(physfs PROPERTIES VERSION ${PHYSFS_VERSION}) set_target_properties(physfs PROPERTIES VERSION ${PHYSFS_VERSION})
set_target_properties(physfs PROPERTIES SOVERSION ${PHYSFS_SOVERSION}) set_target_properties(physfs PROPERTIES SOVERSION ${PHYSFS_SOVERSION})
set_target_properties(physfs PROPERTIES EXPORT_NAME PhysFS)
if(WINRT) if(WINRT)
set_target_properties(physfs PROPERTIES VS_WINRT_COMPONENT True) set_target_properties(physfs PROPERTIES VS_WINRT_COMPONENT True)
endif() endif()
target_link_libraries(physfs ${OPTIONAL_LIBRARY_LIBS} ${OTHER_LDFLAGS}) if(OS2) # OS/2 does not support a DLL name longer than 8 characters.
set_target_properties(physfs PROPERTIES OUTPUT_NAME "physfs")
endif()
target_include_directories(physfs PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>")
target_link_libraries(physfs PRIVATE ${OPTIONAL_LIBRARY_LIBS} ${OTHER_LDFLAGS})
set(PHYSFS_LIB_TARGET physfs) set(PHYSFS_LIB_TARGET physfs)
set(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";physfs") list(APPEND PHYSFS_INSTALL_TARGETS "physfs")
endif() endif()
if(NOT PHYSFS_BUILD_SHARED AND NOT PHYSFS_BUILD_STATIC) if(NOT PHYSFS_BUILD_SHARED AND NOT PHYSFS_BUILD_STATIC)
@ -187,7 +207,7 @@ if(NOT PHYSFS_BUILD_SHARED AND NOT PHYSFS_BUILD_STATIC)
endif() endif()
# CMake FAQ says I need this... # CMake FAQ says I need this...
if(PHYSFS_BUILD_SHARED AND PHYSFS_BUILD_STATIC AND NOT WINDOWS) if(PHYSFS_BUILD_SHARED AND PHYSFS_BUILD_STATIC AND NOT WIN32)
set_target_properties(physfs PROPERTIES CLEAN_DIRECT_OUTPUT 1) set_target_properties(physfs PROPERTIES CLEAN_DIRECT_OUTPUT 1)
set_target_properties(physfs-static PROPERTIES CLEAN_DIRECT_OUTPUT 1) set_target_properties(physfs-static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
endif() endif()
@ -199,26 +219,54 @@ if(PHYSFS_BUILD_TEST)
find_path(HISTORY_H readline/history.h) find_path(HISTORY_H readline/history.h)
if(READLINE_H AND HISTORY_H) if(READLINE_H AND HISTORY_H)
find_library(CURSES_LIBRARY NAMES curses ncurses) find_library(CURSES_LIBRARY NAMES curses ncurses)
if(CURSES_LIBRARY)
set(CMAKE_REQUIRED_LIBRARIES ${CURSES_LIBRARY}) set(CMAKE_REQUIRED_LIBRARIES ${CURSES_LIBRARY})
find_library(READLINE_LIBRARY readline) find_library(READLINE_LIBRARY readline)
if(READLINE_LIBRARY) if(READLINE_LIBRARY)
set(HAVE_SYSTEM_READLINE TRUE) set(HAVE_SYSTEM_READLINE TRUE)
set(TEST_PHYSFS_LIBS ${TEST_PHYSFS_LIBS} ${READLINE_LIBRARY} ${CURSES_LIBRARY}) list(APPEND TEST_PHYSFS_LIBS ${READLINE_LIBRARY} ${CURSES_LIBRARY})
include_directories(SYSTEM ${READLINE_H} ${HISTORY_H}) include_directories(SYSTEM ${READLINE_H} ${HISTORY_H})
add_definitions(-DPHYSFS_HAVE_READLINE=1) add_definitions(-DPHYSFS_HAVE_READLINE=1)
endif() endif()
endif() endif()
endif()
add_executable(test_physfs test/test_physfs.c) add_executable(test_physfs test/test_physfs.c)
target_link_libraries(test_physfs ${PHYSFS_LIB_TARGET} ${TEST_PHYSFS_LIBS} ${OTHER_LDFLAGS}) target_link_libraries(test_physfs PRIVATE ${PHYSFS_LIB_TARGET} ${TEST_PHYSFS_LIBS} ${OTHER_LDFLAGS})
set(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";test_physfs") list(APPEND PHYSFS_INSTALL_TARGETS test_physfs)
endif() endif()
install(TARGETS ${PHYSFS_INSTALL_TARGETS} option(PHYSFS_DISABLE_INSTALL "Disable installing PhysFS" OFF)
RUNTIME DESTINATION bin if(NOT PHYSFS_DISABLE_INSTALL)
LIBRARY DESTINATION lib${LIB_SUFFIX}
ARCHIVE DESTINATION lib${LIB_SUFFIX})
install(FILES src/physfs.h DESTINATION include)
install(TARGETS ${PHYSFS_INSTALL_TARGETS} EXPORT PhysFSExport
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(FILES src/physfs.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(EXPORT PhysFSExport
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/PhysFS"
FILE PhysFSConfig.cmake
NAMESPACE PhysFS::
)
if(NOT MSVC)
configure_file(
"extras/physfs.pc.in"
"extras/physfs.pc"
@ONLY
)
install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/extras/physfs.pc"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig"
)
endif()
endif()
option(PHYSFS_BUILD_DOCS "Build doxygen based documentation" TRUE)
if(PHYSFS_BUILD_DOCS)
find_package(Doxygen) find_package(Doxygen)
if(DOXYGEN_FOUND) if(DOXYGEN_FOUND)
set(PHYSFS_OUTPUT_DOXYFILE "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile") set(PHYSFS_OUTPUT_DOXYFILE "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile")
@ -233,23 +281,26 @@ if(DOXYGEN_FOUND)
file(APPEND "${PHYSFS_OUTPUT_DOXYFILE}" "\n# End auto-generated section.\n\n") file(APPEND "${PHYSFS_OUTPUT_DOXYFILE}" "\n# End auto-generated section.\n\n")
set(PHYSFS_TARGETNAME_DOCS "docs" CACHE STRING "Name of 'docs' build target") set(PHYSFS_TARGETNAME_DOCS "docs" CACHE STRING "Name of 'docs' build target")
add_custom_target( add_custom_target(
${PHYSFS_TARGETNAME_DOCS} ${PHYSFS_TARGETNAME_DOCS}
${DOXYGEN_EXECUTABLE} "${PHYSFS_OUTPUT_DOXYFILE}" ${DOXYGEN_EXECUTABLE} "${PHYSFS_OUTPUT_DOXYFILE}"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
COMMENT "Building documentation in 'docs' directory..." COMMENT "Building documentation in 'docs' directory..."
) )
else() else()
message(STATUS "Doxygen not found. You won't be able to build documentation.") message(STATUS "Doxygen not found. You won't be able to build documentation.")
endif() endif()
endif()
if(UNIX) if(UNIX)
set(PHYSFS_TARBALL "${CMAKE_CURRENT_SOURCE_DIR}/../physfs-${PHYSFS_VERSION}.tar.bz2") set(PHYSFS_TARBALL "${CMAKE_CURRENT_SOURCE_DIR}/../physfs-${PHYSFS_VERSION}.tar.gz")
set(PHYSFS_TARGETNAME_DIST "dist" CACHE STRING "Name of 'dist' build target") set(PHYSFS_TARGETNAME_DIST "dist" CACHE STRING "Name of 'dist' build target")
add_custom_target( add_custom_target(
${PHYSFS_TARGETNAME_DIST} ${PHYSFS_TARGETNAME_DIST}
hg archive -t tbz2 "${PHYSFS_TARBALL}" git archive --prefix="physfs-${PHYSFS_VERSION}/" --output="${PHYSFS_TARBALL}" HEAD
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
COMMENT "Building source tarball '${PHYSFS_TARBALL}'..." COMMENT "Building source tarball '${PHYSFS_TARBALL}'..."
) )
@ -263,17 +314,6 @@ if(UNIX)
) )
endif() endif()
if(NOT MSVC)
configure_file(
"extras/physfs.pc.in"
"extras/physfs.pc"
@ONLY
)
install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/extras/physfs.pc"
DESTINATION "lib${LIB_SUFFIX}/pkgconfig"
)
endif()
macro(message_bool_option _NAME _VALUE) macro(message_bool_option _NAME _VALUE)
if(${_VALUE}) if(${_VALUE})
@ -297,9 +337,9 @@ message_bool_option("ISO9660 support" PHYSFS_ARCHIVE_ISO9660)
message_bool_option("Build static library" PHYSFS_BUILD_STATIC) message_bool_option("Build static library" PHYSFS_BUILD_STATIC)
message_bool_option("Build shared library" PHYSFS_BUILD_SHARED) message_bool_option("Build shared library" PHYSFS_BUILD_SHARED)
message_bool_option("Build stdio test program" PHYSFS_BUILD_TEST) message_bool_option("Build stdio test program" PHYSFS_BUILD_TEST)
message_bool_option("Build Doxygen documentation" PHYSFS_BUILD_DOCS)
if(PHYSFS_BUILD_TEST) if(PHYSFS_BUILD_TEST)
message_bool_option(" Use readline in test program" HAVE_SYSTEM_READLINE) message_bool_option(" Use readline in test program" HAVE_SYSTEM_READLINE)
endif() endif()
# end of CMakeLists.txt ... # end of CMakeLists.txt ...

View File

@ -1,23 +1,17 @@
Copyright (c) 2001-2022 Ryan C. Gordon <icculus@icculus.org> and others.
Copyright (c) 2001-2019 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
This software is provided 'as-is', without any express or implied warranty. arising from the use of this software.
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, Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions: freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not 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 claim that you wrote the original software. If you use this software
product, an acknowledgment in the product documentation would be in a product, an acknowledgment in the product documentation would be
appreciated but is not required. appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
Ryan C. Gordon <icculus@icculus.org>

View File

@ -6,6 +6,6 @@ The changelog is no longer maintained by hand. It made sense to have a single
If you want a list of changes, updated in real time, just point your web If you want a list of changes, updated in real time, just point your web
browser here: browser here:
https://hg.icculus.org/icculus/physfs/ https://github.com/icculus/physfs/commits/

View File

@ -37,7 +37,7 @@ If this all worked for your specific project, you can stop reading now.
UNIX: Unix:
You will need CMake (https://www.cmake.org/) 2.4 or later installed. You will need CMake (https://www.cmake.org/) 2.4 or later installed.

View File

@ -1,53 +1,14 @@
#!/bin/bash #!/bin/bash
# This is a script used by some Buildbot buildslaves to push the project # This is a script used by some Buildbot workers to push the project
# through Clang's static analyzer and prepare the output to be uploaded # through Clang's static analyzer and prepare the output to be uploaded
# back to the buildmaster. You might find it useful too. # back to the buildmaster. You might find it useful too.
# Install Clang (you already have it on Mac OS X, apt-get install clang # Install Clang (you already have it on Mac OS X, apt-get install clang
# on Ubuntu, etc), # on Ubuntu, etc), Make sure "scan-build" is in your $PATH.
# or download checker at http://clang-analyzer.llvm.org/ and unpack it in
# /usr/local ... update CHECKERDIR as appropriate.
FINALDIR="$1" FINALDIR="$1"
CHECKERDIR="/usr/local/checker-279"
if [ ! -d "$CHECKERDIR" ]; then
echo "$CHECKERDIR not found. Trying /usr/share/clang ..." 1>&2
CHECKERDIR="/usr/share/clang/scan-build"
fi
if [ ! -d "$CHECKERDIR" ]; then
echo "$CHECKERDIR not found. Giving up." 1>&2
exit 1
fi
if [ -z "$MAKE" ]; then
OSTYPE=`uname -s`
if [ "$OSTYPE" == "Linux" ]; then
NCPU=`cat /proc/cpuinfo |grep vendor_id |wc -l`
let NCPU=$NCPU+1
elif [ "$OSTYPE" = "Darwin" ]; then
NCPU=`sysctl -n hw.ncpu`
elif [ "$OSTYPE" = "SunOS" ]; then
NCPU=`/usr/sbin/psrinfo |wc -l |sed -e 's/^ *//g;s/ *$//g'`
else
NCPU=1
fi
if [ -z "$NCPU" ]; then
NCPU=1
elif [ "$NCPU" = "0" ]; then
NCPU=1
fi
MAKE="make -j$NCPU"
fi
echo "\$MAKE is '$MAKE'"
MAKECMD="$MAKE"
unset MAKE # prevent warnings about jobserver mode.
set -x set -x
set -e set -e
@ -66,13 +27,10 @@ cd checker-buildbot
# The -Wno-liblto is new since our checker-279 upgrade, I think; checker otherwise warns "libLTO.dylib relative to clang installed dir not found" # The -Wno-liblto is new since our checker-279 upgrade, I think; checker otherwise warns "libLTO.dylib relative to clang installed dir not found"
# You might want to do this for CMake-backed builds instead... # You might want to do this for CMake-backed builds instead...
PATH="$CHECKERDIR/bin:$PATH" scan-build -o analysis cmake -Wno-dev -DPHYSFS_BUILD_SHARED=False -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_FLAGS="-Wno-deprecated-declarations" -DCMAKE_EXE_LINKER_FLAGS="-Wno-liblto" .. scan-build -o analysis cmake -G Ninja -Wno-dev -DPHYSFS_BUILD_SHARED=False -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_FLAGS="-Wno-deprecated-declarations" -DCMAKE_EXE_LINKER_FLAGS="-Wno-liblto" ..
# ...or run configure without the scan-build wrapper...
#CC="$CHECKERDIR/libexec/ccc-analyzer" CFLAGS="-O0 -Wno-deprecated-declarations" LDFLAGS="-Wno-liblto" ../configure --enable-assertions=enabled
rm -rf analysis rm -rf analysis
PATH="$CHECKERDIR/bin:$PATH" scan-build -o analysis $MAKECMD scan-build -o analysis cmake --build . --config Debug
if [ `ls -A analysis |wc -l` == 0 ] ; then if [ `ls -A analysis |wc -l` == 0 ] ; then
mkdir analysis/zarro mkdir analysis/zarro

View File

@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
if [ -z "$SDKDIR" ]; then if [ -z "$SDKDIR" ]; then
SDKDIR="/emsdk_portable" SDKDIR="/emsdk"
fi fi
ENVSCRIPT="$SDKDIR/emsdk_env.sh" ENVSCRIPT="$SDKDIR/emsdk_env.sh"
@ -20,32 +20,6 @@ cd `dirname "$0"`
cd .. cd ..
PHYSFSBASE=`pwd` PHYSFSBASE=`pwd`
if [ -z "$MAKE" ]; then
OSTYPE=`uname -s`
if [ "$OSTYPE" == "Linux" ]; then
NCPU=`cat /proc/cpuinfo |grep vendor_id |wc -l`
let NCPU=$NCPU+1
elif [ "$OSTYPE" = "Darwin" ]; then
NCPU=`sysctl -n hw.ncpu`
elif [ "$OSTYPE" = "SunOS" ]; then
NCPU=`/usr/sbin/psrinfo |wc -l |sed -e 's/^ *//g;s/ *$//g'`
else
NCPU=1
fi
if [ -z "$NCPU" ]; then
NCPU=1
elif [ "$NCPU" = "0" ]; then
NCPU=1
fi
MAKE="make -j$NCPU"
fi
echo "\$MAKE is '$MAKE'"
MAKECMD="$MAKE"
unset MAKE # prevent warnings about jobserver mode.
echo "Setting up Emscripten SDK environment..." echo "Setting up Emscripten SDK environment..."
source "$ENVSCRIPT" source "$ENVSCRIPT"
@ -56,10 +30,10 @@ mkdir buildbot
cd buildbot cd buildbot
echo "Configuring..." echo "Configuring..."
emcmake cmake -G "Unix Makefiles" -DPHYSFS_BUILD_SHARED=False -DCMAKE_BUILD_TYPE=MinSizeRel .. || exit $? emcmake cmake -G "Ninja" -DPHYSFS_BUILD_SHARED=False -DCMAKE_BUILD_TYPE=MinSizeRel .. || exit $?
echo "Building..." echo "Building..."
emmake $MAKECMD || exit $? emmake cmake --build . --config MinSizeRel || exit $?
set -e set -e
rm -rf "$TARBALL" physfs-emscripten rm -rf "$TARBALL" physfs-emscripten

View File

@ -15,24 +15,7 @@ if [ -z $1 ]; then
TARBALL=physfs-raspberrypi.tar.xz TARBALL=physfs-raspberrypi.tar.xz
fi fi
OSTYPE=`uname -s` BUILDBOTDIR="buildbot"
if [ "$OSTYPE" != "Linux" ]; then
# !!! FIXME
echo "This only works on x86 or x64-64 Linux at the moment." 1>&2
exit 1
fi
if [ "x$MAKE" == "x" ]; then
NCPU=`cat /proc/cpuinfo |grep vendor_id |wc -l`
let NCPU=$NCPU+1
MAKE="make -j$NCPU"
fi
echo "\$MAKE is '$MAKE'"
MAKECMD="$MAKE"
unset MAKE # prevent warnings about jobserver mode.
BUILDBOTDIR="raspberrypi-buildbot"
PARENTDIR="$PWD" PARENTDIR="$PWD"
set -e set -e
@ -42,8 +25,9 @@ rm -rf $BUILDBOTDIR
mkdir -p $BUILDBOTDIR mkdir -p $BUILDBOTDIR
pushd $BUILDBOTDIR pushd $BUILDBOTDIR
# the '-G "Ninja"' can be '-G "Unix Makefiles"' if you prefer to use GNU Make.
SYSROOT="/opt/rpi-sysroot" SYSROOT="/opt/rpi-sysroot"
cmake -G "Unix Makefiles" \ cmake -G "Ninja" \
-DCMAKE_C_COMPILER="/opt/rpi-tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/arm-linux-gnueabihf-gcc" \ -DCMAKE_C_COMPILER="/opt/rpi-tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/arm-linux-gnueabihf-gcc" \
-DCMAKE_BUILD_TYPE=MinSizeRel \ -DCMAKE_BUILD_TYPE=MinSizeRel \
-DCMAKE_SYSROOT="$SYSROOT" \ -DCMAKE_SYSROOT="$SYSROOT" \
@ -55,7 +39,7 @@ cmake -G "Unix Makefiles" \
-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \ -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \
.. ..
$MAKECMD cmake --build . --config MinSizeRel
rm -rf "$TARBALL" physfs-raspberrypi rm -rf "$TARBALL" physfs-raspberrypi
mkdir -p physfs-raspberrypi mkdir -p physfs-raspberrypi

View File

@ -208,13 +208,13 @@ int main(int argc, char **argv)
if (!PHYSFS_init(argv[0])) if (!PHYSFS_init(argv[0]))
{ {
fprintf(stderr, "PHYSFS_init(): %s\n", PHYSFS_getLastError()); fprintf(stderr, "PHYSFS_init(): %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
return 1; return 1;
} /* if */ } /* if */
if (!PHYSFS_addToSearchPath(".", 1)) if (!PHYSFS_addToSearchPath(".", 1))
{ {
fprintf(stderr, "PHYSFS_addToSearchPath(): %s\n", PHYSFS_getLastError()); fprintf(stderr, "PHYSFS_addToSearchPath(): %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
PHYSFS_deinit(); PHYSFS_deinit();
return 1; return 1;
} /* if */ } /* if */

View File

@ -105,34 +105,34 @@ int main(int argc, char **argv)
if (!PHYSFS_init(argv[0])) if (!PHYSFS_init(argv[0]))
{ {
fprintf(stderr, "PHYSFS_init(): %s\n", PHYSFS_getLastError()); fprintf(stderr, "PHYSFS_init(): %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
return 1; return 1;
} /* if */ } /* if */
if (!PHYSFS_addToSearchPath(".", 1)) if (!PHYSFS_addToSearchPath(".", 1))
{ {
fprintf(stderr, "PHYSFS_addToSearchPath(): %s\n", PHYSFS_getLastError()); fprintf(stderr, "PHYSFS_addToSearchPath(): %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
PHYSFS_deinit(); PHYSFS_deinit();
return 1; return 1;
} /* if */ } /* if */
if (!PHYSFS_setWriteDir(".")) if (!PHYSFS_setWriteDir("."))
{ {
fprintf(stderr, "PHYSFS_setWriteDir(): %s\n", PHYSFS_getLastError()); fprintf(stderr, "PHYSFS_setWriteDir(): %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
PHYSFS_deinit(); PHYSFS_deinit();
return 1; return 1;
} /* if */ } /* if */
if (!PHYSFS_mkdir("/a/b/c")) if (!PHYSFS_mkdir("/a/b/c"))
{ {
fprintf(stderr, "PHYSFS_mkdir(): %s\n", PHYSFS_getLastError()); fprintf(stderr, "PHYSFS_mkdir(): %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
PHYSFS_deinit(); PHYSFS_deinit();
return 1; return 1;
} /* if */ } /* if */
if (!PHYSFS_mkdir("/a/b/C")) if (!PHYSFS_mkdir("/a/b/C"))
{ {
fprintf(stderr, "PHYSFS_mkdir(): %s\n", PHYSFS_getLastError()); fprintf(stderr, "PHYSFS_mkdir(): %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
PHYSFS_deinit(); PHYSFS_deinit();
return 1; return 1;
} /* if */ } /* if */
@ -141,7 +141,7 @@ int main(int argc, char **argv)
PHYSFS_close(f); PHYSFS_close(f);
if (f == NULL) if (f == NULL)
{ {
fprintf(stderr, "PHYSFS_openWrite(): %s\n", PHYSFS_getLastError()); fprintf(stderr, "PHYSFS_openWrite(): %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
PHYSFS_deinit(); PHYSFS_deinit();
return 1; return 1;
} /* if */ } /* if */
@ -150,7 +150,7 @@ int main(int argc, char **argv)
PHYSFS_close(f); PHYSFS_close(f);
if (f == NULL) if (f == NULL)
{ {
fprintf(stderr, "PHYSFS_openWrite(): %s\n", PHYSFS_getLastError()); fprintf(stderr, "PHYSFS_openWrite(): %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
PHYSFS_deinit(); PHYSFS_deinit();
return 1; return 1;
} /* if */ } /* if */

View File

@ -1,7 +1,7 @@
prefix=@CMAKE_INSTALL_PREFIX@ prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix} exec_prefix=@CMAKE_INSTALL_PREFIX@
libdir=${exec_prefix}/lib libdir=@CMAKE_INSTALL_FULL_LIBDIR@
includedir=${prefix}/include includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
Name: PhysicsFS Name: PhysicsFS
Description: PhysicsFS is a library to provide abstract access to various archives. Description: PhysicsFS is a library to provide abstract access to various archives.

View File

@ -70,7 +70,7 @@ static int physfsrwops_seek(SDL_RWops *rw, int offset, int whence)
if (current == -1) if (current == -1)
{ {
SDL_SetError("Can't find position in file: %s", SDL_SetError("Can't find position in file: %s",
PHYSFS_getLastError()); PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
return -1; return -1;
} /* if */ } /* if */
@ -91,7 +91,7 @@ static int physfsrwops_seek(SDL_RWops *rw, int offset, int whence)
const PHYSFS_sint64 len = PHYSFS_fileLength(handle); const PHYSFS_sint64 len = PHYSFS_fileLength(handle);
if (len == -1) if (len == -1)
{ {
SDL_SetError("Can't find end of file: %s", PHYSFS_getLastError()); SDL_SetError("Can't find end of file: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
return -1; return -1;
} /* if */ } /* if */
@ -112,7 +112,7 @@ static int physfsrwops_seek(SDL_RWops *rw, int offset, int whence)
if (!PHYSFS_seek(handle, (PHYSFS_uint64) pos)) if (!PHYSFS_seek(handle, (PHYSFS_uint64) pos))
{ {
SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError()); SDL_SetError("PhysicsFS error: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
return -1; return -1;
} /* if */ } /* if */
@ -138,7 +138,7 @@ static int physfsrwops_read(SDL_RWops *rw, void *ptr, int size, int maxnum)
{ {
if (!PHYSFS_eof(handle)) /* not EOF? Must be an error. */ if (!PHYSFS_eof(handle)) /* not EOF? Must be an error. */
{ {
SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError()); SDL_SetError("PhysicsFS error: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
#if TARGET_SDL2 #if TARGET_SDL2
return 0; return 0;
@ -167,7 +167,7 @@ static int physfsrwops_write(SDL_RWops *rw, const void *ptr, int size, int num)
const PHYSFS_uint64 writelen = (PHYSFS_uint64) (num * size); const PHYSFS_uint64 writelen = (PHYSFS_uint64) (num * size);
const PHYSFS_sint64 rc = PHYSFS_writeBytes(handle, ptr, writelen); const PHYSFS_sint64 rc = PHYSFS_writeBytes(handle, ptr, writelen);
if (rc != ((PHYSFS_sint64) writelen)) if (rc != ((PHYSFS_sint64) writelen))
SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError()); SDL_SetError("PhysicsFS error: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
#if TARGET_SDL2 #if TARGET_SDL2
return (size_t) rc; return (size_t) rc;
@ -182,7 +182,7 @@ static int physfsrwops_close(SDL_RWops *rw)
PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1; PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
if (!PHYSFS_close(handle)) if (!PHYSFS_close(handle))
{ {
SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError()); SDL_SetError("PhysicsFS error: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
return -1; return -1;
} /* if */ } /* if */
@ -196,7 +196,7 @@ static SDL_RWops *create_rwops(PHYSFS_File *handle)
SDL_RWops *retval = NULL; SDL_RWops *retval = NULL;
if (handle == NULL) if (handle == NULL)
SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError()); SDL_SetError("PhysicsFS error: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
else else
{ {
retval = SDL_AllocRW(); retval = SDL_AllocRW();

View File

@ -28,7 +28,7 @@ static void modTimeToStr(PHYSFS_sint64 modtime, char *modstr, size_t strsize)
static void fail(const char *what, const char *why) static void fail(const char *what, const char *why)
{ {
if (why == NULL) if (why == NULL)
why = PHYSFS_getLastError(); why = PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode());
fprintf(stderr, "%s failed: %s\n", what, why); fprintf(stderr, "%s failed: %s\n", what, why);
failure = 1; failure = 1;
} /* fail */ } /* fail */
@ -150,21 +150,21 @@ int main(int argc, char **argv)
if (!PHYSFS_init(argv[0])) if (!PHYSFS_init(argv[0]))
{ {
fprintf(stderr, "PHYSFS_init() failed: %s\n", PHYSFS_getLastError()); fprintf(stderr, "PHYSFS_init() failed: %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
return 2; return 2;
} /* if */ } /* if */
if (!PHYSFS_setWriteDir(argv[2])) if (!PHYSFS_setWriteDir(argv[2]))
{ {
fprintf(stderr, "PHYSFS_setWriteDir('%s') failed: %s\n", fprintf(stderr, "PHYSFS_setWriteDir('%s') failed: %s\n",
argv[2], PHYSFS_getLastError()); argv[2], PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
return 3; return 3;
} /* if */ } /* if */
if (!PHYSFS_mount(argv[1], NULL, 1)) if (!PHYSFS_mount(argv[1], NULL, 1))
{ {
fprintf(stderr, "PHYSFS_mount('%s') failed: %s\n", fprintf(stderr, "PHYSFS_mount('%s') failed: %s\n",
argv[1], PHYSFS_getLastError()); argv[1], PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
return 4; return 4;
} /* if */ } /* if */

View File

@ -40,14 +40,14 @@ int main(int argc, char **argv)
if (!PHYSFS_init(argv[0])) if (!PHYSFS_init(argv[0]))
{ {
printf("PHYSFS_init() failed: %s\n", PHYSFS_getLastError()); printf("PHYSFS_init() failed: %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
return 42; return 42;
} /* if */ } /* if */
rc = PHYSFS_addToSearchPath(argv[0], 0); rc = PHYSFS_addToSearchPath(argv[0], 0);
if (!rc) if (!rc)
{ {
printf("Couldn't find self-extract data: %s\n", PHYSFS_getLastError()); printf("Couldn't find self-extract data: %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
printf("This might mean you didn't append a zipfile to the binary.\n"); printf("This might mean you didn't append a zipfile to the binary.\n");
return 42; return 42;
} /* if */ } /* if */

93
src/Makefile.os2 Normal file
View File

@ -0,0 +1,93 @@
# Open Watcom makefile to build PhysicsFS for OS/2
# wmake -f Makefile.os2
LIBNAME = physfs
VERSION = 3.3.0
LIBFILE = $(LIBNAME).lib
DLLFILE = $(LIBNAME).dll
LNKFILE = $(LIBNAME).lnk
TITLENAME = $(LIBNAME) $(VERSION)
SRCS = physfs.c &
physfs_byteorder.c &
physfs_unicode.c &
physfs_platform_os2.c &
physfs_archiver_dir.c &
physfs_archiver_unpacked.c &
physfs_archiver_grp.c &
physfs_archiver_hog.c &
physfs_archiver_7z.c &
physfs_archiver_mvl.c &
physfs_archiver_qpak.c &
physfs_archiver_wad.c &
physfs_archiver_zip.c &
physfs_archiver_slb.c &
physfs_archiver_iso9660.c &
physfs_archiver_vdf.c
OBJS = $(SRCS:.c=.obj)
CFLAGS_BASE = -bt=os2 -d0 -q -bm -5s -fp5 -fpi87 -sg -oeatxh -ei -j
CFLAGS_BASE+= -DNDEBUG
# warnings:
CFLAGS_BASE+= -wx
# newer OpenWatcom versions enable W303 by default
CFLAGS_BASE+= -wcd=303
# include paths:
CFLAGS_BASE+= -I"$(%WATCOM)/h/os2" -I"$(%WATCOM)/h"
CFLAGS = $(CFLAGS_BASE)
# to build a dll:
CFLAGS+= -bd
.extensions:
.extensions: .lib .dll .obj .c
all: $(DLLFILE) test_physfs.exe
.c: decoders
.c: examples
$(LIBFILE): $(DLLFILE)
@echo * Create library: $@...
wlib -b -n -q -c -pa -s -t -zld -ii -io $@ $(DLLFILE)
$(DLLFILE): $(OBJS) $(MODPLIB) $(TIMILIB) $(LNKFILE)
@echo * Link: $@
wlink @$(LNKFILE)
$(LNKFILE):
@%create $@
@%append $@ SYSTEM os2v2_dll INITINSTANCE TERMINSTANCE
@%append $@ NAME $(LIBNAME)
@for %i in ($(OBJS)) do @%append $@ FILE %i
@%append $@ OPTION QUIET
@%append $@ OPTION DESCRIPTION '@$#icculus org:$(VERSION)$#@PhysicsFS'
@%append $@ OPTION MAP=$^&.map
@%append $@ OPTION ELIMINATE
@%append $@ OPTION MANYAUTODATA
@%append $@ OPTION OSNAME='OS/2 and eComStation'
@%append $@ OPTION SHOWDEAD
.c.obj:
wcc386 $(CFLAGS) -fo=$^@ $<
test_physfs.obj: "../test/test_physfs.c"
wcc386 $(CFLAGS_BASE) -fo=$^@ $<
test_physfs.exe: $(LIBFILE) test_physfs.obj
@echo * Link: $@
wlink SYS os2v2 LIBR {$(LIBFILE)} op q op el F {test_physfs.obj} N test_physfs.exe
clean: .SYMBOLIC
@echo * Clean: $(TITLENAME)
@if exist *.obj rm *.obj
@if exist *.err rm *.err
@if exist $(LNKFILE) rm $(LNKFILE)
distclean: .SYMBOLIC clean
@if exist $(DLLFILE) rm $(DLLFILE)
@if exist $(LIBFILE) rm $(LIBFILE)
@if exist *.map rm *.map
@if exist *.exe rm *.exe

View File

@ -12,8 +12,6 @@
#include "physfs_internal.h" #include "physfs_internal.h"
#if defined(_MSC_VER) #if defined(_MSC_VER)
#include <stdarg.h>
/* this code came from https://stackoverflow.com/a/8712996 */ /* this code came from https://stackoverflow.com/a/8712996 */
int __PHYSFS_msvc_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) int __PHYSFS_msvc_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap)
{ {
@ -46,6 +44,8 @@ typedef struct __PHYSFS_DIRHANDLE__
void *opaque; /* Instance data unique to the archiver. */ void *opaque; /* Instance data unique to the archiver. */
char *dirName; /* Path to archive in platform-dependent notation. */ char *dirName; /* Path to archive in platform-dependent notation. */
char *mountPoint; /* Mountpoint in virtual file tree. */ char *mountPoint; /* Mountpoint in virtual file tree. */
char *root; /* subdirectory of archiver to use as root of archive (NULL for actual root) */
size_t rootlen; /* subdirectory of archiver to use as root of archive (NULL for actual root) */
const PHYSFS_Archiver *funcs; /* Ptr to archiver info for this handle. */ const PHYSFS_Archiver *funcs; /* Ptr to archiver info for this handle. */
struct __PHYSFS_DIRHANDLE__ *next; /* linked list stuff. */ struct __PHYSFS_DIRHANDLE__ *next; /* linked list stuff. */
} DirHandle; } DirHandle;
@ -86,6 +86,7 @@ static int allowSymLinks = 0;
static PHYSFS_Archiver **archivers = NULL; static PHYSFS_Archiver **archivers = NULL;
static PHYSFS_ArchiveInfo **archiveInfo = NULL; static PHYSFS_ArchiveInfo **archiveInfo = NULL;
static volatile size_t numArchivers = 0; static volatile size_t numArchivers = 0;
static size_t longest_root = 0;
/* mutexes ... */ /* mutexes ... */
static void *errorLock = NULL; /* protects error message list. */ static void *errorLock = NULL; /* protects error message list. */
@ -101,8 +102,8 @@ static inline int __PHYSFS_atomicAdd(int *ptrval, const int val)
{ {
int retval; int retval;
__PHYSFS_platformGrabMutex(stateLock); __PHYSFS_platformGrabMutex(stateLock);
*ptrval += val;
retval = *ptrval; retval = *ptrval;
*ptrval = retval + val;
__PHYSFS_platformReleaseMutex(stateLock); __PHYSFS_platformReleaseMutex(stateLock);
return retval; return retval;
} /* __PHYSFS_atomicAdd */ } /* __PHYSFS_atomicAdd */
@ -920,12 +921,12 @@ static DirHandle *openDirectory(PHYSFS_Io *io, const char *d, int forWriting)
retval = tryOpenDir(io, *i, d, forWriting, &claimed); retval = tryOpenDir(io, *i, d, forWriting, &claimed);
} /* else */ } /* else */
errcode = currentErrorCode(); errcode = claimed ? currentErrorCode() : PHYSFS_ERR_UNSUPPORTED;
if ((!retval) && (created_io)) if ((!retval) && (created_io))
io->destroy(io); io->destroy(io);
BAIL_IF(!retval, claimed ? errcode : PHYSFS_ERR_UNSUPPORTED, NULL); BAIL_IF(!retval, errcode, NULL);
return retval; return retval;
} /* openDirectory */ } /* openDirectory */
@ -980,6 +981,18 @@ static int sanitizePlatformIndependentPath(const char *src, char *dst)
} /* sanitizePlatformIndependentPath */ } /* sanitizePlatformIndependentPath */
static inline size_t dirHandleRootLen(const DirHandle *h)
{
return h ? h->rootlen : 0;
} /* dirHandleRootLen */
static inline int sanitizePlatformIndependentPathWithRoot(const DirHandle *h, const char *src, char *dst)
{
return sanitizePlatformIndependentPath(src, dst + dirHandleRootLen(h));
} /* sanitizePlatformIndependentPathWithRoot */
/* /*
* Figure out if (fname) is part of (h)'s mountpoint. (fname) must be an * Figure out if (fname) is part of (h)'s mountpoint. (fname) must be an
* output from sanitizePlatformIndependentPath(), so that it is in a known * output from sanitizePlatformIndependentPath(), so that it is in a known
@ -1080,6 +1093,8 @@ static int freeDirHandle(DirHandle *dh, FileHandle *openList)
BAIL_IF(i->dirHandle == dh, PHYSFS_ERR_FILES_STILL_OPEN, 0); BAIL_IF(i->dirHandle == dh, PHYSFS_ERR_FILES_STILL_OPEN, 0);
dh->funcs->closeArchive(dh->opaque); dh->funcs->closeArchive(dh->opaque);
if (dh->root) allocator.Free(dh->root);
allocator.Free(dh->dirName); allocator.Free(dh->dirName);
allocator.Free(dh->mountPoint); allocator.Free(dh->mountPoint);
allocator.Free(dh); allocator.Free(dh);
@ -1218,7 +1233,9 @@ int PHYSFS_init(const char *argv0)
if (!userDir) goto initFailed; if (!userDir) goto initFailed;
/* Platform layer is required to append a dirsep. */ /* Platform layer is required to append a dirsep. */
#ifndef __ANDROID__ /* it's an APK file, not a directory, on Android. */
assert(baseDir[strlen(baseDir) - 1] == __PHYSFS_platformDirSeparator); assert(baseDir[strlen(baseDir) - 1] == __PHYSFS_platformDirSeparator);
#endif
assert(userDir[strlen(userDir) - 1] == __PHYSFS_platformDirSeparator); assert(userDir[strlen(userDir) - 1] == __PHYSFS_platformDirSeparator);
if (!initStaticArchivers()) goto initFailed; if (!initStaticArchivers()) goto initFailed;
@ -1378,6 +1395,7 @@ static int doDeinit(void)
archivers = NULL; archivers = NULL;
} /* if */ } /* if */
longest_root = 0;
allowSymLinks = 0; allowSymLinks = 0;
initialized = 0; initialized = 0;
@ -1417,15 +1435,60 @@ char *__PHYSFS_strdup(const char *str)
} /* __PHYSFS_strdup */ } /* __PHYSFS_strdup */
PHYSFS_uint32 __PHYSFS_hashString(const char *str, size_t len) PHYSFS_uint32 __PHYSFS_hashString(const char *str)
{ {
PHYSFS_uint32 hash = 5381; PHYSFS_uint32 hash = 5381;
while (len--) while (1)
hash = ((hash << 5) + hash) ^ *(str++); {
const char ch = *(str++);
if (ch == 0)
break;
hash = ((hash << 5) + hash) ^ ch;
} /* while */
return hash; return hash;
} /* __PHYSFS_hashString */ } /* __PHYSFS_hashString */
PHYSFS_uint32 __PHYSFS_hashStringCaseFold(const char *str)
{
PHYSFS_uint32 hash = 5381;
while (1)
{
const PHYSFS_uint32 cp = __PHYSFS_utf8codepoint(&str);
if (cp == 0)
break;
else
{
PHYSFS_uint32 folded[3];
const int numbytes = (int) (PHYSFS_caseFold(cp, folded) * sizeof (PHYSFS_uint32));
const char *bytes = (const char *) folded;
int i;
for (i = 0; i < numbytes; i++)
hash = ((hash << 5) + hash) ^ *(bytes++);
} /* else */
} /* while */
return hash;
} /* __PHYSFS_hashStringCaseFold */
PHYSFS_uint32 __PHYSFS_hashStringCaseFoldUSAscii(const char *str)
{
PHYSFS_uint32 hash = 5381;
while (1)
{
char ch = *(str++);
if (ch == 0)
break;
else if ((ch >= 'A') && (ch <= 'Z'))
ch -= ('A' - 'a');
hash = ((hash << 5) + hash) ^ ch;
} /* while */
return hash;
} /* __PHYSFS_hashStringCaseFoldUSAscii */
/* MAKE SURE you hold stateLock before calling this! */ /* MAKE SURE you hold stateLock before calling this! */
static int doRegisterArchiver(const PHYSFS_Archiver *_archiver) static int doRegisterArchiver(const PHYSFS_Archiver *_archiver)
{ {
@ -1684,6 +1747,54 @@ int PHYSFS_setWriteDir(const char *newDir)
} /* PHYSFS_setWriteDir */ } /* PHYSFS_setWriteDir */
int PHYSFS_setRoot(const char *archive, const char *subdir)
{
DirHandle *i;
BAIL_IF(!archive, PHYSFS_ERR_INVALID_ARGUMENT, 0);
__PHYSFS_platformGrabMutex(stateLock);
for (i = searchPath; i != NULL; i = i->next)
{
if ((i->dirName != NULL) && (strcmp(archive, i->dirName) == 0))
{
if (!subdir || (strcmp(subdir, "/") == 0))
{
if (i->root)
allocator.Free(i->root);
i->root = NULL;
i->rootlen = 0;
} /* if */
else
{
const size_t len = strlen(subdir) + 1;
char *ptr = (char *) allocator.Malloc(len);
BAIL_IF_MUTEX(!ptr, PHYSFS_ERR_OUT_OF_MEMORY, stateLock, 0);
if (!sanitizePlatformIndependentPath(subdir, ptr))
{
allocator.Free(ptr);
BAIL_MUTEX_ERRPASS(stateLock, 0);
} /* if */
if (i->root)
allocator.Free(i->root);
i->root = ptr;
i->rootlen = strlen(i->root); /* in case sanitizePlatformIndependentPath changed subdir */
if (longest_root < i->rootlen)
longest_root = i->rootlen;
} /* else */
break;
} /* if */
} /* for */
__PHYSFS_platformReleaseMutex(stateLock);
return 1;
} /* PHYSFS_setRoot */
static int doMount(PHYSFS_Io *io, const char *fname, static int doMount(PHYSFS_Io *io, const char *fname,
const char *mountPoint, int appendToPath) const char *mountPoint, int appendToPath)
{ {
@ -2001,6 +2112,9 @@ int PHYSFS_symbolicLinksPermitted(void)
* like ".." which should be done once instead of once per archive. This also * like ".." which should be done once instead of once per archive. This also
* gives us license to treat (fname) as scratch space in this function. * gives us license to treat (fname) as scratch space in this function.
* *
* (fname)'s buffer must have enough space available before it for this
* function to prepend any root directory for this DirHandle.
*
* Returns non-zero if string is safe, zero if there's a security issue. * Returns non-zero if string is safe, zero if there's a security issue.
* PHYSFS_getLastError() will specify what was wrong. (*fname) will be * PHYSFS_getLastError() will specify what was wrong. (*fname) will be
* updated to point past any mount point elements so it is prepared to * updated to point past any mount point elements so it is prepared to
@ -2013,7 +2127,7 @@ static int verifyPath(DirHandle *h, char **_fname, int allowMissing)
char *start; char *start;
char *end; char *end;
if (*fname == '\0') /* quick rejection. */ if ((*fname == '\0') && (!h->root)) /* quick rejection. */
return 1; return 1;
/* !!! FIXME: This codeblock sucks. */ /* !!! FIXME: This codeblock sucks. */
@ -2036,6 +2150,17 @@ static int verifyPath(DirHandle *h, char **_fname, int allowMissing)
retval = 1; /* may be reset, below. */ retval = 1; /* may be reset, below. */
} /* if */ } /* if */
/* prepend the root directory, if any. */
if (h->root)
{
const int isempty = (*fname == '\0');
fname -= h->rootlen + (isempty ? 0 : 1);
strcpy(fname, h->root);
if (!isempty)
fname[h->rootlen] = '/';
*_fname = fname;
} /* if */
start = fname; start = fname;
if (!allowSymLinks) if (!allowSymLinks)
{ {
@ -2081,20 +2206,19 @@ static int verifyPath(DirHandle *h, char **_fname, int allowMissing)
} /* verifyPath */ } /* verifyPath */
/* This must hold the stateLock before calling. */
static int doMkdir(const char *_dname, char *dname) static int doMkdir(const char *_dname, char *dname)
{ {
DirHandle *h; DirHandle *h = writeDir;
char *start; char *start;
char *end; char *end;
int retval = 0; int retval = 0;
int exists = 1; /* force existance check on first path element. */ int exists = 1; /* force existance check on first path element. */
BAIL_IF_ERRPASS(!sanitizePlatformIndependentPath(_dname, dname), 0); assert(h != NULL);
__PHYSFS_platformGrabMutex(stateLock); BAIL_IF_ERRPASS(!sanitizePlatformIndependentPathWithRoot(h, _dname, dname), 0);
BAIL_IF_MUTEX(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, stateLock, 0); BAIL_IF_ERRPASS(!verifyPath(h, &dname, 1), 0);
h = writeDir;
BAIL_IF_MUTEX_ERRPASS(!verifyPath(h, &dname, 1), stateLock, 0);
start = dname; start = dname;
while (1) while (1)
@ -2110,7 +2234,12 @@ static int doMkdir(const char *_dname, char *dname)
const int rc = h->funcs->stat(h->opaque, dname, &statbuf); const int rc = h->funcs->stat(h->opaque, dname, &statbuf);
if ((!rc) && (currentErrorCode() == PHYSFS_ERR_NOT_FOUND)) if ((!rc) && (currentErrorCode() == PHYSFS_ERR_NOT_FOUND))
exists = 0; exists = 0;
retval = ((rc) && (statbuf.filetype == PHYSFS_FILETYPE_DIRECTORY)); /* verifyPath made sure that (dname) doesn't have symlinks if they aren't
allowed, but it's possible the mounted writeDir itself has symlinks in it,
(for example "/var" on iOS is a symlink, and the prefpath will be somewhere
under that)...if we mounted that writeDir, we must allow those symlinks here
unconditionally. */
retval = ( (rc) && ((statbuf.filetype == PHYSFS_FILETYPE_DIRECTORY) || (statbuf.filetype == PHYSFS_FILETYPE_SYMLINK)) );
} /* if */ } /* if */
if (!exists) if (!exists)
@ -2126,7 +2255,6 @@ static int doMkdir(const char *_dname, char *dname)
start = end + 1; start = end + 1;
} /* while */ } /* while */
__PHYSFS_platformReleaseMutex(stateLock);
return retval; return retval;
} /* doMkdir */ } /* doMkdir */
@ -2138,30 +2266,26 @@ int PHYSFS_mkdir(const char *_dname)
size_t len; size_t len;
BAIL_IF(!_dname, PHYSFS_ERR_INVALID_ARGUMENT, 0); BAIL_IF(!_dname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
len = strlen(_dname) + 1;
__PHYSFS_platformGrabMutex(stateLock);
BAIL_IF_MUTEX(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, stateLock, 0);
len = strlen(_dname) + dirHandleRootLen(writeDir) + 1;
dname = (char *) __PHYSFS_smallAlloc(len); dname = (char *) __PHYSFS_smallAlloc(len);
BAIL_IF(!dname, PHYSFS_ERR_OUT_OF_MEMORY, 0); BAIL_IF_MUTEX(!dname, PHYSFS_ERR_OUT_OF_MEMORY, stateLock, 0);
retval = doMkdir(_dname, dname); retval = doMkdir(_dname, dname);
__PHYSFS_platformReleaseMutex(stateLock);
__PHYSFS_smallFree(dname); __PHYSFS_smallFree(dname);
return retval; return retval;
} /* PHYSFS_mkdir */ } /* PHYSFS_mkdir */
/* This must hold the stateLock before calling. */
static int doDelete(const char *_fname, char *fname) static int doDelete(const char *_fname, char *fname)
{ {
int retval; DirHandle *h = writeDir;
DirHandle *h; BAIL_IF_ERRPASS(!sanitizePlatformIndependentPathWithRoot(h, _fname, fname), 0);
BAIL_IF_ERRPASS(!sanitizePlatformIndependentPath(_fname, fname), 0); BAIL_IF_ERRPASS(!verifyPath(h, &fname, 0), 0);
return h->funcs->remove(h->opaque, fname);
__PHYSFS_platformGrabMutex(stateLock);
BAIL_IF_MUTEX(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, stateLock, 0);
h = writeDir;
BAIL_IF_MUTEX_ERRPASS(!verifyPath(h, &fname, 0), stateLock, 0);
retval = h->funcs->remove(h->opaque, fname);
__PHYSFS_platformReleaseMutex(stateLock);
return retval;
} /* doDelete */ } /* doDelete */
@ -2171,11 +2295,13 @@ int PHYSFS_delete(const char *_fname)
char *fname; char *fname;
size_t len; size_t len;
BAIL_IF(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0); __PHYSFS_platformGrabMutex(stateLock);
len = strlen(_fname) + 1; BAIL_IF_MUTEX(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, stateLock, 0);
len = strlen(_fname) + dirHandleRootLen(writeDir) + 1;
fname = (char *) __PHYSFS_smallAlloc(len); fname = (char *) __PHYSFS_smallAlloc(len);
BAIL_IF(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0); BAIL_IF_MUTEX(!fname, PHYSFS_ERR_OUT_OF_MEMORY, stateLock, 0);
retval = doDelete(_fname, fname); retval = doDelete(_fname, fname);
__PHYSFS_platformReleaseMutex(stateLock);
__PHYSFS_smallFree(fname); __PHYSFS_smallFree(fname);
return retval; return retval;
} /* PHYSFS_delete */ } /* PHYSFS_delete */
@ -2184,17 +2310,20 @@ int PHYSFS_delete(const char *_fname)
static DirHandle *getRealDirHandle(const char *_fname) static DirHandle *getRealDirHandle(const char *_fname)
{ {
DirHandle *retval = NULL; DirHandle *retval = NULL;
char *allocated_fname = NULL;
char *fname = NULL; char *fname = NULL;
size_t len; size_t len;
BAIL_IF(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, NULL); BAIL_IF(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, NULL);
len = strlen(_fname) + 1;
fname = __PHYSFS_smallAlloc(len); __PHYSFS_platformGrabMutex(stateLock);
BAIL_IF(!fname, PHYSFS_ERR_OUT_OF_MEMORY, NULL); len = strlen(_fname) + longest_root + 2;
allocated_fname = __PHYSFS_smallAlloc(len);
BAIL_IF_MUTEX(!allocated_fname, PHYSFS_ERR_OUT_OF_MEMORY, stateLock, NULL);
fname = allocated_fname + longest_root + 1;
if (sanitizePlatformIndependentPath(_fname, fname)) if (sanitizePlatformIndependentPath(_fname, fname))
{ {
DirHandle *i; DirHandle *i;
__PHYSFS_platformGrabMutex(stateLock);
for (i = searchPath; i != NULL; i = i->next) for (i = searchPath; i != NULL; i = i->next)
{ {
char *arcfname = fname; char *arcfname = fname;
@ -2213,10 +2342,10 @@ static DirHandle *getRealDirHandle(const char *_fname)
} /* if */ } /* if */
} /* if */ } /* if */
} /* for */ } /* for */
__PHYSFS_platformReleaseMutex(stateLock);
} /* if */ } /* if */
__PHYSFS_smallFree(fname); __PHYSFS_platformReleaseMutex(stateLock);
__PHYSFS_smallFree(allocated_fname);
return retval; return retval;
} /* getRealDirHandle */ } /* getRealDirHandle */
@ -2411,15 +2540,18 @@ int PHYSFS_enumerate(const char *_fn, PHYSFS_EnumerateCallback cb, void *data)
{ {
PHYSFS_EnumerateCallbackResult retval = PHYSFS_ENUM_OK; PHYSFS_EnumerateCallbackResult retval = PHYSFS_ENUM_OK;
size_t len; size_t len;
char *allocated_fname;
char *fname; char *fname;
BAIL_IF(!_fn, PHYSFS_ERR_INVALID_ARGUMENT, 0); BAIL_IF(!_fn, PHYSFS_ERR_INVALID_ARGUMENT, 0);
BAIL_IF(!cb, PHYSFS_ERR_INVALID_ARGUMENT, 0); BAIL_IF(!cb, PHYSFS_ERR_INVALID_ARGUMENT, 0);
len = strlen(_fn) + 1; __PHYSFS_platformGrabMutex(stateLock);
fname = (char *) __PHYSFS_smallAlloc(len);
BAIL_IF(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0);
len = strlen(_fn) + longest_root + 2;
allocated_fname = (char *) __PHYSFS_smallAlloc(len);
BAIL_IF_MUTEX(!allocated_fname, PHYSFS_ERR_OUT_OF_MEMORY, stateLock, 0);
fname = allocated_fname + longest_root + 1;
if (!sanitizePlatformIndependentPath(_fn, fname)) if (!sanitizePlatformIndependentPath(_fn, fname))
retval = PHYSFS_ENUM_STOP; retval = PHYSFS_ENUM_STOP;
else else
@ -2427,8 +2559,6 @@ int PHYSFS_enumerate(const char *_fn, PHYSFS_EnumerateCallback cb, void *data)
DirHandle *i; DirHandle *i;
SymlinkFilterData filterdata; SymlinkFilterData filterdata;
__PHYSFS_platformGrabMutex(stateLock);
if (!allowSymLinks) if (!allowSymLinks)
{ {
memset(&filterdata, '\0', sizeof (filterdata)); memset(&filterdata, '\0', sizeof (filterdata));
@ -2477,10 +2607,11 @@ int PHYSFS_enumerate(const char *_fn, PHYSFS_EnumerateCallback cb, void *data)
} /* else if */ } /* else if */
} /* for */ } /* for */
__PHYSFS_platformReleaseMutex(stateLock);
} /* if */ } /* if */
__PHYSFS_smallFree(fname); __PHYSFS_platformReleaseMutex(stateLock);
__PHYSFS_smallFree(allocated_fname);
return (retval == PHYSFS_ENUM_ERROR) ? 0 : 1; return (retval == PHYSFS_ENUM_ERROR) ? 0 : 1;
} /* PHYSFS_enumerate */ } /* PHYSFS_enumerate */
@ -2541,43 +2672,43 @@ int PHYSFS_isSymbolicLink(const char *fname)
} /* PHYSFS_isSymbolicLink */ } /* PHYSFS_isSymbolicLink */
static PHYSFS_File *doOpenWrite(const char *_fname, int appending) static PHYSFS_File *doOpenWrite(const char *_fname, const int appending)
{ {
FileHandle *fh = NULL; FileHandle *fh = NULL;
DirHandle *h;
size_t len; size_t len;
char *fname; char *fname;
BAIL_IF(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0); BAIL_IF(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
len = strlen(_fname) + 1;
fname = (char *) __PHYSFS_smallAlloc(len);
BAIL_IF(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0);
if (sanitizePlatformIndependentPath(_fname, fname))
{
PHYSFS_Io *io = NULL;
DirHandle *h = NULL;
const PHYSFS_Archiver *f;
__PHYSFS_platformGrabMutex(stateLock); __PHYSFS_platformGrabMutex(stateLock);
GOTO_IF(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, doOpenWriteEnd);
h = writeDir; h = writeDir;
GOTO_IF_ERRPASS(!verifyPath(h, &fname, 0), doOpenWriteEnd); BAIL_IF_MUTEX(!h, PHYSFS_ERR_NO_WRITE_DIR, stateLock, 0);
f = h->funcs; len = strlen(_fname) + dirHandleRootLen(h) + 1;
fname = (char *) __PHYSFS_smallAlloc(len);
BAIL_IF_MUTEX(!fname, PHYSFS_ERR_OUT_OF_MEMORY, stateLock, 0);
if (sanitizePlatformIndependentPathWithRoot(h, _fname, fname))
{
PHYSFS_Io *io = NULL;
char *arcfname = fname;
if (verifyPath(h, &arcfname, 0))
{
const PHYSFS_Archiver *f = h->funcs;
if (appending) if (appending)
io = f->openAppend(h->opaque, fname); io = f->openAppend(h->opaque, arcfname);
else else
io = f->openWrite(h->opaque, fname); io = f->openWrite(h->opaque, arcfname);
GOTO_IF_ERRPASS(!io, doOpenWriteEnd);
if (io)
{
fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle)); fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle));
if (fh == NULL) if (fh == NULL)
{ {
io->destroy(io); io->destroy(io);
GOTO(PHYSFS_ERR_OUT_OF_MEMORY, doOpenWriteEnd); PHYSFS_setErrorCode(PHYSFS_ERR_OUT_OF_MEMORY);
} /* if */ } /* if */
else else
{ {
@ -2587,10 +2718,11 @@ static PHYSFS_File *doOpenWrite(const char *_fname, int appending)
fh->next = openWriteList; fh->next = openWriteList;
openWriteList = fh; openWriteList = fh;
} /* else */ } /* else */
doOpenWriteEnd:
__PHYSFS_platformReleaseMutex(stateLock);
} /* if */ } /* if */
} /* if */
} /* if */
__PHYSFS_platformReleaseMutex(stateLock);
__PHYSFS_smallFree(fname); __PHYSFS_smallFree(fname);
return ((PHYSFS_File *) fh); return ((PHYSFS_File *) fh);
@ -2612,22 +2744,25 @@ PHYSFS_File *PHYSFS_openAppend(const char *filename)
PHYSFS_File *PHYSFS_openRead(const char *_fname) PHYSFS_File *PHYSFS_openRead(const char *_fname)
{ {
FileHandle *fh = NULL; FileHandle *fh = NULL;
char *allocated_fname;
char *fname; char *fname;
size_t len; size_t len;
BAIL_IF(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0); BAIL_IF(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
len = strlen(_fname) + 1;
fname = (char *) __PHYSFS_smallAlloc(len);
BAIL_IF(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0);
if (sanitizePlatformIndependentPath(_fname, fname))
{
DirHandle *i = NULL;
PHYSFS_Io *io = NULL;
__PHYSFS_platformGrabMutex(stateLock); __PHYSFS_platformGrabMutex(stateLock);
GOTO_IF(!searchPath, PHYSFS_ERR_NOT_FOUND, openReadEnd); BAIL_IF_MUTEX(!searchPath, PHYSFS_ERR_NOT_FOUND, stateLock, 0);
len = strlen(_fname) + longest_root + 2;
allocated_fname = (char *) __PHYSFS_smallAlloc(len);
BAIL_IF_MUTEX(!allocated_fname, PHYSFS_ERR_OUT_OF_MEMORY, stateLock, 0);
fname = allocated_fname + longest_root + 1;
if (sanitizePlatformIndependentPath(_fname, fname))
{
PHYSFS_Io *io = NULL;
DirHandle *i;
for (i = searchPath; i != NULL; i = i->next) for (i = searchPath; i != NULL; i = i->next)
{ {
@ -2640,27 +2775,28 @@ PHYSFS_File *PHYSFS_openRead(const char *_fname)
} /* if */ } /* if */
} /* for */ } /* for */
GOTO_IF_ERRPASS(!io, openReadEnd); if (io)
{
fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle)); fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle));
if (fh == NULL) if (fh == NULL)
{ {
io->destroy(io); io->destroy(io);
GOTO(PHYSFS_ERR_OUT_OF_MEMORY, openReadEnd); PHYSFS_setErrorCode(PHYSFS_ERR_OUT_OF_MEMORY);
} /* if */ } /* if */
else
{
memset(fh, '\0', sizeof (FileHandle)); memset(fh, '\0', sizeof (FileHandle));
fh->io = io; fh->io = io;
fh->forReading = 1; fh->forReading = 1;
fh->dirHandle = i; fh->dirHandle = i;
fh->next = openReadList; fh->next = openReadList;
openReadList = fh; openReadList = fh;
} /* else */
openReadEnd: } /* if */
__PHYSFS_platformReleaseMutex(stateLock);
} /* if */ } /* if */
__PHYSFS_smallFree(fname); __PHYSFS_platformReleaseMutex(stateLock);
__PHYSFS_smallFree(allocated_fname);
return ((PHYSFS_File *) fh); return ((PHYSFS_File *) fh);
} /* PHYSFS_openRead */ } /* PHYSFS_openRead */
@ -2993,14 +3129,12 @@ int PHYSFS_flush(PHYSFS_File *handle)
int PHYSFS_stat(const char *_fname, PHYSFS_Stat *stat) int PHYSFS_stat(const char *_fname, PHYSFS_Stat *stat)
{ {
int retval = 0; int retval = 0;
char *allocated_fname;
char *fname; char *fname;
size_t len; size_t len;
BAIL_IF(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0); BAIL_IF(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
BAIL_IF(!stat, PHYSFS_ERR_INVALID_ARGUMENT, 0); BAIL_IF(!stat, PHYSFS_ERR_INVALID_ARGUMENT, 0);
len = strlen(_fname) + 1;
fname = (char *) __PHYSFS_smallAlloc(len);
BAIL_IF(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0);
/* set some sane defaults... */ /* set some sane defaults... */
stat->filesize = -1; stat->filesize = -1;
@ -3010,6 +3144,12 @@ int PHYSFS_stat(const char *_fname, PHYSFS_Stat *stat)
stat->filetype = PHYSFS_FILETYPE_OTHER; stat->filetype = PHYSFS_FILETYPE_OTHER;
stat->readonly = 1; stat->readonly = 1;
__PHYSFS_platformGrabMutex(stateLock);
len = strlen(_fname) + longest_root + 2;
allocated_fname = (char *) __PHYSFS_smallAlloc(len);
BAIL_IF_MUTEX(!allocated_fname, PHYSFS_ERR_OUT_OF_MEMORY, stateLock, 0);
fname = allocated_fname + longest_root + 1;
if (sanitizePlatformIndependentPath(_fname, fname)) if (sanitizePlatformIndependentPath(_fname, fname))
{ {
if (*fname == '\0') if (*fname == '\0')
@ -3022,7 +3162,6 @@ int PHYSFS_stat(const char *_fname, PHYSFS_Stat *stat)
{ {
DirHandle *i; DirHandle *i;
int exists = 0; int exists = 0;
__PHYSFS_platformGrabMutex(stateLock);
for (i = searchPath; ((i != NULL) && (!exists)); i = i->next) for (i = searchPath; ((i != NULL) && (!exists)); i = i->next)
{ {
char *arcfname = fname; char *arcfname = fname;
@ -3040,11 +3179,11 @@ int PHYSFS_stat(const char *_fname, PHYSFS_Stat *stat)
exists = 1; exists = 1;
} /* else if */ } /* else if */
} /* for */ } /* for */
__PHYSFS_platformReleaseMutex(stateLock);
} /* else */ } /* else */
} /* if */ } /* if */
__PHYSFS_smallFree(fname); __PHYSFS_platformReleaseMutex(stateLock);
__PHYSFS_smallFree(allocated_fname);
return retval; return retval;
} /* PHYSFS_stat */ } /* PHYSFS_stat */
@ -3142,7 +3281,7 @@ static void setDefaultAllocator(void)
} /* setDefaultAllocator */ } /* setDefaultAllocator */
int __PHYSFS_DirTreeInit(__PHYSFS_DirTree *dt, const size_t entrylen) int __PHYSFS_DirTreeInit(__PHYSFS_DirTree *dt, const size_t entrylen, const int case_sensitive, const int only_usascii)
{ {
static char rootpath[2] = { '/', '\0' }; static char rootpath[2] = { '/', '\0' };
size_t alloclen; size_t alloclen;
@ -3150,6 +3289,8 @@ int __PHYSFS_DirTreeInit(__PHYSFS_DirTree *dt, const size_t entrylen)
assert(entrylen >= sizeof (__PHYSFS_DirTreeEntry)); assert(entrylen >= sizeof (__PHYSFS_DirTreeEntry));
memset(dt, '\0', sizeof (*dt)); memset(dt, '\0', sizeof (*dt));
dt->case_sensitive = case_sensitive;
dt->only_usascii = only_usascii;
dt->root = (__PHYSFS_DirTreeEntry *) allocator.Malloc(entrylen); dt->root = (__PHYSFS_DirTreeEntry *) allocator.Malloc(entrylen);
BAIL_IF(!dt->root, PHYSFS_ERR_OUT_OF_MEMORY, 0); BAIL_IF(!dt->root, PHYSFS_ERR_OUT_OF_MEMORY, 0);
@ -3170,9 +3311,10 @@ int __PHYSFS_DirTreeInit(__PHYSFS_DirTree *dt, const size_t entrylen)
} /* __PHYSFS_DirTreeInit */ } /* __PHYSFS_DirTreeInit */
static inline PHYSFS_uint32 hashPathName(__PHYSFS_DirTree *dt, const char *name) static PHYSFS_uint32 hashPathName(__PHYSFS_DirTree *dt, const char *name)
{ {
return __PHYSFS_hashString(name, strlen(name)) % dt->hashBuckets; const PHYSFS_uint32 hashval = dt->case_sensitive ? __PHYSFS_hashString(name) : dt->only_usascii ? __PHYSFS_hashStringCaseFoldUSAscii(name) : __PHYSFS_hashStringCaseFold(name);
return hashval % dt->hashBuckets;
} /* hashPathName */ } /* hashPathName */
@ -3233,6 +3375,7 @@ void *__PHYSFS_DirTreeAdd(__PHYSFS_DirTree *dt, char *name, const int isdir)
/* Find the __PHYSFS_DirTreeEntry for a path in platform-independent notation. */ /* Find the __PHYSFS_DirTreeEntry for a path in platform-independent notation. */
void *__PHYSFS_DirTreeFind(__PHYSFS_DirTree *dt, const char *path) void *__PHYSFS_DirTreeFind(__PHYSFS_DirTree *dt, const char *path)
{ {
const int cs = dt->case_sensitive;
PHYSFS_uint32 hashval; PHYSFS_uint32 hashval;
__PHYSFS_DirTreeEntry *prev = NULL; __PHYSFS_DirTreeEntry *prev = NULL;
__PHYSFS_DirTreeEntry *retval; __PHYSFS_DirTreeEntry *retval;
@ -3243,7 +3386,8 @@ void *__PHYSFS_DirTreeFind(__PHYSFS_DirTree *dt, const char *path)
hashval = hashPathName(dt, path); hashval = hashPathName(dt, path);
for (retval = dt->hash[hashval]; retval; retval = retval->hashnext) for (retval = dt->hash[hashval]; retval; retval = retval->hashnext)
{ {
if (strcmp(retval->name, path) == 0) const int cmp = cs ? strcmp(retval->name, path) : PHYSFS_utf8stricmp(retval->name, path);
if (cmp == 0)
{ {
if (prev != NULL) /* move this to the front of the list */ if (prev != NULL) /* move this to the front of the list */
{ {

View File

@ -145,7 +145,7 @@
* - .ISO (ISO9660 files, CD-ROM images) * - .ISO (ISO9660 files, CD-ROM images)
* - .GRP (Build Engine groupfile archives) * - .GRP (Build Engine groupfile archives)
* - .PAK (Quake I/II archive format) * - .PAK (Quake I/II archive format)
* - .HOG (Descent I/II HOG file archives) * - .HOG (Descent I/II/III HOG file archives)
* - .MVL (Descent II movielib archives) * - .MVL (Descent II movielib archives)
* - .WAD (DOOM engine archives) * - .WAD (DOOM engine archives)
* - .VDF (Gothic I/II engine archives) * - .VDF (Gothic I/II engine archives)
@ -225,7 +225,9 @@ extern "C" {
#if defined(PHYSFS_DECL) #if defined(PHYSFS_DECL)
/* do nothing. */ /* do nothing. */
#elif defined(_MSC_VER) #elif defined(PHYSFS_STATIC)
#define PHYSFS_DECL /**/
#elif defined(_WIN32) || defined(__OS2__)
#define PHYSFS_DECL __declspec(dllexport) #define PHYSFS_DECL __declspec(dllexport)
#elif defined(__SUNPRO_C) #elif defined(__SUNPRO_C)
#define PHYSFS_DECL __global #define PHYSFS_DECL __global
@ -433,8 +435,8 @@ typedef struct PHYSFS_Version
#ifndef DOXYGEN_SHOULD_IGNORE_THIS #ifndef DOXYGEN_SHOULD_IGNORE_THIS
#define PHYSFS_VER_MAJOR 3 #define PHYSFS_VER_MAJOR 3
#define PHYSFS_VER_MINOR 0 #define PHYSFS_VER_MINOR 3
#define PHYSFS_VER_PATCH 2 #define PHYSFS_VER_PATCH 0
#endif /* DOXYGEN_SHOULD_IGNORE_THIS */ #endif /* DOXYGEN_SHOULD_IGNORE_THIS */
@ -493,6 +495,14 @@ typedef struct PHYSFS_Version
PHYSFS_DECL void PHYSFS_getLinkedVersion(PHYSFS_Version *ver); PHYSFS_DECL void PHYSFS_getLinkedVersion(PHYSFS_Version *ver);
#ifdef __ANDROID__
typedef struct PHYSFS_AndroidInit
{
void *jnienv;
void *context;
} PHYSFS_AndroidInit;
#endif
/** /**
* \fn int PHYSFS_init(const char *argv0) * \fn int PHYSFS_init(const char *argv0)
* \brief Initialize the PhysicsFS library. * \brief Initialize the PhysicsFS library.
@ -502,11 +512,22 @@ PHYSFS_DECL void PHYSFS_getLinkedVersion(PHYSFS_Version *ver);
* This should be called prior to any attempts to change your process's * This should be called prior to any attempts to change your process's
* current working directory. * current working directory.
* *
* \warning On Android, argv0 should be a non-NULL pointer to a
* PHYSFS_AndroidInit struct. This struct must hold a valid JNIEnv *
* and a JNI jobject of a Context (either the application context or
* the current Activity is fine). Both are cast to a void * so we
* don't need jni.h included wherever physfs.h is. PhysicsFS
* uses these objects to query some system details. PhysicsFS does
* not hold a reference to the JNIEnv or Context past the call to
* PHYSFS_init(). If you pass a NULL here, PHYSFS_init can still
* succeed, but PHYSFS_getBaseDir() and PHYSFS_getPrefDir() will be
* incorrect.
*
* \param argv0 the argv[0] string passed to your program's mainline. * \param argv0 the argv[0] string passed to your program's mainline.
* This may be NULL on most platforms (such as ones without a * This may be NULL on most platforms (such as ones without a
* standard main() function), but you should always try to pass * standard main() function), but you should always try to pass
* something in here. Unix-like systems such as Linux _need_ to * something in here. Many Unix-like systems _need_ to pass argv[0]
* pass argv[0] from main() in here. * from main() in here. See warning about Android, too!
* \return nonzero on success, zero on error. Specifics of the error can be * \return nonzero on success, zero on error. Specifics of the error can be
* gleaned from PHYSFS_getLastError(). * gleaned from PHYSFS_getLastError().
* *
@ -762,6 +783,15 @@ PHYSFS_DECL char **PHYSFS_getCdRomDirs(void);
* *
* You should probably use the base dir in your search path. * You should probably use the base dir in your search path.
* *
* \warning On most platforms, this is a directory; on Android, this gives
* you the path to the app's package (APK) file. As APK files are
* just .zip files, you can mount them in PhysicsFS like regular
* directories. You'll probably want to call
* PHYSFS_setRoot(basedir, "/assets") after mounting to make your
* app's actual data available directly without all the Android
* metadata and directory offset. Note that if you passed a NULL to
* PHYSFS_init(), you will not get the APK file here.
*
* \return READ ONLY string of base dir in platform-dependent notation. * \return READ ONLY string of base dir in platform-dependent notation.
* *
* \sa PHYSFS_getPrefDir * \sa PHYSFS_getPrefDir
@ -2702,10 +2732,10 @@ typedef PHYSFS_EnumerateCallbackResult (*PHYSFS_EnumerateCallback)(void *data,
* *
* \code * \code
* *
* static int printDir(void *data, const char *origdir, const char *fname) * static PHYSFS_EnumerateCallbackResult printDir(void *data, const char *origdir, const char *fname)
* { * {
* printf(" * We've got [%s] in [%s].\n", fname, origdir); * printf(" * We've got [%s] in [%s].\n", fname, origdir);
* return 1; // give me more data, please. * return PHYSFS_ENUM_OK; // give me more data, please.
* } * }
* *
* // ... * // ...
@ -3844,6 +3874,46 @@ PHYSFS_DECL int PHYSFS_deregisterArchiver(const char *ext);
/* Everything above this line is part of the PhysicsFS 2.1 API. */ /* Everything above this line is part of the PhysicsFS 2.1 API. */
/**
* \fn int PHYSFS_setRoot(const char *archive, const char *subdir)
* \brief Make a subdirectory of an archive its root directory.
*
* This lets you narrow down the accessible files in a specific archive. For
* example, if you have x.zip with a file in y/z.txt, mounted to /a, if you
* call PHYSFS_setRoot("x.zip", "/y"), then the call
* PHYSFS_openRead("/a/z.txt") will succeed.
*
* You can change an archive's root at any time, altering the interpolated
* file tree (depending on where paths shift, a different archive may be
* providing various files). If you set the root to NULL or "/", the
* archive will be treated as if no special root was set (as if the archive
* was just mounted normally).
*
* Changing the root only affects future operations on pathnames; a file
* that was opened from a path that changed due to a setRoot will not be
* affected.
*
* Setting a new root is not limited to archives in the search path; you may
* set one on the write dir, too, which might be useful if you have files
* open for write and thus can't change the write dir at the moment.
*
* It is not an error to set a subdirectory that does not exist to be the
* root of an archive; however, no files will be visible in this case. If
* the missing directories end up getting created (a mkdir to the physical
* filesystem, etc) then this will be reflected in the interpolated tree.
*
* \param archive dir/archive on which to change root.
* \param subdir new subdirectory to make the root of this archive.
* \return nonzero on success, zero on failure. Use
* PHYSFS_getLastErrorCode() to obtain the specific error.
*/
PHYSFS_DECL int PHYSFS_setRoot(const char *archive, const char *subdir);
/* Everything above this line is part of the PhysicsFS 3.1 API. */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -185,7 +185,7 @@ static int szipLoadEntries(SZIPinfo *info)
{ {
int retval = 0; int retval = 0;
if (__PHYSFS_DirTreeInit(&info->tree, sizeof (SZIPentry))) if (__PHYSFS_DirTreeInit(&info->tree, sizeof (SZIPentry), 1, 0))
{ {
const PHYSFS_uint32 count = info->db.NumFiles; const PHYSFS_uint32 count = info->db.NumFiles;
PHYSFS_uint32 i; PHYSFS_uint32 i;
@ -285,12 +285,15 @@ static PHYSFS_Io *SZIP_openRead(void *opaque, const char *path)
&blockIndex, &outBuffer, &outBufferSize, &offset, &blockIndex, &outBuffer, &outBufferSize, &offset,
&outSizeProcessed, alloc, alloc); &outSizeProcessed, alloc, alloc);
GOTO_IF(rc != SZ_OK, szipErrorCode(rc), SZIP_openRead_failed); GOTO_IF(rc != SZ_OK, szipErrorCode(rc), SZIP_openRead_failed);
GOTO_IF(outBuffer == NULL, PHYSFS_ERR_OUT_OF_MEMORY, SZIP_openRead_failed);
io->destroy(io); io->destroy(io);
io = NULL; io = NULL;
buf = allocator.Malloc(outSizeProcessed); buf = allocator.Malloc(outSizeProcessed ? outSizeProcessed : 1);
GOTO_IF(rc != SZ_OK, PHYSFS_ERR_OUT_OF_MEMORY, SZIP_openRead_failed); GOTO_IF(buf == NULL, PHYSFS_ERR_OUT_OF_MEMORY, SZIP_openRead_failed);
if (outSizeProcessed > 0)
memcpy(buf, outBuffer + offset, outSizeProcessed); memcpy(buf, outBuffer + offset, outSizeProcessed);
alloc->Free(alloc, outBuffer); alloc->Free(alloc, outBuffer);

View File

@ -76,7 +76,7 @@ static void *GRP_openArchive(PHYSFS_Io *io, const char *name,
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &count, sizeof(count)), NULL); BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &count, sizeof(count)), NULL);
count = PHYSFS_swapULE32(count); count = PHYSFS_swapULE32(count);
unpkarc = UNPK_openArchive(io); unpkarc = UNPK_openArchive(io, 0, 1);
BAIL_IF_ERRPASS(!unpkarc, NULL); BAIL_IF_ERRPASS(!unpkarc, NULL);
if (!grpLoadEntries(io, count, unpkarc)) if (!grpLoadEntries(io, count, unpkarc))

View File

@ -1,9 +1,9 @@
/* /*
* HOG support routines for PhysicsFS. * HOG support routines for PhysicsFS.
* *
* This driver handles Descent I/II HOG archives. * This driver handles Descent I/II/III HOG archives.
* *
* The format is very simple: * The Descent I/II format is very simple:
* *
* The file always starts with the 3-byte signature "DHF" (Descent * The file always starts with the 3-byte signature "DHF" (Descent
* HOG file). After that the files of a HOG are just attached after * HOG file). After that the files of a HOG are just attached after
@ -23,10 +23,23 @@
* *
* (That info is from http://www.descent2.com/ddn/specs/hog/) * (That info is from http://www.descent2.com/ddn/specs/hog/)
* *
* Descent 3 moved to HOG2 format, which starts with the chars "HOG2",
* then 32-bits for the number of contained files, 32 bits for the offset
* to the first file's data, then 56 bytes of 0xFF (reserved?). Then for
* each file, there's 36 bytes for filename (null-terminated, rest of bytes
* are garbage), 32-bits unknown/reserved (always zero?), 32-bits of length
* of file data, 32-bits of time since Unix epoch. Then immediately following,
* for each file is their uncompressed content, you can find its offset
* by starting at the initial data offset and adding the filesize of each
* prior file.
*
* This information was found at:
* https://web.archive.org/web/20020213004051/http://descent-3.com/ddn/specs/hog/
*
*
* Please see the file LICENSE.txt in the source's root directory. * Please see the file LICENSE.txt in the source's root directory.
* *
* This file written by Bradley Bell. * This file written by Bradley Bell and Ryan C. Gordon.
* Based on grp.c by Ryan C. Gordon.
*/ */
#define __PHYSICSFS_INTERNAL__ #define __PHYSICSFS_INTERNAL__
@ -34,7 +47,15 @@
#if PHYSFS_SUPPORTS_HOG #if PHYSFS_SUPPORTS_HOG
static int hogLoadEntries(PHYSFS_Io *io, void *arc) static int readui32(PHYSFS_Io *io, PHYSFS_uint32 *val)
{
PHYSFS_uint32 v;
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &v, sizeof (v)), 0);
*val = PHYSFS_swapULE32(v);
return 1;
} /* readui32 */
static int hog1LoadEntries(PHYSFS_Io *io, void *arc)
{ {
const PHYSFS_uint64 iolen = io->length(io); const PHYSFS_uint64 iolen = io->length(io);
PHYSFS_uint32 pos = 3; PHYSFS_uint32 pos = 3;
@ -45,11 +66,10 @@ static int hogLoadEntries(PHYSFS_Io *io, void *arc)
char name[13]; char name[13];
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, name, 13), 0); BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, name, 13), 0);
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &size, 4), 0); BAIL_IF_ERRPASS(!readui32(io, &size), 0);
name[12] = '\0'; /* just in case. */ name[12] = '\0'; /* just in case. */
pos += 13 + 4; pos += 13 + 4;
size = PHYSFS_swapULE32(size);
BAIL_IF_ERRPASS(!UNPK_addEntry(arc, name, 0, -1, -1, pos, size), 0); BAIL_IF_ERRPASS(!UNPK_addEntry(arc, name, 0, -1, -1, pos, size), 0);
pos += size; pos += size;
@ -60,24 +80,60 @@ static int hogLoadEntries(PHYSFS_Io *io, void *arc)
return 1; return 1;
} /* hogLoadEntries */ } /* hogLoadEntries */
static int hog2LoadEntries(PHYSFS_Io *io, void *arc)
{
PHYSFS_uint32 numfiles;
PHYSFS_uint32 pos;
PHYSFS_uint32 i;
BAIL_IF_ERRPASS(!readui32(io, &numfiles), 0);
BAIL_IF_ERRPASS(!readui32(io, &pos), 0);
BAIL_IF_ERRPASS(!io->seek(io, 68), 0); /* skip to end of header. */
for (i = 0; i < numfiles; i++) {
char name[37];
PHYSFS_uint32 reserved;
PHYSFS_uint32 size;
PHYSFS_uint32 mtime;
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, name, 36), 0);
BAIL_IF_ERRPASS(!readui32(io, &reserved), 0);
BAIL_IF_ERRPASS(!readui32(io, &size), 0);
BAIL_IF_ERRPASS(!readui32(io, &mtime), 0);
name[36] = '\0'; /* just in case */
BAIL_IF_ERRPASS(!UNPK_addEntry(arc, name, 0, mtime, mtime, pos, size), 0);
pos += size;
}
return 1;
} /* hog2LoadEntries */
static void *HOG_openArchive(PHYSFS_Io *io, const char *name, static void *HOG_openArchive(PHYSFS_Io *io, const char *name,
int forWriting, int *claimed) int forWriting, int *claimed)
{ {
PHYSFS_uint8 buf[3]; PHYSFS_uint8 buf[3];
void *unpkarc = NULL; void *unpkarc = NULL;
int hog1 = 0;
assert(io != NULL); /* shouldn't ever happen. */ assert(io != NULL); /* shouldn't ever happen. */
BAIL_IF(forWriting, PHYSFS_ERR_READ_ONLY, NULL); BAIL_IF(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, buf, 3), NULL); BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, buf, 3), NULL);
BAIL_IF(memcmp(buf, "DHF", 3) != 0, PHYSFS_ERR_UNSUPPORTED, NULL);
if (memcmp(buf, "DHF", 3) == 0)
hog1 = 1; /* original HOG (Descent 1 and 2) archive */
else
{
BAIL_IF(memcmp(buf, "HOG", 3) != 0, PHYSFS_ERR_UNSUPPORTED, NULL); /* Not HOG2 */
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, buf, 1), NULL);
BAIL_IF(buf[0] != '2', PHYSFS_ERR_UNSUPPORTED, NULL); /* Not HOG2 */
} /* else */
*claimed = 1; *claimed = 1;
unpkarc = UNPK_openArchive(io); unpkarc = UNPK_openArchive(io, 0, 1);
BAIL_IF_ERRPASS(!unpkarc, NULL); BAIL_IF_ERRPASS(!unpkarc, NULL);
if (!hogLoadEntries(io, unpkarc)) if (!(hog1 ? hog1LoadEntries(io, unpkarc) : hog2LoadEntries(io, unpkarc)))
{ {
UNPK_abandonArchive(unpkarc); UNPK_abandonArchive(unpkarc);
return NULL; return NULL;
@ -92,7 +148,7 @@ const PHYSFS_Archiver __PHYSFS_Archiver_HOG =
CURRENT_PHYSFS_ARCHIVER_API_VERSION, CURRENT_PHYSFS_ARCHIVER_API_VERSION,
{ {
"HOG", "HOG",
"Descent I/II HOG file format", "Descent I/II/III HOG file format",
"Bradley Bell <btb@icculus.org>", "Bradley Bell <btb@icculus.org>",
"https://icculus.org/physfs/", "https://icculus.org/physfs/",
0, /* supportsSymlinks */ 0, /* supportsSymlinks */

View File

@ -251,7 +251,7 @@ static int parseVolumeDescriptor(PHYSFS_Io *io, PHYSFS_uint64 *_rootpos,
pos += 2048; /* each volume descriptor is 2048 bytes */ pos += 2048; /* each volume descriptor is 2048 bytes */
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &type, 1), 0); BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &type, 1), 0);
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &identifier, 5), 0); BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, identifier, 5), 0);
if (memcmp(identifier, "CD001", 5) != 0) /* maybe not an iso? */ if (memcmp(identifier, "CD001", 5) != 0) /* maybe not an iso? */
{ {
@ -346,7 +346,8 @@ static void *ISO9660_openArchive(PHYSFS_Io *io, const char *filename,
if (!parseVolumeDescriptor(io, &rootpos, &len, &joliet, claimed)) if (!parseVolumeDescriptor(io, &rootpos, &len, &joliet, claimed))
return NULL; return NULL;
unpkarc = UNPK_openArchive(io); /* !!! FIXME: check case_sensitive and only_usascii params for this archive. */
unpkarc = UNPK_openArchive(io, 1, 0);
BAIL_IF_ERRPASS(!unpkarc, NULL); BAIL_IF_ERRPASS(!unpkarc, NULL);
if (!iso9660LoadEntries(io, joliet, "", rootpos, rootpos + len, unpkarc)) if (!iso9660LoadEntries(io, joliet, "", rootpos, rootpos + len, unpkarc))

View File

@ -70,7 +70,7 @@ static void *MVL_openArchive(PHYSFS_Io *io, const char *name,
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &count, sizeof(count)), NULL); BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &count, sizeof(count)), NULL);
count = PHYSFS_swapULE32(count); count = PHYSFS_swapULE32(count);
unpkarc = UNPK_openArchive(io); unpkarc = UNPK_openArchive(io, 0, 1);
BAIL_IF_ERRPASS(!unpkarc, NULL); BAIL_IF_ERRPASS(!unpkarc, NULL);
if (!mvlLoadEntries(io, count, unpkarc)) if (!mvlLoadEntries(io, count, unpkarc))

View File

@ -86,7 +86,8 @@ static void *QPAK_openArchive(PHYSFS_Io *io, const char *name,
BAIL_IF_ERRPASS(!io->seek(io, pos), NULL); BAIL_IF_ERRPASS(!io->seek(io, pos), NULL);
unpkarc = UNPK_openArchive(io); /* !!! FIXME: check case_sensitive and only_usascii params for this archive. */
unpkarc = UNPK_openArchive(io, 1, 0);
BAIL_IF_ERRPASS(!unpkarc, NULL); BAIL_IF_ERRPASS(!unpkarc, NULL);
if (!qpakLoadEntries(io, count, unpkarc)) if (!qpakLoadEntries(io, count, unpkarc))

View File

@ -36,7 +36,7 @@ static int slbLoadEntries(PHYSFS_Io *io, const PHYSFS_uint32 count, void *arc)
BAIL_IF(backslash != '\\', PHYSFS_ERR_CORRUPT, 0); BAIL_IF(backslash != '\\', PHYSFS_ERR_CORRUPT, 0);
/* read the rest of the buffer, 63 bytes */ /* read the rest of the buffer, 63 bytes */
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &name, 63), 0); BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, name, 63), 0);
name[63] = '\0'; /* in case the name lacks the null terminator */ name[63] = '\0'; /* in case the name lacks the null terminator */
/* convert backslashes */ /* convert backslashes */
@ -94,7 +94,8 @@ static void *SLB_openArchive(PHYSFS_Io *io, const char *name,
/* seek to the table of contents */ /* seek to the table of contents */
BAIL_IF_ERRPASS(!io->seek(io, tocPos), NULL); BAIL_IF_ERRPASS(!io->seek(io, tocPos), NULL);
unpkarc = UNPK_openArchive(io); /* !!! FIXME: check case_sensitive and only_usascii params for this archive. */
unpkarc = UNPK_openArchive(io, 1, 0);
BAIL_IF_ERRPASS(!unpkarc, NULL); BAIL_IF_ERRPASS(!unpkarc, NULL);
if (!slbLoadEntries(io, count, unpkarc)) if (!slbLoadEntries(io, count, unpkarc))

View File

@ -285,12 +285,12 @@ void *UNPK_addEntry(void *opaque, char *name, const int isdir,
} /* UNPK_addEntry */ } /* UNPK_addEntry */
void *UNPK_openArchive(PHYSFS_Io *io) void *UNPK_openArchive(PHYSFS_Io *io, const int case_sensitive, const int only_usascii)
{ {
UNPKinfo *info = (UNPKinfo *) allocator.Malloc(sizeof (UNPKinfo)); UNPKinfo *info = (UNPKinfo *) allocator.Malloc(sizeof (UNPKinfo));
BAIL_IF(!info, PHYSFS_ERR_OUT_OF_MEMORY, NULL); BAIL_IF(!info, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
if (!__PHYSFS_DirTreeInit(&info->tree, sizeof (UNPKentry))) if (!__PHYSFS_DirTreeInit(&info->tree, sizeof (UNPKentry), case_sensitive, only_usascii))
{ {
allocator.Free(info); allocator.Free(info);
return NULL; return NULL;

View File

@ -129,7 +129,8 @@ static void *VDF_openArchive(PHYSFS_Io *io, const char *name,
BAIL_IF_ERRPASS(!io->seek(io, rootCatOffset), NULL); BAIL_IF_ERRPASS(!io->seek(io, rootCatOffset), NULL);
unpkarc = UNPK_openArchive(io); /* !!! FIXME: check case_sensitive and only_usascii params for this archive. */
unpkarc = UNPK_openArchive(io, 1, 0);
BAIL_IF_ERRPASS(!unpkarc, NULL); BAIL_IF_ERRPASS(!unpkarc, NULL);
if (!vdfLoadEntries(io, count, vdfDosTimeToEpoch(timestamp), unpkarc)) if (!vdfLoadEntries(io, count, vdfDosTimeToEpoch(timestamp), unpkarc))

View File

@ -95,7 +95,7 @@ static void *WAD_openArchive(PHYSFS_Io *io, const char *name,
BAIL_IF_ERRPASS(!io->seek(io, directoryOffset), 0); BAIL_IF_ERRPASS(!io->seek(io, directoryOffset), 0);
unpkarc = UNPK_openArchive(io); unpkarc = UNPK_openArchive(io, 0, 1);
BAIL_IF_ERRPASS(!unpkarc, NULL); BAIL_IF_ERRPASS(!unpkarc, NULL);
if (!wadLoadEntries(io, count, unpkarc)) if (!wadLoadEntries(io, count, unpkarc))

View File

@ -15,6 +15,11 @@
#include <errno.h> #include <errno.h>
#include <time.h> #include <time.h>
#if (PHYSFS_BYTEORDER == PHYSFS_LIL_ENDIAN)
#define MINIZ_LITTLE_ENDIAN 1
#else
#define MINIZ_LITTLE_ENDIAN 0
#endif
#include "physfs_miniz.h" #include "physfs_miniz.h"
/* /*
@ -568,7 +573,7 @@ static PHYSFS_sint64 zip_find_end_of_central_dir(PHYSFS_Io *io, PHYSFS_sint64 *l
{ {
if (!__PHYSFS_readAll(io, buf, maxread - 4)) if (!__PHYSFS_readAll(io, buf, maxread - 4))
return -1; return -1;
memcpy(&buf[maxread - 4], &extra, sizeof (extra)); memcpy(&buf[maxread - 4], extra, sizeof (extra));
totalread += maxread - 4; totalread += maxread - 4;
} /* if */ } /* if */
else else
@ -578,7 +583,7 @@ static PHYSFS_sint64 zip_find_end_of_central_dir(PHYSFS_Io *io, PHYSFS_sint64 *l
totalread += maxread; totalread += maxread;
} /* else */ } /* else */
memcpy(&extra, buf, sizeof (extra)); memcpy(extra, buf, sizeof (extra));
for (i = maxread - 4; i > 0; i--) for (i = maxread - 4; i > 0; i--)
{ {
@ -833,7 +838,10 @@ static int zip_parse_local(PHYSFS_Io *io, ZIPentry *entry)
BAIL_IF_ERRPASS(!readui32(io, &ui32), 0); BAIL_IF_ERRPASS(!readui32(io, &ui32), 0);
BAIL_IF(ui32 != ZIP_LOCAL_FILE_SIG, PHYSFS_ERR_CORRUPT, 0); BAIL_IF(ui32 != ZIP_LOCAL_FILE_SIG, PHYSFS_ERR_CORRUPT, 0);
BAIL_IF_ERRPASS(!readui16(io, &ui16), 0); BAIL_IF_ERRPASS(!readui16(io, &ui16), 0);
BAIL_IF(ui16 != entry->version_needed, PHYSFS_ERR_CORRUPT, 0); /* Windows Explorer might rewrite the entire central directory, setting
this field to 2.0/MS-DOS for all files, so favor the local version,
which it leaves intact if it didn't alter that specific file. */
entry->version_needed = ui16;
BAIL_IF_ERRPASS(!readui16(io, &ui16), 0); /* general bits. */ BAIL_IF_ERRPASS(!readui16(io, &ui16), 0); /* general bits. */
BAIL_IF_ERRPASS(!readui16(io, &ui16), 0); BAIL_IF_ERRPASS(!readui16(io, &ui16), 0);
BAIL_IF(ui16 != entry->compression_method, PHYSFS_ERR_CORRUPT, 0); BAIL_IF(ui16 != entry->compression_method, PHYSFS_ERR_CORRUPT, 0);
@ -1482,7 +1490,7 @@ static void *ZIP_openArchive(PHYSFS_Io *io, const char *name,
if (!zip_parse_end_of_central_dir(info, &dstart, &cdir_ofs, &count)) if (!zip_parse_end_of_central_dir(info, &dstart, &cdir_ofs, &count))
goto ZIP_openarchive_failed; goto ZIP_openarchive_failed;
else if (!__PHYSFS_DirTreeInit(&info->tree, sizeof (ZIPentry))) else if (!__PHYSFS_DirTreeInit(&info->tree, sizeof (ZIPentry), 1, 0))
goto ZIP_openarchive_failed; goto ZIP_openarchive_failed;
root = (ZIPentry *) info->tree.root; root = (ZIPentry *) info->tree.root;

View File

@ -38,7 +38,7 @@
#include <malloc.h> #include <malloc.h>
#endif #endif
#ifdef PHYSFS_PLATFORM_SOLARIS #if defined(PHYSFS_PLATFORM_SOLARIS) || defined(PHYSFS_PLATFORM_LINUX)
#include <alloca.h> #include <alloca.h>
#endif #endif
@ -69,7 +69,7 @@ extern "C" {
All file-private symbols need to be marked "static". All file-private symbols need to be marked "static".
Everything shared between PhysicsFS sources needs to be in this Everything shared between PhysicsFS sources needs to be in this
file between the visibility pragma blocks. */ file between the visibility pragma blocks. */
#if PHYSFS_MINIMUM_GCC_VERSION(4,0) || defined(__clang__) #if !defined(_WIN32) && (PHYSFS_MINIMUM_GCC_VERSION(4,0) || defined(__clang__))
#define PHYSFS_HAVE_PRAGMA_VISIBILITY 1 #define PHYSFS_HAVE_PRAGMA_VISIBILITY 1
#endif #endif
@ -95,6 +95,7 @@ extern const PHYSFS_Archiver __PHYSFS_Archiver_VDF;
/* a real C99-compliant snprintf() is in Visual Studio 2015, /* a real C99-compliant snprintf() is in Visual Studio 2015,
but just use this everywhere for binary compatibility. */ but just use this everywhere for binary compatibility. */
#if defined(_MSC_VER) #if defined(_MSC_VER)
#include <stdarg.h>
int __PHYSFS_msvc_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap); int __PHYSFS_msvc_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap);
int __PHYSFS_msvc_snprintf(char *outBuf, size_t size, const char *format, ...); int __PHYSFS_msvc_snprintf(char *outBuf, size_t size, const char *format, ...);
#define vsnprintf __PHYSFS_msvc_vsnprintf #define vsnprintf __PHYSFS_msvc_vsnprintf
@ -108,14 +109,24 @@ const void *__PHYSFS_winrtCalcPrefDir(void);
#endif #endif
/* atomic operations. */ /* atomic operations. */
/* increment/decrement operations return the final incremented/decremented value. */
#if defined(_MSC_VER) && (_MSC_VER >= 1500) #if defined(_MSC_VER) && (_MSC_VER >= 1500)
#include <intrin.h> #include <intrin.h>
__PHYSFS_COMPILE_TIME_ASSERT(LongEqualsInt, sizeof (int) == sizeof (long)); __PHYSFS_COMPILE_TIME_ASSERT(LongEqualsInt, sizeof (int) == sizeof (long));
#define __PHYSFS_ATOMIC_INCR(ptrval) _InterlockedIncrement((long*)(ptrval)) #define __PHYSFS_ATOMIC_INCR(ptrval) _InterlockedIncrement((long*)(ptrval))
#define __PHYSFS_ATOMIC_DECR(ptrval) _InterlockedDecrement((long*)(ptrval)) #define __PHYSFS_ATOMIC_DECR(ptrval) _InterlockedDecrement((long*)(ptrval))
#elif defined(__clang__) || (defined(__GNUC__) && (((__GNUC__ * 10000) + (__GNUC_MINOR__ * 100)) >= 40100)) #elif defined(__clang__) || (defined(__GNUC__) && (((__GNUC__ * 10000) + (__GNUC_MINOR__ * 100)) >= 40100))
#define __PHYSFS_ATOMIC_INCR(ptrval) __sync_fetch_and_add(ptrval, 1) #define __PHYSFS_ATOMIC_INCR(ptrval) __sync_add_and_fetch(ptrval, 1)
#define __PHYSFS_ATOMIC_DECR(ptrval) __sync_fetch_and_add(ptrval, -1) #define __PHYSFS_ATOMIC_DECR(ptrval) __sync_add_and_fetch(ptrval, -1)
#elif defined(__WATCOMC__) && defined(__386__)
extern __inline int _xadd_watcom(volatile int *a, int v);
#pragma aux _xadd_watcom = \
"lock xadd [ecx], eax" \
parm [ecx] [eax] \
value [eax] \
modify exact [eax];
#define __PHYSFS_ATOMIC_INCR(ptrval) (_xadd_watcom(ptrval, 1)+1)
#define __PHYSFS_ATOMIC_DECR(ptrval) (_xadd_watcom(ptrval, -1)-1)
#else #else
#define PHYSFS_NEED_ATOMIC_OP_FALLBACK 1 #define PHYSFS_NEED_ATOMIC_OP_FALLBACK 1
int __PHYSFS_ATOMIC_INCR(int *ptrval); int __PHYSFS_ATOMIC_INCR(int *ptrval);
@ -213,6 +224,7 @@ extern void SZIP_global_init(void);
/* The latest supported PHYSFS_Archiver::version value. */ /* The latest supported PHYSFS_Archiver::version value. */
#define CURRENT_PHYSFS_ARCHIVER_API_VERSION 0 #define CURRENT_PHYSFS_ARCHIVER_API_VERSION 0
/* This byteorder stuff was lifted from SDL. https://www.libsdl.org/ */ /* This byteorder stuff was lifted from SDL. https://www.libsdl.org/ */
#define PHYSFS_LIL_ENDIAN 1234 #define PHYSFS_LIL_ENDIAN 1234
#define PHYSFS_BIG_ENDIAN 4321 #define PHYSFS_BIG_ENDIAN 4321
@ -220,11 +232,26 @@ extern void SZIP_global_init(void);
#ifdef __linux__ #ifdef __linux__
#include <endian.h> #include <endian.h>
#define PHYSFS_BYTEORDER __BYTE_ORDER #define PHYSFS_BYTEORDER __BYTE_ORDER
#else /* __linux__ */ #elif defined(__OpenBSD__) || defined(__DragonFly__)
#include <endian.h>
#define PHYSFS_BYTEORDER BYTE_ORDER
#elif defined(__FreeBSD__) || defined(__NetBSD__)
#include <sys/endian.h>
#define PHYSFS_BYTEORDER BYTE_ORDER
/* predefs from newer gcc and clang versions: */
#elif defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) && defined(__BYTE_ORDER__)
#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#define PHYSFS_BYTEORDER PHYSFS_LIL_ENDIAN
#elif (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#define PHYSFS_BYTEORDER PHYSFS_BIG_ENDIAN
#else
#error Unsupported endianness
#endif /**/
#else
#if defined(__hppa__) || \ #if defined(__hppa__) || \
defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \ defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \
(defined(__MIPS__) && defined(__MISPEB__)) || \ (defined(__MIPS__) && defined(__MIPSEB__)) || \
defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC) || \ defined(__ppc__) || defined(__POWERPC__) || defined(__powerpc__) || defined(__PPC__) || \
defined(__sparc__) defined(__sparc__)
#define PHYSFS_BYTEORDER PHYSFS_BIG_ENDIAN #define PHYSFS_BYTEORDER PHYSFS_BIG_ENDIAN
#else #else
@ -312,7 +339,18 @@ char *__PHYSFS_strdup(const char *str);
/* /*
* Give a hash value for a C string (uses djb's xor hashing algorithm). * Give a hash value for a C string (uses djb's xor hashing algorithm).
*/ */
PHYSFS_uint32 __PHYSFS_hashString(const char *str, size_t len); PHYSFS_uint32 __PHYSFS_hashString(const char *str);
/*
* Give a hash value for a C string (uses djb's xor hashing algorithm), case folding as it goes.
*/
PHYSFS_uint32 __PHYSFS_hashStringCaseFold(const char *str);
/*
* Give a hash value for a C string (uses djb's xor hashing algorithm), case folding as it goes,
* assuming that this is only US-ASCII chars (one byte per char, only 'A' through 'Z' need folding).
*/
PHYSFS_uint32 __PHYSFS_hashStringCaseFoldUSAscii(const char *str);
/* /*
@ -348,9 +386,10 @@ int __PHYSFS_readAll(PHYSFS_Io *io, void *buf, const size_t len);
/* These are shared between some archivers. */ /* These are shared between some archivers. */
/* LOTS of legacy formats that only use US ASCII, not actually UTF-8, so let them optimize here. */
void *UNPK_openArchive(PHYSFS_Io *io, const int case_sensitive, const int only_usascii);
void UNPK_abandonArchive(void *opaque); void UNPK_abandonArchive(void *opaque);
void UNPK_closeArchive(void *opaque); void UNPK_closeArchive(void *opaque);
void *UNPK_openArchive(PHYSFS_Io *io);
void *UNPK_addEntry(void *opaque, char *name, const int isdir, void *UNPK_addEntry(void *opaque, char *name, const int isdir,
const PHYSFS_sint64 ctime, const PHYSFS_sint64 mtime, const PHYSFS_sint64 ctime, const PHYSFS_sint64 mtime,
const PHYSFS_uint64 pos, const PHYSFS_uint64 len); const PHYSFS_uint64 pos, const PHYSFS_uint64 len);
@ -382,10 +421,13 @@ typedef struct __PHYSFS_DirTree
__PHYSFS_DirTreeEntry **hash; /* all entries hashed for fast lookup. */ __PHYSFS_DirTreeEntry **hash; /* all entries hashed for fast lookup. */
size_t hashBuckets; /* number of buckets in hash. */ size_t hashBuckets; /* number of buckets in hash. */
size_t entrylen; /* size in bytes of entries (including subclass). */ size_t entrylen; /* size in bytes of entries (including subclass). */
int case_sensitive; /* non-zero to treat entries as case-sensitive in DirTreeFind */
int only_usascii; /* non-zero to treat paths as US ASCII only (one byte per char, only 'A' through 'Z' are considered for case folding). */
} __PHYSFS_DirTree; } __PHYSFS_DirTree;
int __PHYSFS_DirTreeInit(__PHYSFS_DirTree *dt, const size_t entrylen); /* LOTS of legacy formats that only use US ASCII, not actually UTF-8, so let them optimize here. */
int __PHYSFS_DirTreeInit(__PHYSFS_DirTree *dt, const size_t entrylen, const int case_sensitive, const int only_usascii);
void *__PHYSFS_DirTreeAdd(__PHYSFS_DirTree *dt, char *name, const int isdir); void *__PHYSFS_DirTreeAdd(__PHYSFS_DirTree *dt, char *name, const int isdir);
void *__PHYSFS_DirTreeFind(__PHYSFS_DirTree *dt, const char *path); void *__PHYSFS_DirTreeFind(__PHYSFS_DirTree *dt, const char *path);
PHYSFS_EnumerateCallbackResult __PHYSFS_DirTreeEnumerate(void *opaque, PHYSFS_EnumerateCallbackResult __PHYSFS_DirTreeEnumerate(void *opaque,
@ -715,6 +757,11 @@ int __PHYSFS_platformGrabMutex(void *mutex);
*/ */
void __PHYSFS_platformReleaseMutex(void *mutex); void __PHYSFS_platformReleaseMutex(void *mutex);
/* !!! FIXME: move to public API? */
PHYSFS_uint32 __PHYSFS_utf8codepoint(const char **_str);
#if PHYSFS_HAVE_PRAGMA_VISIBILITY #if PHYSFS_HAVE_PRAGMA_VISIBILITY
#pragma GCC visibility pop #pragma GCC visibility pop
#endif #endif

View File

@ -506,6 +506,7 @@ MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned mem
#endif #endif
#if defined(MY_CPU_AMD64) \ #if defined(MY_CPU_AMD64) \
|| defined(_M_ARM64) \
|| defined(_M_IA64) \ || defined(_M_IA64) \
|| defined(__AARCH64EL__) \ || defined(__AARCH64EL__) \
|| defined(__AARCH64EB__) || defined(__AARCH64EB__)
@ -531,6 +532,8 @@ MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned mem
#if defined(_WIN32) && defined(_M_ARM) #if defined(_WIN32) && defined(_M_ARM)
#define MY_CPU_ARM_LE #define MY_CPU_ARM_LE
#elif defined(_WIN64) && defined(_M_ARM64)
#define MY_CPU_ARM_LE
#endif #endif
#if defined(_WIN32) && defined(_M_IA64) #if defined(_WIN32) && defined(_M_IA64)

View File

@ -22,12 +22,14 @@ typedef unsigned long mz_ulong;
typedef void *(*mz_alloc_func)(void *opaque, unsigned int items, unsigned int size); typedef void *(*mz_alloc_func)(void *opaque, unsigned int items, unsigned int size);
typedef void (*mz_free_func)(void *opaque, void *address); typedef void (*mz_free_func)(void *opaque, void *address);
#ifndef MINIZ_LITTLE_ENDIAN /* if not defined by PHYSFS */
#if defined(_M_IX86) || defined(_M_X64) #if defined(_M_IX86) || defined(_M_X64)
/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 if integer loads and stores to unaligned addresses are acceptable on the target platform (slightly faster). */ /* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 if integer loads and stores to unaligned addresses are acceptable on the target platform (slightly faster). */
#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
/* Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. */ /* Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. */
#define MINIZ_LITTLE_ENDIAN 1 #define MINIZ_LITTLE_ENDIAN 1
#endif #endif
#endif /**/
#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) #if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__)
/* Set MINIZ_HAS_64BIT_REGISTERS to 1 if the processor has 64-bit general purpose registers (enables 64-bit bitbuffer in inflator) */ /* Set MINIZ_HAS_64BIT_REGISTERS to 1 if the processor has 64-bit general purpose registers (enables 64-bit bitbuffer in inflator) */
@ -117,6 +119,8 @@ struct tinfl_decompressor_tag
#define MZ_MAX(a,b) (((a)>(b))?(a):(b)) #define MZ_MAX(a,b) (((a)>(b))?(a):(b))
#define MZ_MIN(a,b) (((a)<(b))?(a):(b)) #define MZ_MIN(a,b) (((a)<(b))?(a):(b))
#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) #define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj))
#define MZ_CLEAR_ARR(obj) memset((obj), 0, sizeof(obj))
#define MZ_CLEAR_PTR(obj) memset((obj), 0, sizeof(*obj))
#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
#define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) #define MZ_READ_LE16(p) *((const mz_uint16 *)(p))
@ -171,8 +175,12 @@ struct tinfl_decompressor_tag
code_len = TINFL_FAST_LOOKUP_BITS; \ code_len = TINFL_FAST_LOOKUP_BITS; \
do { \ do { \
temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \
} while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \ } while ((temp < 0) && (num_bits >= (code_len + 1))); \
} TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \ if (temp >= 0) break; \
} \
TINFL_GET_BYTE(state_index, c); \
bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \
num_bits += 8; \
} while (num_bits < 15); } while (num_bits < 15);
/* TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read */ /* TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read */
@ -274,13 +282,13 @@ static tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_
else else
{ {
for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; } for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; }
MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; } MZ_CLEAR_ARR(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; }
r->m_table_sizes[2] = 19; r->m_table_sizes[2] = 19;
} }
for ( ; (int)r->m_type >= 0; r->m_type--) for ( ; (int)r->m_type >= 0; r->m_type--)
{ {
int tree_next, tree_cur; tinfl_huff_table *pTable; int tree_next, tree_cur; tinfl_huff_table *pTable;
mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree); mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_ARR(total_syms); MZ_CLEAR_ARR(pTable->m_look_up); MZ_CLEAR_ARR(pTable->m_tree);
for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++; for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++;
used_syms = 0, total = 0; next_code[0] = next_code[1] = 0; used_syms = 0, total = 0; next_code[0] = next_code[1] = 0;
for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); } for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); }
@ -699,3 +707,4 @@ static int mz_inflateEnd(mz_streamp pStream)
For more information, please refer to <https://unlicense.org/> For more information, please refer to <https://unlicense.org/>
*/ */

View File

@ -0,0 +1,117 @@
/*
* Android 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_ANDROID
#include <jni.h>
#include <android/log.h>
#include "physfs_internal.h"
static char *prefpath = NULL;
int __PHYSFS_platformInit(void)
{
return 1; /* always succeed. */
} /* __PHYSFS_platformInit */
void __PHYSFS_platformDeinit(void)
{
if (prefpath)
{
allocator.Free(prefpath);
prefpath = NULL;
} /* if */
} /* __PHYSFS_platformDeinit */
void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
{
/* no-op. */
} /* __PHYSFS_platformDetectAvailableCDs */
char *__PHYSFS_platformCalcBaseDir(const char *argv0)
{
/* as a cheat, we expect argv0 to be a PHYSFS_AndroidInit* on Android. */
PHYSFS_AndroidInit *ainit = (PHYSFS_AndroidInit *) argv0;
char *retval = NULL;
JNIEnv *jenv = NULL;
jobject jcontext;
if (ainit == NULL)
return __PHYSFS_strdup("/"); /* oh well. */
jenv = (JNIEnv *) ainit->jnienv;
jcontext = (jobject) ainit->context;
if ((*jenv)->PushLocalFrame(jenv, 16) >= 0)
{
jobject jfileobj = 0;
jmethodID jmeth = 0;
jthrowable jexception = 0;
jstring jstr = 0;
jmeth = (*jenv)->GetMethodID(jenv, (*jenv)->GetObjectClass(jenv, jcontext), "getPackageResourcePath", "()Ljava/lang/String;");
jstr = (jstring)(*jenv)->CallObjectMethod(jenv, jcontext, jmeth);
jexception = (*jenv)->ExceptionOccurred(jenv); /* this can't throw an exception, right? Just in case. */
if (jexception != NULL)
(*jenv)->ExceptionClear(jenv);
else
{
const char *path = (*jenv)->GetStringUTFChars(jenv, jstr, NULL);
retval = __PHYSFS_strdup(path);
(*jenv)->ReleaseStringUTFChars(jenv, jstr, path);
} /* else */
/* We only can rely on the Activity being valid during this function call,
so go ahead and grab the prefpath too. */
jmeth = (*jenv)->GetMethodID(jenv, (*jenv)->GetObjectClass(jenv, jcontext), "getFilesDir", "()Ljava/io/File;");
jfileobj = (*jenv)->CallObjectMethod(jenv, jcontext, jmeth);
if (jfileobj)
{
jmeth = (*jenv)->GetMethodID(jenv, (*jenv)->GetObjectClass(jenv, jfileobj), "getCanonicalPath", "()Ljava/lang/String;");
jstr = (jstring)(*jenv)->CallObjectMethod(jenv, jfileobj, jmeth);
jexception = (*jenv)->ExceptionOccurred(jenv);
if (jexception != NULL)
(*jenv)->ExceptionClear(jenv);
else
{
const char *path = (*jenv)->GetStringUTFChars(jenv, jstr, NULL);
const size_t len = strlen(path) + 2;
prefpath = allocator.Malloc(len);
if (prefpath)
snprintf(prefpath, len, "%s/", path);
(*jenv)->ReleaseStringUTFChars(jenv, jstr, path);
} /* else */
} /* if */
(*jenv)->PopLocalFrame(jenv, NULL);
} /* if */
/* we can't return NULL because then PhysicsFS will treat argv0 as a string, but it's a non-NULL jobject! */
if (retval == NULL)
retval = __PHYSFS_strdup("/"); /* we pray this works. */
return retval;
} /* __PHYSFS_platformCalcBaseDir */
char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
{
return __PHYSFS_strdup(prefpath ? prefpath : "/");
} /* __PHYSFS_platformCalcPrefDir */
#endif /* PHYSFS_PLATFORM_ANDROID */
/* end of physfs_platform_android.c ... */

View File

@ -12,6 +12,7 @@
#ifdef PHYSFS_PLATFORM_APPLE #ifdef PHYSFS_PLATFORM_APPLE
#include <Foundation/Foundation.h> #include <Foundation/Foundation.h>
#include <dlfcn.h>
#include "physfs_internal.h" #include "physfs_internal.h"
@ -99,7 +100,7 @@ static int darwinIsWholeMedia(io_service_t service)
} /* darwinIsWholeMedia */ } /* darwinIsWholeMedia */
static int darwinIsMountedDisc(char *bsdName, mach_port_t masterPort) static int darwinIsMountedDisc(char *bsdName, mach_port_t mainPort)
{ {
int retval = 0; int retval = 0;
CFMutableDictionaryRef matchingDict; CFMutableDictionaryRef matchingDict;
@ -107,10 +108,10 @@ static int darwinIsMountedDisc(char *bsdName, mach_port_t masterPort)
io_iterator_t iter; io_iterator_t iter;
io_service_t service; io_service_t service;
if ((matchingDict = IOBSDNameMatching(masterPort, 0, bsdName)) == NULL) if ((matchingDict = IOBSDNameMatching(mainPort, 0, bsdName)) == NULL)
return 0; return 0;
rc = IOServiceGetMatchingServices(masterPort, matchingDict, &iter); rc = IOServiceGetMatchingServices(mainPort, matchingDict, &iter);
if ((rc != KERN_SUCCESS) || (!iter)) if ((rc != KERN_SUCCESS) || (!iter))
return 0; return 0;
@ -158,13 +159,25 @@ static int darwinIsMountedDisc(char *bsdName, mach_port_t masterPort)
void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data) void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
{ {
#if !defined(PHYSFS_NO_CDROM_SUPPORT) #if !defined(PHYSFS_NO_CDROM_SUPPORT)
/* macOS 12.0 changed "master" names to "main". */
typedef kern_return_t (*ioMainPortFn)(mach_port_t, mach_port_t *);
static ioMainPortFn ioMainPort = NULL;
const char *devPrefix = "/dev/"; const char *devPrefix = "/dev/";
const int prefixLen = strlen(devPrefix); const int prefixLen = strlen(devPrefix);
mach_port_t masterPort = 0; mach_port_t mainPort = 0;
struct statfs *mntbufp; struct statfs *mntbufp;
int i, mounts; int i, mounts;
if (IOMasterPort(MACH_PORT_NULL, &masterPort) != KERN_SUCCESS) if (ioMainPort == NULL)
{
ioMainPort = (ioMainPortFn) dlsym(RTLD_DEFAULT, "IOMainPort");
if (!ioMainPort)
ioMainPort = (ioMainPortFn) dlsym(RTLD_DEFAULT, "IOMasterPort");
if (!ioMainPort)
return; /* oh well, no CD-ROMs for you. */
} /* if */
if (ioMainPort(MACH_PORT_NULL, &mainPort) != KERN_SUCCESS)
BAIL(PHYSFS_ERR_OS_ERROR, ) /*return void*/; BAIL(PHYSFS_ERR_OS_ERROR, ) /*return void*/;
mounts = getmntinfo(&mntbufp, MNT_WAIT); /* NOT THREAD SAFE! */ mounts = getmntinfo(&mntbufp, MNT_WAIT); /* NOT THREAD SAFE! */
@ -176,7 +189,7 @@ void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
continue; continue;
dev += prefixLen; dev += prefixLen;
if (darwinIsMountedDisc(dev, masterPort)) if (darwinIsMountedDisc(dev, mainPort))
cb(data, mnt); cb(data, mnt);
} /* for */ } /* for */
#endif /* !defined(PHYSFS_NO_CDROM_SUPPORT) */ #endif /* !defined(PHYSFS_NO_CDROM_SUPPORT) */

View File

@ -222,7 +222,7 @@ static char *cvtPathToCorrectCase(char *buf)
if (ptr != NULL) /* isolate element to find (fname is the start). */ if (ptr != NULL) /* isolate element to find (fname is the start). */
*ptr = '\0'; *ptr = '\0';
rc = DosFindFirst((unsigned char *) spec, &hdir, FILE_DIRECTORY, rc = DosFindFirst(spec, &hdir, FILE_DIRECTORY,
&fb, sizeof (fb), &count, FIL_STANDARD); &fb, sizeof (fb), &count, FIL_STANDARD);
if (rc == NO_ERROR) if (rc == NO_ERROR)
{ {
@ -331,7 +331,7 @@ static int isCdRomDrive(ULONG drive)
ULONG ul1, ul2; ULONG ul1, ul2;
APIRET rc; APIRET rc;
HFILE hfile = NULLHANDLE; HFILE hfile = NULLHANDLE;
unsigned char drivename[3] = { 0, ':', '\0' }; char drivename[3] = { 0, ':', '\0' };
drivename[0] = 'A' + drive; drivename[0] = 'A' + drive;
@ -443,7 +443,7 @@ PHYSFS_EnumerateCallbackResult __PHYSFS_platformEnumerate(const char *dirname,
__PHYSFS_smallFree(utf8); __PHYSFS_smallFree(utf8);
BAIL_IF_ERRPASS(!cpspec, PHYSFS_ENUM_ERROR); BAIL_IF_ERRPASS(!cpspec, PHYSFS_ENUM_ERROR);
rc = DosFindFirst((unsigned char *) cpspec, &hdir, rc = DosFindFirst(cpspec, &hdir,
FILE_DIRECTORY | FILE_ARCHIVED | FILE_DIRECTORY | FILE_ARCHIVED |
FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM, FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM,
&fb, sizeof (fb), &count, FIL_STANDARD); &fb, sizeof (fb), &count, FIL_STANDARD);
@ -535,7 +535,7 @@ int __PHYSFS_platformMkDir(const char *filename)
APIRET rc; APIRET rc;
char *cpstr = cvtUtf8ToCodepage(filename); char *cpstr = cvtUtf8ToCodepage(filename);
BAIL_IF_ERRPASS(!cpstr, 0); BAIL_IF_ERRPASS(!cpstr, 0);
rc = DosCreateDir((unsigned char *) cpstr, NULL); rc = DosCreateDir(cpstr, NULL);
allocator.Free(cpstr); allocator.Free(cpstr);
BAIL_IF(rc != NO_ERROR, errcodeFromAPIRET(rc), 0); BAIL_IF(rc != NO_ERROR, errcodeFromAPIRET(rc), 0);
return 1; return 1;

View File

@ -6,8 +6,6 @@
* This file written by Ryan C. Gordon. * This file written by Ryan C. Gordon.
*/ */
/* !!! FIXME: check for EINTR? */
#define __PHYSICSFS_INTERNAL__ #define __PHYSICSFS_INTERNAL__
#include "physfs_platforms.h" #include "physfs_platforms.h"
@ -157,19 +155,41 @@ int __PHYSFS_platformMkDir(const char *path)
} /* __PHYSFS_platformMkDir */ } /* __PHYSFS_platformMkDir */
#if !defined(O_CLOEXEC) && defined(FD_CLOEXEC)
static inline void set_CLOEXEC(int fildes)
{
int flags = fcntl(fildes, F_GETFD);
if (flags != -1) {
fcntl(fildes, F_SETFD, flags | FD_CLOEXEC);
}
}
#endif
static void *doOpen(const char *filename, int mode) static void *doOpen(const char *filename, int mode)
{ {
const int appending = (mode & O_APPEND); const int appending = (mode & O_APPEND);
int fd; int fd;
int *retval; int *retval;
errno = 0; errno = 0;
/* O_APPEND doesn't actually behave as we'd like. */ /* O_APPEND doesn't actually behave as we'd like. */
mode &= ~O_APPEND; mode &= ~O_APPEND;
#ifdef O_CLOEXEC
/* Add O_CLOEXEC if defined */
mode |= O_CLOEXEC;
#endif
do {
fd = open(filename, mode, S_IRUSR | S_IWUSR); fd = open(filename, mode, S_IRUSR | S_IWUSR);
} while ((fd < 0) && (errno == EINTR));
BAIL_IF(fd < 0, errcodeFromErrno(), NULL); BAIL_IF(fd < 0, errcodeFromErrno(), NULL);
#if !defined(O_CLOEXEC) && defined(FD_CLOEXEC)
set_CLOEXEC(fd);
#endif
if (appending) if (appending)
{ {
if (lseek(fd, 0, SEEK_END) < 0) if (lseek(fd, 0, SEEK_END) < 0)
@ -219,7 +239,9 @@ PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
if (!__PHYSFS_ui64FitsAddressSpace(len)) if (!__PHYSFS_ui64FitsAddressSpace(len))
BAIL(PHYSFS_ERR_INVALID_ARGUMENT, -1); BAIL(PHYSFS_ERR_INVALID_ARGUMENT, -1);
do {
rc = read(fd, buffer, (size_t) len); rc = read(fd, buffer, (size_t) len);
} while ((rc == -1) && (errno == EINTR));
BAIL_IF(rc == -1, errcodeFromErrno(), -1); BAIL_IF(rc == -1, errcodeFromErrno(), -1);
assert(rc >= 0); assert(rc >= 0);
assert(rc <= len); assert(rc <= len);
@ -236,7 +258,9 @@ PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
if (!__PHYSFS_ui64FitsAddressSpace(len)) if (!__PHYSFS_ui64FitsAddressSpace(len))
BAIL(PHYSFS_ERR_INVALID_ARGUMENT, -1); BAIL(PHYSFS_ERR_INVALID_ARGUMENT, -1);
do {
rc = write(fd, (void *) buffer, (size_t) len); rc = write(fd, (void *) buffer, (size_t) len);
} while ((rc == -1) && (errno == EINTR));
BAIL_IF(rc == -1, errcodeFromErrno(), rc); BAIL_IF(rc == -1, errcodeFromErrno(), rc);
assert(rc >= 0); assert(rc >= 0);
assert(rc <= len); assert(rc <= len);
@ -275,8 +299,13 @@ PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
int __PHYSFS_platformFlush(void *opaque) int __PHYSFS_platformFlush(void *opaque)
{ {
const int fd = *((int *) opaque); const int fd = *((int *) opaque);
if ((fcntl(fd, F_GETFL) & O_ACCMODE) != O_RDONLY) int rc = -1;
BAIL_IF(fsync(fd) == -1, errcodeFromErrno(), 0); if ((fcntl(fd, F_GETFL) & O_ACCMODE) != O_RDONLY) {
do {
rc = fsync(fd);
} while ((rc == -1) && (errno == EINTR));
BAIL_IF(rc == -1, errcodeFromErrno(), 0);
}
return 1; return 1;
} /* __PHYSFS_platformFlush */ } /* __PHYSFS_platformFlush */
@ -284,7 +313,10 @@ int __PHYSFS_platformFlush(void *opaque)
void __PHYSFS_platformClose(void *opaque) void __PHYSFS_platformClose(void *opaque)
{ {
const int fd = *((int *) opaque); const int fd = *((int *) opaque);
(void) close(fd); /* we don't check this. You should have used flush! */ int rc = -1;
do {
rc = close(fd); /* we don't check this. You should have used flush! */
} while ((rc == -1) && (errno == EINTR));
allocator.Free(opaque); allocator.Free(opaque);
} /* __PHYSFS_platformClose */ } /* __PHYSFS_platformClose */

View File

@ -261,12 +261,6 @@ char *__PHYSFS_platformCalcBaseDir(const char *argv0)
if (sysctl(mib, 4, fullpath, &buflen, NULL, 0) != -1) if (sysctl(mib, 4, fullpath, &buflen, NULL, 0) != -1)
retval = __PHYSFS_strdup(fullpath); retval = __PHYSFS_strdup(fullpath);
} }
#elif defined(PHYSFS_PLATFORM_SOLARIS)
{
const char *path = getexecname();
if ((path != NULL) && (path[0] == '/')) /* must be absolute path... */
retval = __PHYSFS_strdup(path);
}
#endif #endif
/* If there's a Linux-like /proc filesystem, you can get the full path to /* If there's a Linux-like /proc filesystem, you can get the full path to
@ -278,6 +272,7 @@ char *__PHYSFS_platformCalcBaseDir(const char *argv0)
retval = readSymLink("/proc/self/exe"); retval = readSymLink("/proc/self/exe");
if (!retval) retval = readSymLink("/proc/curproc/file"); if (!retval) retval = readSymLink("/proc/curproc/file");
if (!retval) retval = readSymLink("/proc/curproc/exe"); if (!retval) retval = readSymLink("/proc/curproc/exe");
if (!retval) retval = readSymLink("/proc/self/path/a.out");
if (retval == NULL) if (retval == NULL)
{ {
/* older kernels don't have /proc/self ... try PID version... */ /* older kernels don't have /proc/self ... try PID version... */
@ -289,6 +284,15 @@ char *__PHYSFS_platformCalcBaseDir(const char *argv0)
} /* if */ } /* if */
} /* if */ } /* if */
#if defined(PHYSFS_PLATFORM_SOLARIS)
if (!retval) /* try getexecname() if /proc didn't pan out. This may not be an absolute path! */
{
const char *path = getexecname();
if ((path != NULL) && (path[0] == '/')) /* must be absolute path... */
retval = __PHYSFS_strdup(path);
} /* if */
#endif
if (retval != NULL) /* chop off filename. */ if (retval != NULL) /* chop off filename. */
{ {
char *ptr = strrchr(retval, '/'); char *ptr = strrchr(retval, '/');

View File

@ -101,7 +101,7 @@ static char *unicodeToUtf8Heap(const WCHAR *w_str)
static inline HANDLE winFindFirstFileW(const WCHAR *path, LPWIN32_FIND_DATAW d) static inline HANDLE winFindFirstFileW(const WCHAR *path, LPWIN32_FIND_DATAW d)
{ {
#ifdef PHYSFS_PLATFORM_WINRT #if defined(PHYSFS_PLATFORM_WINRT) || (_WIN32_WINNT >= 0x0501) // Windows XP+
return FindFirstFileExW(path, FindExInfoStandard, d, return FindFirstFileExW(path, FindExInfoStandard, d,
FindExSearchNameMatch, NULL, 0); FindExSearchNameMatch, NULL, 0);
#else #else
@ -111,7 +111,7 @@ static inline HANDLE winFindFirstFileW(const WCHAR *path, LPWIN32_FIND_DATAW d)
static inline BOOL winInitializeCriticalSection(LPCRITICAL_SECTION lpcs) static inline BOOL winInitializeCriticalSection(LPCRITICAL_SECTION lpcs)
{ {
#ifdef PHYSFS_PLATFORM_WINRT #if defined(PHYSFS_PLATFORM_WINRT) || (_WIN32_WINNT >= 0x0600) // Windows Vista+
return InitializeCriticalSectionEx(lpcs, 2000, 0); return InitializeCriticalSectionEx(lpcs, 2000, 0);
#else #else
InitializeCriticalSection(lpcs); InitializeCriticalSection(lpcs);
@ -123,7 +123,7 @@ static inline HANDLE winCreateFileW(const WCHAR *wfname, const DWORD mode,
const DWORD creation) const DWORD creation)
{ {
const DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE; const DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE;
#ifdef PHYSFS_PLATFORM_WINRT #if defined(PHYSFS_PLATFORM_WINRT) || (_WIN32_WINNT >= 0x0602) // Windows 8+
return CreateFile2(wfname, mode, share, creation, NULL); return CreateFile2(wfname, mode, share, creation, NULL);
#else #else
return CreateFileW(wfname, mode, share, NULL, creation, return CreateFileW(wfname, mode, share, NULL, creation,
@ -134,7 +134,7 @@ static inline HANDLE winCreateFileW(const WCHAR *wfname, const DWORD mode,
static BOOL winSetFilePointer(HANDLE h, const PHYSFS_sint64 pos, static BOOL winSetFilePointer(HANDLE h, const PHYSFS_sint64 pos,
PHYSFS_sint64 *_newpos, const DWORD whence) PHYSFS_sint64 *_newpos, const DWORD whence)
{ {
#ifdef PHYSFS_PLATFORM_WINRT #if defined(PHYSFS_PLATFORM_WINRT) || (_WIN32_WINNT >= 0x0501) // Windows XP+
LARGE_INTEGER lipos; LARGE_INTEGER lipos;
LARGE_INTEGER linewpos; LARGE_INTEGER linewpos;
BOOL rc; BOOL rc;
@ -158,7 +158,7 @@ static BOOL winSetFilePointer(HANDLE h, const PHYSFS_sint64 pos,
static PHYSFS_sint64 winGetFileSize(HANDLE h) static PHYSFS_sint64 winGetFileSize(HANDLE h)
{ {
#ifdef PHYSFS_PLATFORM_WINRT #if defined(PHYSFS_PLATFORM_WINRT) || (_WIN32_WINNT >= 0x0600) // Windows Vista+
FILE_STANDARD_INFO info; FILE_STANDARD_INFO info;
const BOOL rc = GetFileInformationByHandleEx(h, FileStandardInfo, const BOOL rc = GetFileInformationByHandleEx(h, FileStandardInfo,
&info, sizeof (info)); &info, sizeof (info));

View File

@ -40,9 +40,9 @@
# define PHYSFS_PLATFORM_POSIX 1 # define PHYSFS_PLATFORM_POSIX 1
#elif defined(macintosh) #elif defined(macintosh)
# error Classic Mac OS support was dropped from PhysicsFS 2.0. Move to OS X. # error Classic Mac OS support was dropped from PhysicsFS 2.0. Move to OS X.
#elif defined(ANDROID) #elif defined(__ANDROID__)
# define PHYSFS_PLATFORM_LINUX 1 # define PHYSFS_PLATFORM_LINUX 1
# define PHYSFS_PLATFORM_UNIX 1 # define PHYSFS_PLATFORM_ANDROID 1
# define PHYSFS_PLATFORM_POSIX 1 # define PHYSFS_PLATFORM_POSIX 1
# define PHYSFS_NO_CDROM_SUPPORT 1 # define PHYSFS_NO_CDROM_SUPPORT 1
#elif defined(__linux) #elif defined(__linux)

View File

@ -21,8 +21,8 @@
/* /*
* This may not be the best value, but it's one that isn't represented * 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 * in Unicode (0x10FFFF is the largest codepoint value). We return this
* value from utf8codepoint() if there's bogus bits in the * value from __PHYSFS_utf8codepoint() if there's bogus bits in the
* stream. utf8codepoint() will turn this value into something * stream. __PHYSFS_utf8codepoint() will turn this value into something
* reasonable (like a question mark), for text that wants to try to recover, * 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 * whereas utf8valid() will use the value to determine if a string has bad
* bits. * bits.
@ -35,7 +35,7 @@
*/ */
#define UNICODE_BOGUS_CHAR_CODEPOINT '?' #define UNICODE_BOGUS_CHAR_CODEPOINT '?'
static PHYSFS_uint32 utf8codepoint(const char **_str) PHYSFS_uint32 __PHYSFS_utf8codepoint(const char **_str)
{ {
const char *str = *_str; const char *str = *_str;
PHYSFS_uint32 retval = 0; PHYSFS_uint32 retval = 0;
@ -188,6 +188,11 @@ static PHYSFS_uint32 utf8codepoint(const char **_str)
} /* else if */ } /* else if */
return UNICODE_BOGUS_CHAR_VALUE; return UNICODE_BOGUS_CHAR_VALUE;
} /* __PHYSFS_utf8codepoint */
static inline PHYSFS_uint32 utf8codepoint(const char **_str)
{
return __PHYSFS_utf8codepoint(_str);
} /* utf8codepoint */ } /* utf8codepoint */
static PHYSFS_uint32 utf16codepoint(const PHYSFS_uint16 **_str) static PHYSFS_uint32 utf16codepoint(const PHYSFS_uint16 **_str)
@ -210,7 +215,7 @@ static PHYSFS_uint32 utf16codepoint(const PHYSFS_uint16 **_str)
else else
{ {
src++; /* eat the other surrogate. */ src++; /* eat the other surrogate. */
cp = (((cp - 0xD800) << 10) | (pair - 0xDC00)); cp = 0x10000 + (((cp - 0xD800) << 10) | (pair - 0xDC00));
} /* else */ } /* else */
} /* else if */ } /* else if */
@ -238,7 +243,7 @@ void PHYSFS_utf8ToUcs4(const char *src, PHYSFS_uint32 *dst, PHYSFS_uint64 len)
len -= sizeof (PHYSFS_uint32); /* save room for null char. */ len -= sizeof (PHYSFS_uint32); /* save room for null char. */
while (len >= sizeof (PHYSFS_uint32)) while (len >= sizeof (PHYSFS_uint32))
{ {
PHYSFS_uint32 cp = utf8codepoint(&src); PHYSFS_uint32 cp = __PHYSFS_utf8codepoint(&src);
if (cp == 0) if (cp == 0)
break; break;
else if (cp == UNICODE_BOGUS_CHAR_VALUE) else if (cp == UNICODE_BOGUS_CHAR_VALUE)
@ -256,7 +261,7 @@ void PHYSFS_utf8ToUcs2(const char *src, PHYSFS_uint16 *dst, PHYSFS_uint64 len)
len -= sizeof (PHYSFS_uint16); /* save room for null char. */ len -= sizeof (PHYSFS_uint16); /* save room for null char. */
while (len >= sizeof (PHYSFS_uint16)) while (len >= sizeof (PHYSFS_uint16))
{ {
PHYSFS_uint32 cp = utf8codepoint(&src); PHYSFS_uint32 cp = __PHYSFS_utf8codepoint(&src);
if (cp == 0) if (cp == 0)
break; break;
else if (cp == UNICODE_BOGUS_CHAR_VALUE) else if (cp == UNICODE_BOGUS_CHAR_VALUE)
@ -278,7 +283,7 @@ void PHYSFS_utf8ToUtf16(const char *src, PHYSFS_uint16 *dst, PHYSFS_uint64 len)
len -= sizeof (PHYSFS_uint16); /* save room for null char. */ len -= sizeof (PHYSFS_uint16); /* save room for null char. */
while (len >= sizeof (PHYSFS_uint16)) while (len >= sizeof (PHYSFS_uint16))
{ {
PHYSFS_uint32 cp = utf8codepoint(&src); PHYSFS_uint32 cp = __PHYSFS_utf8codepoint(&src);
if (cp == 0) if (cp == 0)
break; break;
else if (cp == UNICODE_BOGUS_CHAR_VALUE) else if (cp == UNICODE_BOGUS_CHAR_VALUE)

View File

@ -31,8 +31,8 @@
#include "physfs.h" #include "physfs.h"
#define TEST_VERSION_MAJOR 3 #define TEST_VERSION_MAJOR 3
#define TEST_VERSION_MINOR 0 #define TEST_VERSION_MINOR 3
#define TEST_VERSION_PATCH 2 #define TEST_VERSION_PATCH 0
static FILE *history_file = NULL; static FILE *history_file = NULL;
static PHYSFS_uint32 do_buffer_size = 0; static PHYSFS_uint32 do_buffer_size = 0;
@ -288,6 +288,53 @@ static int cmd_getmountpoint(char *args)
return 1; return 1;
} /* cmd_getmountpoint */ } /* cmd_getmountpoint */
static int cmd_setroot(char *args)
{
char *archive;
char *subdir;
char *ptr;
archive = args;
if (*archive == '\"')
{
archive++;
ptr = strchr(archive, '\"');
if (ptr == NULL)
{
printf("missing string terminator in argument.\n");
return 1;
} /* if */
*(ptr) = '\0';
} /* if */
else
{
ptr = strchr(archive, ' ');
*ptr = '\0';
} /* else */
subdir = ptr + 1;
if (*subdir == '\"')
{
subdir++;
ptr = strchr(subdir, '\"');
if (ptr == NULL)
{
printf("missing string terminator in argument.\n");
return 1;
} /* if */
*(ptr) = '\0';
} /* if */
if (PHYSFS_setRoot(archive, subdir))
printf("Successful.\n");
else
printf("Failure. reason: %s.\n", PHYSFS_getLastError());
return 1;
} /* cmd_setroot */
static int cmd_removearchive(char *args) static int cmd_removearchive(char *args)
{ {
if (*args == '\"') if (*args == '\"')
@ -1340,6 +1387,7 @@ static const command_info commands[] =
{ "stressbuffer", cmd_stressbuffer, 1, "<bufferSize>" }, { "stressbuffer", cmd_stressbuffer, 1, "<bufferSize>" },
{ "crc32", cmd_crc32, 1, "<fileToHash>" }, { "crc32", cmd_crc32, 1, "<fileToHash>" },
{ "getmountpoint", cmd_getmountpoint, 1, "<dir>" }, { "getmountpoint", cmd_getmountpoint, 1, "<dir>" },
{ "setroot", cmd_setroot, 2, "<archiveLocation> <root>" },
{ NULL, NULL, -1, NULL } { NULL, NULL, -1, NULL }
}; };