diff --git a/CMakeLists.txt b/CMakeLists.txt index 539a837..e9ba950 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) message(FATAL_ERROR "In-source builds prohibited. Call CMake from a build/ directory.") endif() -cmake_minimum_required(VERSION 3.7) +cmake_minimum_required(VERSION 3.25) # Create superbuild project project(antkeeper-superbuild VERSION "0.0.1") @@ -49,9 +49,9 @@ if(CMAKE_COMPILER_IS_GNUCC) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -g") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -O3") elseif(MSVC) - set(CMAKE_CXX_FLAGS "/MP /W3 /MT /GR- /GS- /EHsc /D_WIN32_WINNT=0x0501 /DWINVER=0x0501") - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS}") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} /O2") + set(CMAKE_CXX_FLAGS "/MP /W3 /GR- /GS- /EHsc /D_WIN32_WINNT=0x0501 /DWINVER=0x0501") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} /MTd") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} /MT /O2") endif() # Set C compiler flags @@ -252,6 +252,7 @@ ExternalProject_Add(physfs "-DPHYSFS_BUILD_STATIC=ON" "-DPHYSFS_BUILD_SHARED=OFF" "-DPHYSFS_BUILD_TEST=OFF" + "-DPHYSFS_BUILD_DOCS=OFF" BUILD_ALWAYS 0) # Build FreeType module @@ -290,7 +291,7 @@ ExternalProject_Add(antkeeper-source "-DCMAKE_CXX_FLAGS_RELEASE='${CMAKE_CXX_FLAGS_RELEASE}'" "-DCMAKE_EXE_LINKER_FLAGS='${CMAKE_EXE_LINKER_FLAGS}'" "-DCMAKE_EXE_LINKER_FLAGS_DEBUG='${CMAKE_EXE_LINKER_FLAGS_DEBUG}'" - "-DCMAKE_EXE_LINKER_FLAGS_RELEASE='${CMAKE_EXE_LINKER_FLAGSRELEASE}'" + "-DCMAKE_EXE_LINKER_FLAGS_RELEASE='${CMAKE_EXE_LINKER_FLAGS_RELEASE}'" BUILD_ALWAYS 1) # Build antkeeper-data module (if exists) diff --git a/modules/antkeeper-source b/modules/antkeeper-source index a37f7c0..5d4748c 160000 --- a/modules/antkeeper-source +++ b/modules/antkeeper-source @@ -1 +1 @@ -Subproject commit a37f7c0f5fe2c441bd2e1b26d19bcda3ace05988 +Subproject commit 5d4748cb91f2688154c17845e146643920fb2244 diff --git a/modules/physfs/.github/FUNDING.yml b/modules/physfs/.github/FUNDING.yml new file mode 100644 index 0000000..5cf911b --- /dev/null +++ b/modules/physfs/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: [icculus] +patreon: icculus diff --git a/modules/physfs/.github/workflows/main.yml b/modules/physfs/.github/workflows/main.yml new file mode 100644 index 0000000..15b9cfd --- /dev/null +++ b/modules/physfs/.github/workflows/main.yml @@ -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/ diff --git a/modules/physfs/.github/workflows/os2.yml b/modules/physfs/.github/workflows/os2.yml new file mode 100644 index 0000000..c948576 --- /dev/null +++ b/modules/physfs/.github/workflows/os2.yml @@ -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 .. diff --git a/modules/physfs/.hgignore b/modules/physfs/.gitignore similarity index 50% rename from modules/physfs/.hgignore rename to modules/physfs/.gitignore index d015a85..7878ec0 100644 --- a/modules/physfs/.hgignore +++ b/modules/physfs/.gitignore @@ -1,2 +1,2 @@ -syntax:glob cmake-build + diff --git a/modules/physfs/.hg_archival.txt b/modules/physfs/.hg_archival.txt deleted file mode 100644 index 4cbb35c..0000000 --- a/modules/physfs/.hg_archival.txt +++ /dev/null @@ -1,6 +0,0 @@ -repo: 7672c9962ce627edaaa67ff54fe4ad8f9a46dc2b -node: ae84e126219c52e7e4d35f22c3ccfe1413718961 -branch: stable-3.0 -latesttag: release-3.0.2 -latesttagdistance: 1 -changessincelatesttag: 1 diff --git a/modules/physfs/.hgtags b/modules/physfs/.hgtags deleted file mode 100644 index 1ee5f53..0000000 --- a/modules/physfs/.hgtags +++ /dev/null @@ -1,16 +0,0 @@ -0bb92a5f0fffd2452cc737346e8b796c213a5688 release-0.1.1 -2f2afcbd8abd784f738ac45b0368044763d63748 release-0.1.0 -3c7cf50a58fbf220154acd4bdfdf00a21f259eb7 release-0.1.8 -473b50402f55b2340fc286775d1b78d18a810362 release-0.1.3 -60b5f566a2585d78b2ffadd8d9c16299d0340820 release-1.0.0 -67aff4091bf129f7167ed87f937b15f31093e19e release-0.1.9 -6ad1722bbcaec1265cb74c9b7be13fe02a547d37 release-0.1.7 -8f3ccaaea1cd5dc19235882494d6102e5e9176fb release-0.1.2 -c966316c89981bea6ccaa2c2909bb303bfeeb82b release-0.1.6 -d2f04ab4b4127757234af6b30bfc98ad4ee9cb15 release-0.1.4 -d94f1ccac8095509c57ad640d54796aea0d260f0 release-0.1.5 -fe0c1d6f40afa6fca09a277a1ade59231f16c66f release-1.1.1 -5d70fca3be361258edfb59c3edaba5abe75a1e88 release-2.0.0 -df04959950eb3830c39adfa983789f70f86062d7 release-1.1.0 -3396e6dd19fbb52a3fa7e171ffb38ed9acb285a4 release-2.1.1 -fcdfd7e3d4d77bed8a865f2bdc2901497340d841 release-3.0.2 diff --git a/modules/physfs/CMakeLists.txt b/modules/physfs/CMakeLists.txt index 4a67c27..b3291cc 100644 --- a/modules/physfs/CMakeLists.txt +++ b/modules/physfs/CMakeLists.txt @@ -9,27 +9,29 @@ # compile, using preprocessor checks for platform-specific bits instead of # testing in here. -cmake_minimum_required(VERSION 2.8.4) +set(PHYSFS_VERSION 3.2.0) -project(PhysicsFS) -set(PHYSFS_VERSION 3.0.2) +cmake_minimum_required(VERSION 3.0) + +project(PhysicsFS VERSION ${PHYSFS_VERSION} LANGUAGES C ) + +include(GNUInstallDirs) # Increment this if/when we break backwards compatibility. set(PHYSFS_SOVERSION 1) -# I hate that they define "WIN32" ... we're about to move to Win64...I hope! -if(WIN32 AND NOT WINDOWS) - set(WINDOWS TRUE) -endif() +set(PHYSFS_M_SRCS) +set(PHYSFS_CPP_SRCS) -include_directories(./src) +# I hate that they define "WIN32" ... we're about to move to Win64...I hope! if(APPLE) 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() -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. set(CMAKE_SKIP_RPATH ON CACHE BOOL "Skip RPATH" FORCE) endif() @@ -42,10 +44,10 @@ endif() if(HAIKU) # We add this explicitly, since we don't want CMake to think this # 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(ROOT_LIBRARY root) - set(OPTIONAL_LIBRARY_LIBS ${OPTIONAL_LIBRARY_LIBS} ${BE_LIBRARY} ${ROOT_LIBRARY}) + list(APPEND OPTIONAL_LIBRARY_LIBS ${BE_LIBRARY} ${ROOT_LIBRARY}) endif() 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() if(WINRT) - set(PHYSFS_CPP_SRCS src/physfs_platform_winrt.cpp) + list(APPEND PHYSFS_CPP_SRCS src/physfs_platform_winrt.cpp) 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) if(PTHREAD_LIBRARY) set(OPTIONAL_LIBRARY_LIBS ${OPTIONAL_LIBRARY_LIBS} ${PTHREAD_LIBRARY}) endif() endif() +if(PHYSFS_CPP_SRCS) + enable_language(CXX) +endif() + # Almost everything is "compiled" here, but things that don't apply to the # build are #ifdef'd out. This is to make it easy to embed PhysicsFS into # another project or bring up a new build system: just compile all the source @@ -76,6 +82,7 @@ set(PHYSFS_SRCS src/physfs_platform_windows.c src/physfs_platform_os2.c src/physfs_platform_qnx.c + src/physfs_platform_android.c src/physfs_archiver_dir.c src/physfs_archiver_unpacked.c src/physfs_archiver_grp.c @@ -151,6 +158,8 @@ endif() option(PHYSFS_BUILD_STATIC "Build static library" TRUE) if(PHYSFS_BUILD_STATIC) 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 # library named "physfs.lib" which would conflict; Unix tend to like the # 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 STATIC_LIBRARY_FLAGS "/ignore:4264") 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 "$") + target_link_libraries(physfs-static PRIVATE ${OPTIONAL_LIBRARY_LIBS} ${OTHER_LDFLAGS}) set(PHYSFS_LIB_TARGET physfs-static) - set(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";physfs-static") + list(APPEND PHYSFS_INSTALL_TARGETS "physfs-static") endif() option(PHYSFS_BUILD_SHARED "Build shared library" TRUE) if(PHYSFS_BUILD_SHARED) 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 VERSION ${PHYSFS_VERSION}) set_target_properties(physfs PROPERTIES SOVERSION ${PHYSFS_SOVERSION}) + set_target_properties(physfs PROPERTIES EXPORT_NAME PhysFS) if(WINRT) set_target_properties(physfs PROPERTIES VS_WINRT_COMPONENT True) 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 "$") + target_link_libraries(physfs PRIVATE ${OPTIONAL_LIBRARY_LIBS} ${OTHER_LDFLAGS}) set(PHYSFS_LIB_TARGET physfs) - set(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";physfs") + list(APPEND PHYSFS_INSTALL_TARGETS "physfs") endif() 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() # 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-static PROPERTIES CLEAN_DIRECT_OUTPUT 1) endif() @@ -199,57 +219,88 @@ if(PHYSFS_BUILD_TEST) find_path(HISTORY_H readline/history.h) if(READLINE_H AND HISTORY_H) find_library(CURSES_LIBRARY NAMES curses ncurses) - set(CMAKE_REQUIRED_LIBRARIES ${CURSES_LIBRARY}) - find_library(READLINE_LIBRARY readline) - if(READLINE_LIBRARY) - set(HAVE_SYSTEM_READLINE TRUE) - set(TEST_PHYSFS_LIBS ${TEST_PHYSFS_LIBS} ${READLINE_LIBRARY} ${CURSES_LIBRARY}) - include_directories(SYSTEM ${READLINE_H} ${HISTORY_H}) - add_definitions(-DPHYSFS_HAVE_READLINE=1) + if(CURSES_LIBRARY) + set(CMAKE_REQUIRED_LIBRARIES ${CURSES_LIBRARY}) + find_library(READLINE_LIBRARY readline) + if(READLINE_LIBRARY) + set(HAVE_SYSTEM_READLINE TRUE) + list(APPEND TEST_PHYSFS_LIBS ${READLINE_LIBRARY} ${CURSES_LIBRARY}) + include_directories(SYSTEM ${READLINE_H} ${HISTORY_H}) + add_definitions(-DPHYSFS_HAVE_READLINE=1) + endif() endif() endif() add_executable(test_physfs test/test_physfs.c) - target_link_libraries(test_physfs ${PHYSFS_LIB_TARGET} ${TEST_PHYSFS_LIBS} ${OTHER_LDFLAGS}) - set(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";test_physfs") + target_link_libraries(test_physfs PRIVATE ${PHYSFS_LIB_TARGET} ${TEST_PHYSFS_LIBS} ${OTHER_LDFLAGS}) + list(APPEND PHYSFS_INSTALL_TARGETS test_physfs) endif() -install(TARGETS ${PHYSFS_INSTALL_TARGETS} - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib${LIB_SUFFIX} - ARCHIVE DESTINATION lib${LIB_SUFFIX}) -install(FILES src/physfs.h DESTINATION include) - -find_package(Doxygen) -if(DOXYGEN_FOUND) - set(PHYSFS_OUTPUT_DOXYFILE "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile") - configure_file( - "${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile" - "${PHYSFS_OUTPUT_DOXYFILE}" - COPYONLY - ) - file(APPEND "${PHYSFS_OUTPUT_DOXYFILE}" "\n\n# Below auto-generated by cmake...\n\n") - file(APPEND "${PHYSFS_OUTPUT_DOXYFILE}" "PROJECT_NUMBER = \"${PHYSFS_VERSION}\"\n") - file(APPEND "${PHYSFS_OUTPUT_DOXYFILE}" "OUTPUT_DIRECTORY = \"${CMAKE_CURRENT_BINARY_DIR}/docs\"\n") - file(APPEND "${PHYSFS_OUTPUT_DOXYFILE}" "\n# End auto-generated section.\n\n") +option(PHYSFS_DISABLE_INSTALL "Disable installing PhysFS" OFF) +if(NOT PHYSFS_DISABLE_INSTALL) - set(PHYSFS_TARGETNAME_DOCS "docs" CACHE STRING "Name of 'docs' build target") - add_custom_target( - ${PHYSFS_TARGETNAME_DOCS} - ${DOXYGEN_EXECUTABLE} "${PHYSFS_OUTPUT_DOXYFILE}" - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - COMMENT "Building documentation in 'docs' directory..." + 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:: ) -else() - message(STATUS "Doxygen not found. You won't be able to build documentation.") + + 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) + if(DOXYGEN_FOUND) + set(PHYSFS_OUTPUT_DOXYFILE "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile") + configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile" + "${PHYSFS_OUTPUT_DOXYFILE}" + COPYONLY + ) + file(APPEND "${PHYSFS_OUTPUT_DOXYFILE}" "\n\n# Below auto-generated by cmake...\n\n") + file(APPEND "${PHYSFS_OUTPUT_DOXYFILE}" "PROJECT_NUMBER = \"${PHYSFS_VERSION}\"\n") + file(APPEND "${PHYSFS_OUTPUT_DOXYFILE}" "OUTPUT_DIRECTORY = \"${CMAKE_CURRENT_BINARY_DIR}/docs\"\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") + + add_custom_target( + ${PHYSFS_TARGETNAME_DOCS} + ${DOXYGEN_EXECUTABLE} "${PHYSFS_OUTPUT_DOXYFILE}" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + COMMENT "Building documentation in 'docs' directory..." + ) + + else() + message(STATUS "Doxygen not found. You won't be able to build documentation.") + endif() endif() 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") add_custom_target( ${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}" COMMENT "Building source tarball '${PHYSFS_TARBALL}'..." ) @@ -263,17 +314,6 @@ if(UNIX) ) 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) 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 shared library" PHYSFS_BUILD_SHARED) message_bool_option("Build stdio test program" PHYSFS_BUILD_TEST) +message_bool_option("Build Doxygen documentation" PHYSFS_BUILD_DOCS) if(PHYSFS_BUILD_TEST) message_bool_option(" Use readline in test program" HAVE_SYSTEM_READLINE) endif() # end of CMakeLists.txt ... - diff --git a/modules/physfs/LICENSE.txt b/modules/physfs/LICENSE.txt index 8658ea4..e8d37a1 100644 --- a/modules/physfs/LICENSE.txt +++ b/modules/physfs/LICENSE.txt @@ -1,23 +1,17 @@ - - 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 arising from - the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software in a - product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be +Copyright (c) 2001-2022 Ryan C. Gordon and others. + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source distribution. - - Ryan C. Gordon - +3. This notice may not be removed or altered from any source distribution. diff --git a/modules/physfs/docs/CHANGELOG.txt b/modules/physfs/docs/CHANGELOG.txt index 649f0f1..7ff7245 100644 --- a/modules/physfs/docs/CHANGELOG.txt +++ b/modules/physfs/docs/CHANGELOG.txt @@ -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 browser here: - https://hg.icculus.org/icculus/physfs/ + https://github.com/icculus/physfs/commits/ diff --git a/modules/physfs/docs/INSTALL.txt b/modules/physfs/docs/INSTALL.txt index 781b973..39db64c 100644 --- a/modules/physfs/docs/INSTALL.txt +++ b/modules/physfs/docs/INSTALL.txt @@ -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. diff --git a/modules/physfs/extras/buildbot-checker.sh b/modules/physfs/extras/buildbot-checker.sh index 6c9a5f7..3a37a5e 100644 --- a/modules/physfs/extras/buildbot-checker.sh +++ b/modules/physfs/extras/buildbot-checker.sh @@ -1,53 +1,14 @@ #!/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 # back to the buildmaster. You might find it useful too. # Install Clang (you already have it on Mac OS X, apt-get install clang -# on Ubuntu, etc), -# or download checker at http://clang-analyzer.llvm.org/ and unpack it in -# /usr/local ... update CHECKERDIR as appropriate. +# on Ubuntu, etc), Make sure "scan-build" is in your $PATH. 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 -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" # 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" .. - -# ...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 +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" .. 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 mkdir analysis/zarro diff --git a/modules/physfs/extras/buildbot-emscripten.sh b/modules/physfs/extras/buildbot-emscripten.sh index 79f20a3..b71a073 100644 --- a/modules/physfs/extras/buildbot-emscripten.sh +++ b/modules/physfs/extras/buildbot-emscripten.sh @@ -1,7 +1,7 @@ #!/bin/bash if [ -z "$SDKDIR" ]; then - SDKDIR="/emsdk_portable" + SDKDIR="/emsdk" fi ENVSCRIPT="$SDKDIR/emsdk_env.sh" @@ -20,32 +20,6 @@ cd `dirname "$0"` cd .. 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..." source "$ENVSCRIPT" @@ -56,10 +30,10 @@ mkdir buildbot cd buildbot 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..." -emmake $MAKECMD || exit $? +emmake cmake --build . --config MinSizeRel || exit $? set -e rm -rf "$TARBALL" physfs-emscripten diff --git a/modules/physfs/extras/buildbot-raspberrypi.sh b/modules/physfs/extras/buildbot-raspberrypi.sh index 61064d6..5968894 100644 --- a/modules/physfs/extras/buildbot-raspberrypi.sh +++ b/modules/physfs/extras/buildbot-raspberrypi.sh @@ -15,24 +15,7 @@ if [ -z $1 ]; then TARBALL=physfs-raspberrypi.tar.xz fi -OSTYPE=`uname -s` -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" +BUILDBOTDIR="buildbot" PARENTDIR="$PWD" set -e @@ -42,8 +25,9 @@ rm -rf $BUILDBOTDIR mkdir -p $BUILDBOTDIR pushd $BUILDBOTDIR +# the '-G "Ninja"' can be '-G "Unix Makefiles"' if you prefer to use GNU Make. 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_BUILD_TYPE=MinSizeRel \ -DCMAKE_SYSROOT="$SYSROOT" \ @@ -55,7 +39,7 @@ cmake -G "Unix Makefiles" \ -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \ .. -$MAKECMD +cmake --build . --config MinSizeRel rm -rf "$TARBALL" physfs-raspberrypi mkdir -p physfs-raspberrypi diff --git a/modules/physfs/extras/globbing.c b/modules/physfs/extras/globbing.c index cac9c40..b639551 100644 --- a/modules/physfs/extras/globbing.c +++ b/modules/physfs/extras/globbing.c @@ -208,13 +208,13 @@ int main(int argc, char **argv) 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; } /* if */ if (!PHYSFS_addToSearchPath(".", 1)) { - fprintf(stderr, "PHYSFS_addToSearchPath(): %s\n", PHYSFS_getLastError()); + fprintf(stderr, "PHYSFS_addToSearchPath(): %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); PHYSFS_deinit(); return 1; } /* if */ diff --git a/modules/physfs/extras/ignorecase.c b/modules/physfs/extras/ignorecase.c index 869c213..5f0f35b 100644 --- a/modules/physfs/extras/ignorecase.c +++ b/modules/physfs/extras/ignorecase.c @@ -105,34 +105,34 @@ int main(int argc, char **argv) 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; } /* if */ if (!PHYSFS_addToSearchPath(".", 1)) { - fprintf(stderr, "PHYSFS_addToSearchPath(): %s\n", PHYSFS_getLastError()); + fprintf(stderr, "PHYSFS_addToSearchPath(): %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); PHYSFS_deinit(); return 1; } /* if */ if (!PHYSFS_setWriteDir(".")) { - fprintf(stderr, "PHYSFS_setWriteDir(): %s\n", PHYSFS_getLastError()); + fprintf(stderr, "PHYSFS_setWriteDir(): %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); PHYSFS_deinit(); return 1; } /* if */ 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(); return 1; } /* if */ 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(); return 1; } /* if */ @@ -141,7 +141,7 @@ int main(int argc, char **argv) PHYSFS_close(f); if (f == NULL) { - fprintf(stderr, "PHYSFS_openWrite(): %s\n", PHYSFS_getLastError()); + fprintf(stderr, "PHYSFS_openWrite(): %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); PHYSFS_deinit(); return 1; } /* if */ @@ -150,7 +150,7 @@ int main(int argc, char **argv) PHYSFS_close(f); if (f == NULL) { - fprintf(stderr, "PHYSFS_openWrite(): %s\n", PHYSFS_getLastError()); + fprintf(stderr, "PHYSFS_openWrite(): %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); PHYSFS_deinit(); return 1; } /* if */ diff --git a/modules/physfs/extras/physfs.pc.in b/modules/physfs/extras/physfs.pc.in index 6cd0972..f7e0307 100644 --- a/modules/physfs/extras/physfs.pc.in +++ b/modules/physfs/extras/physfs.pc.in @@ -1,7 +1,7 @@ prefix=@CMAKE_INSTALL_PREFIX@ -exec_prefix=${prefix} -libdir=${exec_prefix}/lib -includedir=${prefix}/include +exec_prefix=@CMAKE_INSTALL_PREFIX@ +libdir=@CMAKE_INSTALL_FULL_LIBDIR@ +includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ Name: PhysicsFS Description: PhysicsFS is a library to provide abstract access to various archives. diff --git a/modules/physfs/extras/physfsrwops.c b/modules/physfs/extras/physfsrwops.c index a8654ab..ad38f25 100644 --- a/modules/physfs/extras/physfsrwops.c +++ b/modules/physfs/extras/physfsrwops.c @@ -70,7 +70,7 @@ static int physfsrwops_seek(SDL_RWops *rw, int offset, int whence) if (current == -1) { SDL_SetError("Can't find position in file: %s", - PHYSFS_getLastError()); + PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); return -1; } /* if */ @@ -91,7 +91,7 @@ static int physfsrwops_seek(SDL_RWops *rw, int offset, int whence) const PHYSFS_sint64 len = PHYSFS_fileLength(handle); 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; } /* if */ @@ -112,7 +112,7 @@ static int physfsrwops_seek(SDL_RWops *rw, int offset, int whence) 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; } /* 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. */ { - SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError()); + SDL_SetError("PhysicsFS error: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); #if TARGET_SDL2 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_sint64 rc = PHYSFS_writeBytes(handle, ptr, 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 return (size_t) rc; @@ -182,7 +182,7 @@ static int physfsrwops_close(SDL_RWops *rw) PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1; if (!PHYSFS_close(handle)) { - SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError()); + SDL_SetError("PhysicsFS error: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); return -1; } /* if */ @@ -196,7 +196,7 @@ static SDL_RWops *create_rwops(PHYSFS_File *handle) SDL_RWops *retval = NULL; if (handle == NULL) - SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError()); + SDL_SetError("PhysicsFS error: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); else { retval = SDL_AllocRW(); diff --git a/modules/physfs/extras/physfsunpack.c b/modules/physfs/extras/physfsunpack.c index 1d26502..96f87de 100644 --- a/modules/physfs/extras/physfsunpack.c +++ b/modules/physfs/extras/physfsunpack.c @@ -28,7 +28,7 @@ static void modTimeToStr(PHYSFS_sint64 modtime, char *modstr, size_t strsize) static void fail(const char *what, const char *why) { if (why == NULL) - why = PHYSFS_getLastError(); + why = PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()); fprintf(stderr, "%s failed: %s\n", what, why); failure = 1; } /* fail */ @@ -150,21 +150,21 @@ int main(int argc, char **argv) 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; } /* if */ if (!PHYSFS_setWriteDir(argv[2])) { fprintf(stderr, "PHYSFS_setWriteDir('%s') failed: %s\n", - argv[2], PHYSFS_getLastError()); + argv[2], PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); return 3; } /* if */ if (!PHYSFS_mount(argv[1], NULL, 1)) { fprintf(stderr, "PHYSFS_mount('%s') failed: %s\n", - argv[1], PHYSFS_getLastError()); + argv[1], PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); return 4; } /* if */ diff --git a/modules/physfs/extras/selfextract.c b/modules/physfs/extras/selfextract.c index 2e8bba3..2a110e8 100644 --- a/modules/physfs/extras/selfextract.c +++ b/modules/physfs/extras/selfextract.c @@ -40,14 +40,14 @@ int main(int argc, char **argv) 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; } /* if */ rc = PHYSFS_addToSearchPath(argv[0], 0); 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"); return 42; } /* if */ diff --git a/modules/physfs/src/Makefile.os2 b/modules/physfs/src/Makefile.os2 new file mode 100644 index 0000000..1974f79 --- /dev/null +++ b/modules/physfs/src/Makefile.os2 @@ -0,0 +1,93 @@ +# Open Watcom makefile to build PhysicsFS for OS/2 +# wmake -f Makefile.os2 + +LIBNAME = physfs +VERSION = 3.2.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 diff --git a/modules/physfs/src/physfs.c b/modules/physfs/src/physfs.c index fdb1405..6476e0a 100644 --- a/modules/physfs/src/physfs.c +++ b/modules/physfs/src/physfs.c @@ -12,8 +12,6 @@ #include "physfs_internal.h" #if defined(_MSC_VER) -#include - /* this code came from https://stackoverflow.com/a/8712996 */ 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. */ char *dirName; /* Path to archive in platform-dependent notation. */ 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. */ struct __PHYSFS_DIRHANDLE__ *next; /* linked list stuff. */ } DirHandle; @@ -86,6 +86,7 @@ static int allowSymLinks = 0; static PHYSFS_Archiver **archivers = NULL; static PHYSFS_ArchiveInfo **archiveInfo = NULL; static volatile size_t numArchivers = 0; +static size_t longest_root = 0; /* mutexes ... */ static void *errorLock = NULL; /* protects error message list. */ @@ -101,8 +102,8 @@ static inline int __PHYSFS_atomicAdd(int *ptrval, const int val) { int retval; __PHYSFS_platformGrabMutex(stateLock); + *ptrval += val; retval = *ptrval; - *ptrval = retval + val; __PHYSFS_platformReleaseMutex(stateLock); return retval; } /* __PHYSFS_atomicAdd */ @@ -920,12 +921,12 @@ static DirHandle *openDirectory(PHYSFS_Io *io, const char *d, int forWriting) retval = tryOpenDir(io, *i, d, forWriting, &claimed); } /* else */ - errcode = currentErrorCode(); + errcode = claimed ? currentErrorCode() : PHYSFS_ERR_UNSUPPORTED; if ((!retval) && (created_io)) io->destroy(io); - BAIL_IF(!retval, claimed ? errcode : PHYSFS_ERR_UNSUPPORTED, NULL); + BAIL_IF(!retval, errcode, NULL); return retval; } /* openDirectory */ @@ -980,6 +981,18 @@ static int sanitizePlatformIndependentPath(const char *src, char *dst) } /* 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 * 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); dh->funcs->closeArchive(dh->opaque); + + if (dh->root) allocator.Free(dh->root); allocator.Free(dh->dirName); allocator.Free(dh->mountPoint); allocator.Free(dh); @@ -1218,7 +1233,9 @@ int PHYSFS_init(const char *argv0) if (!userDir) goto initFailed; /* 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); + #endif assert(userDir[strlen(userDir) - 1] == __PHYSFS_platformDirSeparator); if (!initStaticArchivers()) goto initFailed; @@ -1378,6 +1395,7 @@ static int doDeinit(void) archivers = NULL; } /* if */ + longest_root = 0; allowSymLinks = 0; initialized = 0; @@ -1417,15 +1435,60 @@ char *__PHYSFS_strdup(const char *str) } /* __PHYSFS_strdup */ -PHYSFS_uint32 __PHYSFS_hashString(const char *str, size_t len) +PHYSFS_uint32 __PHYSFS_hashString(const char *str) { PHYSFS_uint32 hash = 5381; - while (len--) - hash = ((hash << 5) + hash) ^ *(str++); + while (1) + { + const char ch = *(str++); + if (ch == 0) + break; + hash = ((hash << 5) + hash) ^ ch; + } /* while */ return hash; } /* __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! */ static int doRegisterArchiver(const PHYSFS_Archiver *_archiver) { @@ -1684,6 +1747,54 @@ int PHYSFS_setWriteDir(const char *newDir) } /* 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, 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 * 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. * PHYSFS_getLastError() will specify what was wrong. (*fname) will be * 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 *end; - if (*fname == '\0') /* quick rejection. */ + if ((*fname == '\0') && (!h->root)) /* quick rejection. */ return 1; /* !!! FIXME: This codeblock sucks. */ @@ -2036,6 +2150,17 @@ static int verifyPath(DirHandle *h, char **_fname, int allowMissing) retval = 1; /* may be reset, below. */ } /* 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; if (!allowSymLinks) { @@ -2081,20 +2206,19 @@ static int verifyPath(DirHandle *h, char **_fname, int allowMissing) } /* verifyPath */ +/* This must hold the stateLock before calling. */ static int doMkdir(const char *_dname, char *dname) { - DirHandle *h; + DirHandle *h = writeDir; char *start; char *end; int retval = 0; 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_MUTEX(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, stateLock, 0); - h = writeDir; - BAIL_IF_MUTEX_ERRPASS(!verifyPath(h, &dname, 1), stateLock, 0); + BAIL_IF_ERRPASS(!sanitizePlatformIndependentPathWithRoot(h, _dname, dname), 0); + BAIL_IF_ERRPASS(!verifyPath(h, &dname, 1), 0); start = dname; while (1) @@ -2110,7 +2234,12 @@ static int doMkdir(const char *_dname, char *dname) const int rc = h->funcs->stat(h->opaque, dname, &statbuf); if ((!rc) && (currentErrorCode() == PHYSFS_ERR_NOT_FOUND)) 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 (!exists) @@ -2126,7 +2255,6 @@ static int doMkdir(const char *_dname, char *dname) start = end + 1; } /* while */ - __PHYSFS_platformReleaseMutex(stateLock); return retval; } /* doMkdir */ @@ -2138,30 +2266,26 @@ int PHYSFS_mkdir(const char *_dname) size_t len; 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); - BAIL_IF(!dname, PHYSFS_ERR_OUT_OF_MEMORY, 0); + BAIL_IF_MUTEX(!dname, PHYSFS_ERR_OUT_OF_MEMORY, stateLock, 0); retval = doMkdir(_dname, dname); + __PHYSFS_platformReleaseMutex(stateLock); __PHYSFS_smallFree(dname); return retval; } /* PHYSFS_mkdir */ +/* This must hold the stateLock before calling. */ static int doDelete(const char *_fname, char *fname) { - int retval; - DirHandle *h; - BAIL_IF_ERRPASS(!sanitizePlatformIndependentPath(_fname, fname), 0); - - __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; + DirHandle *h = writeDir; + BAIL_IF_ERRPASS(!sanitizePlatformIndependentPathWithRoot(h, _fname, fname), 0); + BAIL_IF_ERRPASS(!verifyPath(h, &fname, 0), 0); + return h->funcs->remove(h->opaque, fname); } /* doDelete */ @@ -2171,11 +2295,13 @@ int PHYSFS_delete(const char *_fname) char *fname; size_t len; - BAIL_IF(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0); - len = strlen(_fname) + 1; + __PHYSFS_platformGrabMutex(stateLock); + BAIL_IF_MUTEX(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, stateLock, 0); + len = strlen(_fname) + dirHandleRootLen(writeDir) + 1; 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); + __PHYSFS_platformReleaseMutex(stateLock); __PHYSFS_smallFree(fname); return retval; } /* PHYSFS_delete */ @@ -2184,17 +2310,20 @@ int PHYSFS_delete(const char *_fname) static DirHandle *getRealDirHandle(const char *_fname) { DirHandle *retval = NULL; + char *allocated_fname = NULL; char *fname = NULL; size_t len; BAIL_IF(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, NULL); - len = strlen(_fname) + 1; - fname = __PHYSFS_smallAlloc(len); - BAIL_IF(!fname, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + + __PHYSFS_platformGrabMutex(stateLock); + 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)) { DirHandle *i; - __PHYSFS_platformGrabMutex(stateLock); for (i = searchPath; i != NULL; i = i->next) { char *arcfname = fname; @@ -2213,10 +2342,10 @@ static DirHandle *getRealDirHandle(const char *_fname) } /* if */ } /* if */ } /* for */ - __PHYSFS_platformReleaseMutex(stateLock); } /* if */ - __PHYSFS_smallFree(fname); + __PHYSFS_platformReleaseMutex(stateLock); + __PHYSFS_smallFree(allocated_fname); return retval; } /* getRealDirHandle */ @@ -2411,15 +2540,18 @@ int PHYSFS_enumerate(const char *_fn, PHYSFS_EnumerateCallback cb, void *data) { PHYSFS_EnumerateCallbackResult retval = PHYSFS_ENUM_OK; size_t len; + char *allocated_fname; char *fname; BAIL_IF(!_fn, PHYSFS_ERR_INVALID_ARGUMENT, 0); BAIL_IF(!cb, PHYSFS_ERR_INVALID_ARGUMENT, 0); - len = strlen(_fn) + 1; - fname = (char *) __PHYSFS_smallAlloc(len); - BAIL_IF(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0); + __PHYSFS_platformGrabMutex(stateLock); + 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)) retval = PHYSFS_ENUM_STOP; else @@ -2427,8 +2559,6 @@ int PHYSFS_enumerate(const char *_fn, PHYSFS_EnumerateCallback cb, void *data) DirHandle *i; SymlinkFilterData filterdata; - __PHYSFS_platformGrabMutex(stateLock); - if (!allowSymLinks) { memset(&filterdata, '\0', sizeof (filterdata)); @@ -2477,10 +2607,11 @@ int PHYSFS_enumerate(const char *_fn, PHYSFS_EnumerateCallback cb, void *data) } /* else if */ } /* for */ - __PHYSFS_platformReleaseMutex(stateLock); } /* if */ - __PHYSFS_smallFree(fname); + __PHYSFS_platformReleaseMutex(stateLock); + + __PHYSFS_smallFree(allocated_fname); return (retval == PHYSFS_ENUM_ERROR) ? 0 : 1; } /* PHYSFS_enumerate */ @@ -2541,57 +2672,58 @@ int PHYSFS_isSymbolicLink(const char *fname) } /* PHYSFS_isSymbolicLink */ -static PHYSFS_File *doOpenWrite(const char *_fname, int appending) +static PHYSFS_File *doOpenWrite(const char *_fname, const int appending) { FileHandle *fh = NULL; + DirHandle *h; size_t len; char *fname; 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); - - GOTO_IF(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, doOpenWriteEnd); - h = writeDir; - GOTO_IF_ERRPASS(!verifyPath(h, &fname, 0), doOpenWriteEnd); + __PHYSFS_platformGrabMutex(stateLock); - f = h->funcs; - if (appending) - io = f->openAppend(h->opaque, fname); - else - io = f->openWrite(h->opaque, fname); + h = writeDir; + BAIL_IF_MUTEX(!h, PHYSFS_ERR_NO_WRITE_DIR, stateLock, 0); - GOTO_IF_ERRPASS(!io, doOpenWriteEnd); + len = strlen(_fname) + dirHandleRootLen(h) + 1; + fname = (char *) __PHYSFS_smallAlloc(len); + BAIL_IF_MUTEX(!fname, PHYSFS_ERR_OUT_OF_MEMORY, stateLock, 0); - fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle)); - if (fh == NULL) - { - io->destroy(io); - GOTO(PHYSFS_ERR_OUT_OF_MEMORY, doOpenWriteEnd); - } /* if */ - else + if (sanitizePlatformIndependentPathWithRoot(h, _fname, fname)) + { + PHYSFS_Io *io = NULL; + char *arcfname = fname; + if (verifyPath(h, &arcfname, 0)) { - memset(fh, '\0', sizeof (FileHandle)); - fh->io = io; - fh->dirHandle = h; - fh->next = openWriteList; - openWriteList = fh; - } /* else */ + const PHYSFS_Archiver *f = h->funcs; + if (appending) + io = f->openAppend(h->opaque, arcfname); + else + io = f->openWrite(h->opaque, arcfname); - doOpenWriteEnd: - __PHYSFS_platformReleaseMutex(stateLock); + if (io) + { + fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle)); + if (fh == NULL) + { + io->destroy(io); + PHYSFS_setErrorCode(PHYSFS_ERR_OUT_OF_MEMORY); + } /* if */ + else + { + memset(fh, '\0', sizeof (FileHandle)); + fh->io = io; + fh->dirHandle = h; + fh->next = openWriteList; + openWriteList = fh; + } /* else */ + } /* if */ + } /* if */ } /* if */ + __PHYSFS_platformReleaseMutex(stateLock); + __PHYSFS_smallFree(fname); return ((PHYSFS_File *) fh); } /* doOpenWrite */ @@ -2612,22 +2744,25 @@ PHYSFS_File *PHYSFS_openAppend(const char *filename) PHYSFS_File *PHYSFS_openRead(const char *_fname) { FileHandle *fh = NULL; + char *allocated_fname; char *fname; size_t len; 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); + + __PHYSFS_platformGrabMutex(stateLock); + + 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)) { - DirHandle *i = NULL; PHYSFS_Io *io = NULL; - - __PHYSFS_platformGrabMutex(stateLock); - - GOTO_IF(!searchPath, PHYSFS_ERR_NOT_FOUND, openReadEnd); + DirHandle *i; for (i = searchPath; i != NULL; i = i->next) { @@ -2640,27 +2775,28 @@ PHYSFS_File *PHYSFS_openRead(const char *_fname) } /* if */ } /* for */ - GOTO_IF_ERRPASS(!io, openReadEnd); - - fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle)); - if (fh == NULL) + if (io) { - io->destroy(io); - GOTO(PHYSFS_ERR_OUT_OF_MEMORY, openReadEnd); + fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle)); + if (fh == NULL) + { + io->destroy(io); + PHYSFS_setErrorCode(PHYSFS_ERR_OUT_OF_MEMORY); + } /* if */ + else + { + memset(fh, '\0', sizeof (FileHandle)); + fh->io = io; + fh->forReading = 1; + fh->dirHandle = i; + fh->next = openReadList; + openReadList = fh; + } /* else */ } /* if */ - - memset(fh, '\0', sizeof (FileHandle)); - fh->io = io; - fh->forReading = 1; - fh->dirHandle = i; - fh->next = openReadList; - openReadList = fh; - - openReadEnd: - __PHYSFS_platformReleaseMutex(stateLock); } /* if */ - __PHYSFS_smallFree(fname); + __PHYSFS_platformReleaseMutex(stateLock); + __PHYSFS_smallFree(allocated_fname); return ((PHYSFS_File *) fh); } /* PHYSFS_openRead */ @@ -2993,14 +3129,12 @@ int PHYSFS_flush(PHYSFS_File *handle) int PHYSFS_stat(const char *_fname, PHYSFS_Stat *stat) { int retval = 0; + char *allocated_fname; char *fname; size_t len; BAIL_IF(!_fname, 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... */ stat->filesize = -1; @@ -3010,6 +3144,12 @@ int PHYSFS_stat(const char *_fname, PHYSFS_Stat *stat) stat->filetype = PHYSFS_FILETYPE_OTHER; 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 (*fname == '\0') @@ -3022,7 +3162,6 @@ int PHYSFS_stat(const char *_fname, PHYSFS_Stat *stat) { DirHandle *i; int exists = 0; - __PHYSFS_platformGrabMutex(stateLock); for (i = searchPath; ((i != NULL) && (!exists)); i = i->next) { char *arcfname = fname; @@ -3040,11 +3179,11 @@ int PHYSFS_stat(const char *_fname, PHYSFS_Stat *stat) exists = 1; } /* else if */ } /* for */ - __PHYSFS_platformReleaseMutex(stateLock); } /* else */ } /* if */ - __PHYSFS_smallFree(fname); + __PHYSFS_platformReleaseMutex(stateLock); + __PHYSFS_smallFree(allocated_fname); return retval; } /* PHYSFS_stat */ @@ -3142,7 +3281,7 @@ static void setDefaultAllocator(void) } /* 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' }; size_t alloclen; @@ -3150,6 +3289,8 @@ int __PHYSFS_DirTreeInit(__PHYSFS_DirTree *dt, const size_t entrylen) assert(entrylen >= sizeof (__PHYSFS_DirTreeEntry)); memset(dt, '\0', sizeof (*dt)); + dt->case_sensitive = case_sensitive; + dt->only_usascii = only_usascii; dt->root = (__PHYSFS_DirTreeEntry *) allocator.Malloc(entrylen); 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 */ -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 */ @@ -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. */ void *__PHYSFS_DirTreeFind(__PHYSFS_DirTree *dt, const char *path) { + const int cs = dt->case_sensitive; PHYSFS_uint32 hashval; __PHYSFS_DirTreeEntry *prev = NULL; __PHYSFS_DirTreeEntry *retval; @@ -3243,7 +3386,8 @@ void *__PHYSFS_DirTreeFind(__PHYSFS_DirTree *dt, const char *path) hashval = hashPathName(dt, path); 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 */ { diff --git a/modules/physfs/src/physfs.h b/modules/physfs/src/physfs.h index 1085550..6e55ce4 100644 --- a/modules/physfs/src/physfs.h +++ b/modules/physfs/src/physfs.h @@ -145,7 +145,7 @@ * - .ISO (ISO9660 files, CD-ROM images) * - .GRP (Build Engine groupfile archives) * - .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) * - .WAD (DOOM engine archives) * - .VDF (Gothic I/II engine archives) @@ -225,7 +225,9 @@ extern "C" { #if defined(PHYSFS_DECL) /* do nothing. */ -#elif defined(_MSC_VER) +#elif defined(PHYSFS_STATIC) +#define PHYSFS_DECL /**/ +#elif defined(_WIN32) || defined(__OS2__) #define PHYSFS_DECL __declspec(dllexport) #elif defined(__SUNPRO_C) #define PHYSFS_DECL __global @@ -433,8 +435,8 @@ typedef struct PHYSFS_Version #ifndef DOXYGEN_SHOULD_IGNORE_THIS #define PHYSFS_VER_MAJOR 3 -#define PHYSFS_VER_MINOR 0 -#define PHYSFS_VER_PATCH 2 +#define PHYSFS_VER_MINOR 2 +#define PHYSFS_VER_PATCH 0 #endif /* DOXYGEN_SHOULD_IGNORE_THIS */ @@ -493,6 +495,14 @@ typedef struct PHYSFS_Version 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) * \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 * 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. * This may be NULL on most platforms (such as ones without a * standard main() function), but you should always try to pass - * something in here. Unix-like systems such as Linux _need_ to - * pass argv[0] from main() in here. + * something in here. Many Unix-like systems _need_ to pass argv[0] + * from main() in here. See warning about Android, too! * \return nonzero on success, zero on error. Specifics of the error can be * 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. * + * \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. * * \sa PHYSFS_getPrefDir @@ -2702,10 +2732,10 @@ typedef PHYSFS_EnumerateCallbackResult (*PHYSFS_EnumerateCallback)(void *data, * * \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); - * 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. */ + +/** + * \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 } #endif diff --git a/modules/physfs/src/physfs_archiver_7z.c b/modules/physfs/src/physfs_archiver_7z.c index 914f691..44be3c9 100644 --- a/modules/physfs/src/physfs_archiver_7z.c +++ b/modules/physfs/src/physfs_archiver_7z.c @@ -185,7 +185,7 @@ static int szipLoadEntries(SZIPinfo *info) { 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; PHYSFS_uint32 i; @@ -285,13 +285,16 @@ static PHYSFS_Io *SZIP_openRead(void *opaque, const char *path) &blockIndex, &outBuffer, &outBufferSize, &offset, &outSizeProcessed, alloc, alloc); 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 = NULL; - buf = allocator.Malloc(outSizeProcessed); - GOTO_IF(rc != SZ_OK, PHYSFS_ERR_OUT_OF_MEMORY, SZIP_openRead_failed); - memcpy(buf, outBuffer + offset, outSizeProcessed); + buf = allocator.Malloc(outSizeProcessed ? outSizeProcessed : 1); + GOTO_IF(buf == NULL, PHYSFS_ERR_OUT_OF_MEMORY, SZIP_openRead_failed); + + if (outSizeProcessed > 0) + memcpy(buf, outBuffer + offset, outSizeProcessed); alloc->Free(alloc, outBuffer); outBuffer = NULL; diff --git a/modules/physfs/src/physfs_archiver_grp.c b/modules/physfs/src/physfs_archiver_grp.c index 758475e..9a2978a 100644 --- a/modules/physfs/src/physfs_archiver_grp.c +++ b/modules/physfs/src/physfs_archiver_grp.c @@ -76,7 +76,7 @@ static void *GRP_openArchive(PHYSFS_Io *io, const char *name, BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &count, sizeof(count)), NULL); count = PHYSFS_swapULE32(count); - unpkarc = UNPK_openArchive(io); + unpkarc = UNPK_openArchive(io, 0, 1); BAIL_IF_ERRPASS(!unpkarc, NULL); if (!grpLoadEntries(io, count, unpkarc)) diff --git a/modules/physfs/src/physfs_archiver_hog.c b/modules/physfs/src/physfs_archiver_hog.c index 832209f..a818478 100644 --- a/modules/physfs/src/physfs_archiver_hog.c +++ b/modules/physfs/src/physfs_archiver_hog.c @@ -1,9 +1,9 @@ /* * 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 * 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/) * + * 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. * - * This file written by Bradley Bell. - * Based on grp.c by Ryan C. Gordon. + * This file written by Bradley Bell and Ryan C. Gordon. */ #define __PHYSICSFS_INTERNAL__ @@ -34,7 +47,15 @@ #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); PHYSFS_uint32 pos = 3; @@ -45,11 +66,10 @@ static int hogLoadEntries(PHYSFS_Io *io, void *arc) char name[13]; 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. */ pos += 13 + 4; - size = PHYSFS_swapULE32(size); BAIL_IF_ERRPASS(!UNPK_addEntry(arc, name, 0, -1, -1, pos, size), 0); pos += size; @@ -60,24 +80,60 @@ static int hogLoadEntries(PHYSFS_Io *io, void *arc) return 1; } /* 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, int forWriting, int *claimed) { PHYSFS_uint8 buf[3]; void *unpkarc = NULL; + int hog1 = 0; assert(io != NULL); /* shouldn't ever happen. */ BAIL_IF(forWriting, PHYSFS_ERR_READ_ONLY, 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; - unpkarc = UNPK_openArchive(io); + unpkarc = UNPK_openArchive(io, 0, 1); BAIL_IF_ERRPASS(!unpkarc, NULL); - if (!hogLoadEntries(io, unpkarc)) + if (!(hog1 ? hog1LoadEntries(io, unpkarc) : hog2LoadEntries(io, unpkarc))) { UNPK_abandonArchive(unpkarc); return NULL; @@ -92,7 +148,7 @@ const PHYSFS_Archiver __PHYSFS_Archiver_HOG = CURRENT_PHYSFS_ARCHIVER_API_VERSION, { "HOG", - "Descent I/II HOG file format", + "Descent I/II/III HOG file format", "Bradley Bell ", "https://icculus.org/physfs/", 0, /* supportsSymlinks */ diff --git a/modules/physfs/src/physfs_archiver_iso9660.c b/modules/physfs/src/physfs_archiver_iso9660.c index 965c83f..e92d677 100644 --- a/modules/physfs/src/physfs_archiver_iso9660.c +++ b/modules/physfs/src/physfs_archiver_iso9660.c @@ -251,7 +251,7 @@ static int parseVolumeDescriptor(PHYSFS_Io *io, PHYSFS_uint64 *_rootpos, pos += 2048; /* each volume descriptor is 2048 bytes */ 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? */ { @@ -346,7 +346,8 @@ static void *ISO9660_openArchive(PHYSFS_Io *io, const char *filename, if (!parseVolumeDescriptor(io, &rootpos, &len, &joliet, claimed)) 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); if (!iso9660LoadEntries(io, joliet, "", rootpos, rootpos + len, unpkarc)) diff --git a/modules/physfs/src/physfs_archiver_mvl.c b/modules/physfs/src/physfs_archiver_mvl.c index 78b59f1..7a5c432 100644 --- a/modules/physfs/src/physfs_archiver_mvl.c +++ b/modules/physfs/src/physfs_archiver_mvl.c @@ -70,7 +70,7 @@ static void *MVL_openArchive(PHYSFS_Io *io, const char *name, BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &count, sizeof(count)), NULL); count = PHYSFS_swapULE32(count); - unpkarc = UNPK_openArchive(io); + unpkarc = UNPK_openArchive(io, 0, 1); BAIL_IF_ERRPASS(!unpkarc, NULL); if (!mvlLoadEntries(io, count, unpkarc)) diff --git a/modules/physfs/src/physfs_archiver_qpak.c b/modules/physfs/src/physfs_archiver_qpak.c index 15a5f2d..ddca271 100644 --- a/modules/physfs/src/physfs_archiver_qpak.c +++ b/modules/physfs/src/physfs_archiver_qpak.c @@ -86,7 +86,8 @@ static void *QPAK_openArchive(PHYSFS_Io *io, const char *name, 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); if (!qpakLoadEntries(io, count, unpkarc)) diff --git a/modules/physfs/src/physfs_archiver_slb.c b/modules/physfs/src/physfs_archiver_slb.c index 4fc28d4..58f3bc8 100644 --- a/modules/physfs/src/physfs_archiver_slb.c +++ b/modules/physfs/src/physfs_archiver_slb.c @@ -36,7 +36,7 @@ static int slbLoadEntries(PHYSFS_Io *io, const PHYSFS_uint32 count, void *arc) BAIL_IF(backslash != '\\', PHYSFS_ERR_CORRUPT, 0); /* 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 */ /* convert backslashes */ @@ -94,7 +94,8 @@ static void *SLB_openArchive(PHYSFS_Io *io, const char *name, /* seek to the table of contents */ 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); if (!slbLoadEntries(io, count, unpkarc)) diff --git a/modules/physfs/src/physfs_archiver_unpacked.c b/modules/physfs/src/physfs_archiver_unpacked.c index 575efef..fbb12a0 100644 --- a/modules/physfs/src/physfs_archiver_unpacked.c +++ b/modules/physfs/src/physfs_archiver_unpacked.c @@ -285,12 +285,12 @@ void *UNPK_addEntry(void *opaque, char *name, const int isdir, } /* 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)); 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); return NULL; diff --git a/modules/physfs/src/physfs_archiver_vdf.c b/modules/physfs/src/physfs_archiver_vdf.c index 99bbb2a..6d3a23f 100644 --- a/modules/physfs/src/physfs_archiver_vdf.c +++ b/modules/physfs/src/physfs_archiver_vdf.c @@ -129,7 +129,8 @@ static void *VDF_openArchive(PHYSFS_Io *io, const char *name, 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); if (!vdfLoadEntries(io, count, vdfDosTimeToEpoch(timestamp), unpkarc)) diff --git a/modules/physfs/src/physfs_archiver_wad.c b/modules/physfs/src/physfs_archiver_wad.c index b094c5b..d3ae045 100644 --- a/modules/physfs/src/physfs_archiver_wad.c +++ b/modules/physfs/src/physfs_archiver_wad.c @@ -95,7 +95,7 @@ static void *WAD_openArchive(PHYSFS_Io *io, const char *name, BAIL_IF_ERRPASS(!io->seek(io, directoryOffset), 0); - unpkarc = UNPK_openArchive(io); + unpkarc = UNPK_openArchive(io, 0, 1); BAIL_IF_ERRPASS(!unpkarc, NULL); if (!wadLoadEntries(io, count, unpkarc)) diff --git a/modules/physfs/src/physfs_archiver_zip.c b/modules/physfs/src/physfs_archiver_zip.c index 9972628..7327a61 100644 --- a/modules/physfs/src/physfs_archiver_zip.c +++ b/modules/physfs/src/physfs_archiver_zip.c @@ -15,6 +15,11 @@ #include #include +#if (PHYSFS_BYTEORDER == PHYSFS_LIL_ENDIAN) +#define MINIZ_LITTLE_ENDIAN 1 +#else +#define MINIZ_LITTLE_ENDIAN 0 +#endif #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)) return -1; - memcpy(&buf[maxread - 4], &extra, sizeof (extra)); + memcpy(&buf[maxread - 4], extra, sizeof (extra)); totalread += maxread - 4; } /* if */ else @@ -578,7 +583,7 @@ static PHYSFS_sint64 zip_find_end_of_central_dir(PHYSFS_Io *io, PHYSFS_sint64 *l totalread += maxread; } /* else */ - memcpy(&extra, buf, sizeof (extra)); + memcpy(extra, buf, sizeof (extra)); 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(ui32 != ZIP_LOCAL_FILE_SIG, PHYSFS_ERR_CORRUPT, 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); 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)) 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; root = (ZIPentry *) info->tree.root; diff --git a/modules/physfs/src/physfs_internal.h b/modules/physfs/src/physfs_internal.h index 2912623..2200d4d 100644 --- a/modules/physfs/src/physfs_internal.h +++ b/modules/physfs/src/physfs_internal.h @@ -38,7 +38,7 @@ #include #endif -#ifdef PHYSFS_PLATFORM_SOLARIS +#if defined(PHYSFS_PLATFORM_SOLARIS) || defined(PHYSFS_PLATFORM_LINUX) #include #endif @@ -69,7 +69,7 @@ extern "C" { All file-private symbols need to be marked "static". Everything shared between PhysicsFS sources needs to be in this 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 #endif @@ -95,6 +95,7 @@ extern const PHYSFS_Archiver __PHYSFS_Archiver_VDF; /* a real C99-compliant snprintf() is in Visual Studio 2015, but just use this everywhere for binary compatibility. */ #if defined(_MSC_VER) +#include 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, ...); #define vsnprintf __PHYSFS_msvc_vsnprintf @@ -108,14 +109,24 @@ const void *__PHYSFS_winrtCalcPrefDir(void); #endif /* atomic operations. */ +/* increment/decrement operations return the final incremented/decremented value. */ #if defined(_MSC_VER) && (_MSC_VER >= 1500) #include __PHYSFS_COMPILE_TIME_ASSERT(LongEqualsInt, sizeof (int) == sizeof (long)); #define __PHYSFS_ATOMIC_INCR(ptrval) _InterlockedIncrement((long*)(ptrval)) #define __PHYSFS_ATOMIC_DECR(ptrval) _InterlockedDecrement((long*)(ptrval)) #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_DECR(ptrval) __sync_fetch_and_add(ptrval, -1) +#define __PHYSFS_ATOMIC_INCR(ptrval) __sync_add_and_fetch(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 #define PHYSFS_NEED_ATOMIC_OP_FALLBACK 1 int __PHYSFS_ATOMIC_INCR(int *ptrval); @@ -213,6 +224,7 @@ extern void SZIP_global_init(void); /* The latest supported PHYSFS_Archiver::version value. */ #define CURRENT_PHYSFS_ARCHIVER_API_VERSION 0 + /* This byteorder stuff was lifted from SDL. https://www.libsdl.org/ */ #define PHYSFS_LIL_ENDIAN 1234 #define PHYSFS_BIG_ENDIAN 4321 @@ -220,11 +232,26 @@ extern void SZIP_global_init(void); #ifdef __linux__ #include #define PHYSFS_BYTEORDER __BYTE_ORDER -#else /* __linux__ */ +#elif defined(__OpenBSD__) || defined(__DragonFly__) +#include +#define PHYSFS_BYTEORDER BYTE_ORDER +#elif defined(__FreeBSD__) || defined(__NetBSD__) +#include +#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__) || \ defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \ - (defined(__MIPS__) && defined(__MISPEB__)) || \ - defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC) || \ + (defined(__MIPS__) && defined(__MIPSEB__)) || \ + defined(__ppc__) || defined(__POWERPC__) || defined(__powerpc__) || defined(__PPC__) || \ defined(__sparc__) #define PHYSFS_BYTEORDER PHYSFS_BIG_ENDIAN #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). */ -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. */ +/* 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_closeArchive(void *opaque); -void *UNPK_openArchive(PHYSFS_Io *io); void *UNPK_addEntry(void *opaque, char *name, const int isdir, const PHYSFS_sint64 ctime, const PHYSFS_sint64 mtime, 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. */ size_t hashBuckets; /* number of buckets in hash. */ 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; -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_DirTreeFind(__PHYSFS_DirTree *dt, const char *path); PHYSFS_EnumerateCallbackResult __PHYSFS_DirTreeEnumerate(void *opaque, @@ -715,6 +757,11 @@ int __PHYSFS_platformGrabMutex(void *mutex); */ void __PHYSFS_platformReleaseMutex(void *mutex); + +/* !!! FIXME: move to public API? */ +PHYSFS_uint32 __PHYSFS_utf8codepoint(const char **_str); + + #if PHYSFS_HAVE_PRAGMA_VISIBILITY #pragma GCC visibility pop #endif diff --git a/modules/physfs/src/physfs_lzmasdk.h b/modules/physfs/src/physfs_lzmasdk.h index c86972e..d2bbcc6 100644 --- a/modules/physfs/src/physfs_lzmasdk.h +++ b/modules/physfs/src/physfs_lzmasdk.h @@ -506,6 +506,7 @@ MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned mem #endif #if defined(MY_CPU_AMD64) \ + || defined(_M_ARM64) \ || defined(_M_IA64) \ || defined(__AARCH64EL__) \ || 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) #define MY_CPU_ARM_LE +#elif defined(_WIN64) && defined(_M_ARM64) +#define MY_CPU_ARM_LE #endif #if defined(_WIN32) && defined(_M_IA64) diff --git a/modules/physfs/src/physfs_miniz.h b/modules/physfs/src/physfs_miniz.h index 30d6f4c..e0fddb0 100644 --- a/modules/physfs/src/physfs_miniz.h +++ b/modules/physfs/src/physfs_miniz.h @@ -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_free_func)(void *opaque, void *address); +#ifndef MINIZ_LITTLE_ENDIAN /* if not defined by PHYSFS */ #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). */ #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 /* Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. */ #define MINIZ_LITTLE_ENDIAN 1 #endif +#endif /**/ #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) */ @@ -117,6 +119,8 @@ struct tinfl_decompressor_tag #define MZ_MAX(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_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 #define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) @@ -166,13 +170,17 @@ struct tinfl_decompressor_tag if (temp >= 0) { \ code_len = temp >> 9; \ if ((code_len) && (num_bits >= code_len)) \ - break; \ + break; \ } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \ code_len = TINFL_FAST_LOOKUP_BITS; \ do { \ temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ - } while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \ - } TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \ + } while ((temp < 0) && (num_bits >= (code_len + 1))); \ + 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); /* 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 { 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; } for ( ; (int)r->m_type >= 0; r->m_type--) { 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]]++; 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)); } @@ -699,3 +707,4 @@ static int mz_inflateEnd(mz_streamp pStream) For more information, please refer to */ + diff --git a/modules/physfs/src/physfs_platform_android.c b/modules/physfs/src/physfs_platform_android.c new file mode 100644 index 0000000..f892fed --- /dev/null +++ b/modules/physfs/src/physfs_platform_android.c @@ -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 +#include +#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 ... */ + diff --git a/modules/physfs/src/physfs_platform_apple.m b/modules/physfs/src/physfs_platform_apple.m index e6207f5..f98f10d 100644 --- a/modules/physfs/src/physfs_platform_apple.m +++ b/modules/physfs/src/physfs_platform_apple.m @@ -12,6 +12,7 @@ #ifdef PHYSFS_PLATFORM_APPLE #include +#include #include "physfs_internal.h" @@ -99,7 +100,7 @@ static int darwinIsWholeMedia(io_service_t service) } /* darwinIsWholeMedia */ -static int darwinIsMountedDisc(char *bsdName, mach_port_t masterPort) +static int darwinIsMountedDisc(char *bsdName, mach_port_t mainPort) { int retval = 0; CFMutableDictionaryRef matchingDict; @@ -107,10 +108,10 @@ static int darwinIsMountedDisc(char *bsdName, mach_port_t masterPort) io_iterator_t iter; io_service_t service; - if ((matchingDict = IOBSDNameMatching(masterPort, 0, bsdName)) == NULL) + if ((matchingDict = IOBSDNameMatching(mainPort, 0, bsdName)) == NULL) return 0; - rc = IOServiceGetMatchingServices(masterPort, matchingDict, &iter); + rc = IOServiceGetMatchingServices(mainPort, matchingDict, &iter); if ((rc != KERN_SUCCESS) || (!iter)) return 0; @@ -158,13 +159,25 @@ static int darwinIsMountedDisc(char *bsdName, mach_port_t masterPort) void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data) { #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 int prefixLen = strlen(devPrefix); - mach_port_t masterPort = 0; + mach_port_t mainPort = 0; struct statfs *mntbufp; 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*/; mounts = getmntinfo(&mntbufp, MNT_WAIT); /* NOT THREAD SAFE! */ @@ -176,7 +189,7 @@ void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data) continue; dev += prefixLen; - if (darwinIsMountedDisc(dev, masterPort)) + if (darwinIsMountedDisc(dev, mainPort)) cb(data, mnt); } /* for */ #endif /* !defined(PHYSFS_NO_CDROM_SUPPORT) */ diff --git a/modules/physfs/src/physfs_platform_os2.c b/modules/physfs/src/physfs_platform_os2.c index 8cc8044..bf47a9d 100644 --- a/modules/physfs/src/physfs_platform_os2.c +++ b/modules/physfs/src/physfs_platform_os2.c @@ -222,7 +222,7 @@ static char *cvtPathToCorrectCase(char *buf) if (ptr != NULL) /* isolate element to find (fname is the start). */ *ptr = '\0'; - rc = DosFindFirst((unsigned char *) spec, &hdir, FILE_DIRECTORY, + rc = DosFindFirst(spec, &hdir, FILE_DIRECTORY, &fb, sizeof (fb), &count, FIL_STANDARD); if (rc == NO_ERROR) { @@ -331,7 +331,7 @@ static int isCdRomDrive(ULONG drive) ULONG ul1, ul2; APIRET rc; HFILE hfile = NULLHANDLE; - unsigned char drivename[3] = { 0, ':', '\0' }; + char drivename[3] = { 0, ':', '\0' }; drivename[0] = 'A' + drive; @@ -443,7 +443,7 @@ PHYSFS_EnumerateCallbackResult __PHYSFS_platformEnumerate(const char *dirname, __PHYSFS_smallFree(utf8); BAIL_IF_ERRPASS(!cpspec, PHYSFS_ENUM_ERROR); - rc = DosFindFirst((unsigned char *) cpspec, &hdir, + rc = DosFindFirst(cpspec, &hdir, FILE_DIRECTORY | FILE_ARCHIVED | FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM, &fb, sizeof (fb), &count, FIL_STANDARD); @@ -535,7 +535,7 @@ int __PHYSFS_platformMkDir(const char *filename) APIRET rc; char *cpstr = cvtUtf8ToCodepage(filename); BAIL_IF_ERRPASS(!cpstr, 0); - rc = DosCreateDir((unsigned char *) cpstr, NULL); + rc = DosCreateDir(cpstr, NULL); allocator.Free(cpstr); BAIL_IF(rc != NO_ERROR, errcodeFromAPIRET(rc), 0); return 1; diff --git a/modules/physfs/src/physfs_platform_posix.c b/modules/physfs/src/physfs_platform_posix.c index fa2159c..7ba5e10 100644 --- a/modules/physfs/src/physfs_platform_posix.c +++ b/modules/physfs/src/physfs_platform_posix.c @@ -6,8 +6,6 @@ * This file written by Ryan C. Gordon. */ -/* !!! FIXME: check for EINTR? */ - #define __PHYSICSFS_INTERNAL__ #include "physfs_platforms.h" @@ -157,19 +155,41 @@ int __PHYSFS_platformMkDir(const char *path) } /* __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) { const int appending = (mode & O_APPEND); int fd; int *retval; + errno = 0; /* O_APPEND doesn't actually behave as we'd like. */ mode &= ~O_APPEND; - fd = open(filename, mode, S_IRUSR | S_IWUSR); +#ifdef O_CLOEXEC + /* Add O_CLOEXEC if defined */ + mode |= O_CLOEXEC; +#endif + + do { + fd = open(filename, mode, S_IRUSR | S_IWUSR); + } while ((fd < 0) && (errno == EINTR)); BAIL_IF(fd < 0, errcodeFromErrno(), NULL); +#if !defined(O_CLOEXEC) && defined(FD_CLOEXEC) + set_CLOEXEC(fd); +#endif + if (appending) { if (lseek(fd, 0, SEEK_END) < 0) @@ -219,7 +239,9 @@ PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer, if (!__PHYSFS_ui64FitsAddressSpace(len)) BAIL(PHYSFS_ERR_INVALID_ARGUMENT, -1); - rc = read(fd, buffer, (size_t) len); + do { + rc = read(fd, buffer, (size_t) len); + } while ((rc == -1) && (errno == EINTR)); BAIL_IF(rc == -1, errcodeFromErrno(), -1); assert(rc >= 0); assert(rc <= len); @@ -236,7 +258,9 @@ PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer, if (!__PHYSFS_ui64FitsAddressSpace(len)) BAIL(PHYSFS_ERR_INVALID_ARGUMENT, -1); - rc = write(fd, (void *) buffer, (size_t) len); + do { + rc = write(fd, (void *) buffer, (size_t) len); + } while ((rc == -1) && (errno == EINTR)); BAIL_IF(rc == -1, errcodeFromErrno(), rc); assert(rc >= 0); assert(rc <= len); @@ -275,8 +299,13 @@ PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque) int __PHYSFS_platformFlush(void *opaque) { const int fd = *((int *) opaque); - if ((fcntl(fd, F_GETFL) & O_ACCMODE) != O_RDONLY) - BAIL_IF(fsync(fd) == -1, errcodeFromErrno(), 0); + int rc = -1; + 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; } /* __PHYSFS_platformFlush */ @@ -284,7 +313,10 @@ int __PHYSFS_platformFlush(void *opaque) void __PHYSFS_platformClose(void *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); } /* __PHYSFS_platformClose */ diff --git a/modules/physfs/src/physfs_platform_windows.c b/modules/physfs/src/physfs_platform_windows.c index c92e98d..652300c 100644 --- a/modules/physfs/src/physfs_platform_windows.c +++ b/modules/physfs/src/physfs_platform_windows.c @@ -101,7 +101,7 @@ static char *unicodeToUtf8Heap(const WCHAR *w_str) 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, FindExSearchNameMatch, NULL, 0); #else @@ -111,7 +111,7 @@ static inline HANDLE winFindFirstFileW(const WCHAR *path, LPWIN32_FIND_DATAW d) 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); #else InitializeCriticalSection(lpcs); @@ -123,7 +123,7 @@ static inline HANDLE winCreateFileW(const WCHAR *wfname, const DWORD mode, const DWORD creation) { 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); #else 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, 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 linewpos; BOOL rc; @@ -158,7 +158,7 @@ static BOOL winSetFilePointer(HANDLE h, const PHYSFS_sint64 pos, static PHYSFS_sint64 winGetFileSize(HANDLE h) { - #ifdef PHYSFS_PLATFORM_WINRT + #if defined(PHYSFS_PLATFORM_WINRT) || (_WIN32_WINNT >= 0x0600) // Windows Vista+ FILE_STANDARD_INFO info; const BOOL rc = GetFileInformationByHandleEx(h, FileStandardInfo, &info, sizeof (info)); diff --git a/modules/physfs/src/physfs_platforms.h b/modules/physfs/src/physfs_platforms.h index d4e4bfd..1ac17d9 100644 --- a/modules/physfs/src/physfs_platforms.h +++ b/modules/physfs/src/physfs_platforms.h @@ -40,11 +40,11 @@ # define PHYSFS_PLATFORM_POSIX 1 #elif defined(macintosh) # error Classic Mac OS support was dropped from PhysicsFS 2.0. Move to OS X. -#elif defined(ANDROID) -# define PHYSFS_PLATFORM_LINUX 1 -# define PHYSFS_PLATFORM_UNIX 1 -# define PHYSFS_PLATFORM_POSIX 1 -# define PHYSFS_NO_CDROM_SUPPORT 1 +#elif defined(__ANDROID__) + # define PHYSFS_PLATFORM_LINUX 1 + # define PHYSFS_PLATFORM_ANDROID 1 + # define PHYSFS_PLATFORM_POSIX 1 + # define PHYSFS_NO_CDROM_SUPPORT 1 #elif defined(__linux) # define PHYSFS_PLATFORM_LINUX 1 # define PHYSFS_PLATFORM_UNIX 1 diff --git a/modules/physfs/src/physfs_unicode.c b/modules/physfs/src/physfs_unicode.c index 0e00602..bab4f8b 100644 --- a/modules/physfs/src/physfs_unicode.c +++ b/modules/physfs/src/physfs_unicode.c @@ -21,8 +21,8 @@ /* * This may not be the best value, but it's one that isn't represented * in Unicode (0x10FFFF is the largest codepoint value). We return this - * value from utf8codepoint() if there's bogus bits in the - * stream. utf8codepoint() will turn this value into something + * value from __PHYSFS_utf8codepoint() if there's bogus bits in the + * stream. __PHYSFS_utf8codepoint() will turn this value into something * reasonable (like a question mark), for text that wants to try to recover, * whereas utf8valid() will use the value to determine if a string has bad * bits. @@ -35,7 +35,7 @@ */ #define UNICODE_BOGUS_CHAR_CODEPOINT '?' -static PHYSFS_uint32 utf8codepoint(const char **_str) +PHYSFS_uint32 __PHYSFS_utf8codepoint(const char **_str) { const char *str = *_str; PHYSFS_uint32 retval = 0; @@ -188,6 +188,11 @@ static PHYSFS_uint32 utf8codepoint(const char **_str) } /* else if */ return UNICODE_BOGUS_CHAR_VALUE; +} /* __PHYSFS_utf8codepoint */ + +static inline PHYSFS_uint32 utf8codepoint(const char **_str) +{ + return __PHYSFS_utf8codepoint(_str); } /* utf8codepoint */ static PHYSFS_uint32 utf16codepoint(const PHYSFS_uint16 **_str) @@ -210,7 +215,7 @@ static PHYSFS_uint32 utf16codepoint(const PHYSFS_uint16 **_str) else { src++; /* eat the other surrogate. */ - cp = (((cp - 0xD800) << 10) | (pair - 0xDC00)); + cp = 0x10000 + (((cp - 0xD800) << 10) | (pair - 0xDC00)); } /* else */ } /* 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. */ while (len >= sizeof (PHYSFS_uint32)) { - PHYSFS_uint32 cp = utf8codepoint(&src); + PHYSFS_uint32 cp = __PHYSFS_utf8codepoint(&src); if (cp == 0) break; 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. */ while (len >= sizeof (PHYSFS_uint16)) { - PHYSFS_uint32 cp = utf8codepoint(&src); + PHYSFS_uint32 cp = __PHYSFS_utf8codepoint(&src); if (cp == 0) break; 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. */ while (len >= sizeof (PHYSFS_uint16)) { - PHYSFS_uint32 cp = utf8codepoint(&src); + PHYSFS_uint32 cp = __PHYSFS_utf8codepoint(&src); if (cp == 0) break; else if (cp == UNICODE_BOGUS_CHAR_VALUE) diff --git a/modules/physfs/test/test_physfs.c b/modules/physfs/test/test_physfs.c index 8ca2adf..3d0fbbe 100644 --- a/modules/physfs/test/test_physfs.c +++ b/modules/physfs/test/test_physfs.c @@ -31,8 +31,8 @@ #include "physfs.h" #define TEST_VERSION_MAJOR 3 -#define TEST_VERSION_MINOR 0 -#define TEST_VERSION_PATCH 2 +#define TEST_VERSION_MINOR 2 +#define TEST_VERSION_PATCH 0 static FILE *history_file = NULL; static PHYSFS_uint32 do_buffer_size = 0; @@ -288,6 +288,53 @@ static int cmd_getmountpoint(char *args) return 1; } /* 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) { if (*args == '\"') @@ -1340,6 +1387,7 @@ static const command_info commands[] = { "stressbuffer", cmd_stressbuffer, 1, "" }, { "crc32", cmd_crc32, 1, "" }, { "getmountpoint", cmd_getmountpoint, 1, "" }, + { "setroot", cmd_setroot, 2, " " }, { NULL, NULL, -1, NULL } };