├── test_mod.zip
├── .gitignore
├── physfs
├── README.txt
├── extras
│ ├── uninstall.sh
│ ├── README-CSharp.txt
│ ├── physfs.pc.in
│ ├── buildbot-emscripten.sh
│ ├── buildbot-raspberrypi.sh
│ ├── buildbot-checker.sh
│ ├── selfextract.c
│ ├── buildbot-os2.sh
│ ├── physfsrwops.h
│ ├── ignorecase.h
│ ├── physfsunpack.c
│ ├── abs-file.h
│ ├── ignorecase.c
│ ├── globbing.h
│ ├── globbing.c
│ ├── physfsrwops.c
│ ├── makecasefoldhashtable.pl
│ └── physfshttpd.c
├── docs
│ ├── CHANGELOG.txt
│ ├── README-API-documentation.txt
│ ├── TODO.txt
│ ├── CREDITS.txt
│ └── INSTALL.txt
├── LICENSE.txt
└── src
│ ├── physfs_platform_winrt.cpp
│ ├── Makefile.os2
│ ├── physfs_platforms.h
│ ├── physfs_archiver_mvl.c
│ ├── physfs_archiver_grp.c
│ ├── physfs_archiver_qpak.c
│ ├── physfs_archiver_csm.c
│ ├── physfs_platform_android.c
│ ├── physfs_archiver_wad.c
│ ├── physfs_archiver_slb.c
│ ├── physfs_platform_qnx.c
│ ├── physfs_platform_haiku.cpp
│ ├── physfs_byteorder.c
│ ├── physfs_archiver_dir.c
│ ├── physfs_archiver_hog.c
│ ├── physfs_archiver_vdf.c
│ ├── physfs_platform_apple.m
│ ├── physfs_archiver_unpacked.c
│ ├── physfs_platform_unix.c
│ └── physfs_platform_posix.c
├── osxbuild.sh
├── one.c
├── license.txt
├── .travis.yml
├── physfs-scm-2.rockspec
├── .github
└── workflows
│ └── test.yml
├── README.md
└── test.lua
/test_mod.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/starwing/lua-physfs/HEAD/test_mod.zip
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.gcov
2 | *.gcda
3 | *.gcno
4 | *.dll
5 | *.so
6 | *.o
7 | *.a
8 | tags
9 |
--------------------------------------------------------------------------------
/physfs/README.txt:
--------------------------------------------------------------------------------
1 |
2 | PhysicsFS; a portable, flexible file i/o abstraction.
3 |
4 | https://icculus.org/physfs/
5 |
6 | Please see the docs directory for documentation.
7 |
8 | Please see LICENSE.txt for licensing information.
9 |
10 |
--------------------------------------------------------------------------------
/physfs/extras/uninstall.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | if [ ! -f "./install_manifest.txt" ]; then
4 | echo "ERROR: This needs to be run from your CMake build directory after installing." 1>&2
5 | exit 1
6 | fi
7 |
8 | xargs rm -vf < install_manifest.txt
9 | exit 0
10 |
11 |
--------------------------------------------------------------------------------
/physfs/extras/README-CSharp.txt:
--------------------------------------------------------------------------------
1 | There used to be C# bindings in this directory, but they have been
2 | unmaintained for many years.
3 |
4 | Instead, there is a more modern PhysicsFS wrapper for .NET available.
5 |
6 | You can find it at https://github.com/frabert/SharpPhysFS
7 |
8 | Thanks to Francesco Bertolaccini for his efforts on that project!
9 |
10 | --ryan.
11 |
12 |
--------------------------------------------------------------------------------
/physfs/docs/CHANGELOG.txt:
--------------------------------------------------------------------------------
1 |
2 | The changelog is no longer maintained by hand. It made sense to have a single
3 | timeline when we were using CVS, but modern revision control tools make this
4 | redundant, at best.
5 |
6 | If you want a list of changes, updated in real time, just point your web
7 | browser here:
8 |
9 | https://github.com/icculus/physfs/commits/
10 |
11 |
12 |
--------------------------------------------------------------------------------
/physfs/extras/physfs.pc.in:
--------------------------------------------------------------------------------
1 | prefix=@CMAKE_INSTALL_PREFIX@
2 | exec_prefix=@CMAKE_INSTALL_PREFIX@
3 | libdir=@CMAKE_INSTALL_FULL_LIBDIR@
4 | includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
5 |
6 | Name: PhysicsFS
7 | Description: PhysicsFS is a library to provide abstract access to various archives.
8 | URL: https://icculus.org/physfs/
9 | Version: @PHYSFS_VERSION@
10 | Libs: -L${libdir} -lphysfs
11 | Cflags: -I${includedir}
12 |
--------------------------------------------------------------------------------
/osxbuild.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | clang -O3 -fPIC -bundle -undefined dynamic_lookup \
4 | -framework CoreServices -framework IOKit -o physfs.so \
5 | -DPHYSFS_SUPPORTS_7Z \
6 | -DPHYSFS_SUPPORTS_QPAK \
7 | -DPHYSFS_SUPPORTS_GRP \
8 | -DPHYSFS_SUPPORTS_HOG \
9 | -DPHYSFS_SUPPORTS_MVL \
10 | -DPHYSFS_SUPPORTS_WAD \
11 | -DPHYSFS_SUPPORTS_SLB \
12 | -DPHYSFS_SUPPORTS_ISO9660 \
13 | lua-physfs.c \
14 | one.c \
15 | physfs/src/physfs_platform_apple.m \
16 | physfs/src/physfs_platform_posix.c \
17 | physfs/src/physfs_platform_unix.c \
18 | physfs/src/physfs_platform_windows.c \
19 |
--------------------------------------------------------------------------------
/physfs/docs/README-API-documentation.txt:
--------------------------------------------------------------------------------
1 | The API documentation is readable in a few ways:
2 |
3 | - Read physfs.h; it's _heavily_ documented and the primary source of reference
4 | documentation for the library.
5 | - Run Doxygen over the header, which produces nicer-to-browse documentation in
6 | HTML, LaTeX, manpage, etc formats. This is done for you if Doxygen is
7 | installed and you build the "docs" target in whatever project files CMake
8 | generated for you.
9 | - Too much trouble? We generated the HTML reference for you, online here:
10 |
11 | https://icculus.org/physfs/docs/
12 |
13 | - We would love well-written tutorials for the latest version of PhysicsFS!
14 | If you write one, we would love to list it here. Drop me a line about it:
15 | icculus@icculus.org ... Thanks!
16 |
17 | --ryan.
18 |
19 |
--------------------------------------------------------------------------------
/one.c:
--------------------------------------------------------------------------------
1 | #include "physfs/src/physfs.c"
2 | #include "physfs/src/physfs_archiver_7z.c"
3 | #include "physfs/src/physfs_archiver_csm.c"
4 | #include "physfs/src/physfs_archiver_dir.c"
5 | #include "physfs/src/physfs_archiver_grp.c"
6 | #define readui32 hug_readui32
7 | #include "physfs/src/physfs_archiver_hog.c"
8 | #undef readui32
9 | #include "physfs/src/physfs_archiver_iso9660.c"
10 | #include "physfs/src/physfs_archiver_mvl.c"
11 | #include "physfs/src/physfs_archiver_qpak.c"
12 | #include "physfs/src/physfs_archiver_slb.c"
13 | #include "physfs/src/physfs_archiver_unpacked.c"
14 | #define readui32 vdf_readui32
15 | #include "physfs/src/physfs_archiver_vdf.c"
16 | #undef readui32
17 | #include "physfs/src/physfs_archiver_wad.c"
18 | #define readui32 zip_readui32
19 | #include "physfs/src/physfs_archiver_zip.c"
20 | #undef readui32
21 | #include "physfs/src/physfs_byteorder.c"
22 | #include "physfs/src/physfs_unicode.c"
23 |
24 |
--------------------------------------------------------------------------------
/physfs/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2001-2022 Ryan C. Gordon and others.
2 |
3 | This software is provided 'as-is', without any express or implied
4 | warranty. In no event will the authors be held liable for any damages
5 | arising from the use of this software.
6 |
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it
9 | freely, subject to the following restrictions:
10 |
11 | 1. The origin of this software must not be misrepresented; you must not
12 | claim that you wrote the original software. If you use this software
13 | in a product, an acknowledgment in the product documentation would be
14 | appreciated but is not required.
15 | 2. Altered source versions must be plainly marked as such, and must not be
16 | misrepresented as being the original software.
17 | 3. This notice may not be removed or altered from any source distribution.
18 |
--------------------------------------------------------------------------------
/license.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Xavier Wang
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/physfs/extras/buildbot-emscripten.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | if [ -z "$SDKDIR" ]; then
4 | SDKDIR="/emsdk"
5 | fi
6 |
7 | ENVSCRIPT="$SDKDIR/emsdk_env.sh"
8 | if [ ! -f "$ENVSCRIPT" ]; then
9 | echo "ERROR: This script expects the Emscripten SDK to be in '$SDKDIR'." 1>&2
10 | echo "ERROR: Set the \$SDKDIR environment variable to override this." 1>&2
11 | exit 1
12 | fi
13 |
14 | TARBALL="$1"
15 | if [ -z $1 ]; then
16 | TARBALL=physfs-emscripten.tar.xz
17 | fi
18 |
19 | cd `dirname "$0"`
20 | cd ..
21 | PHYSFSBASE=`pwd`
22 |
23 | echo "Setting up Emscripten SDK environment..."
24 | source "$ENVSCRIPT"
25 |
26 | echo "Setting up..."
27 | cd "$PHYSFSBASE"
28 | rm -rf buildbot
29 | mkdir buildbot
30 | cd buildbot
31 |
32 | echo "Configuring..."
33 | emcmake cmake -G "Ninja" -DPHYSFS_BUILD_SHARED=False -DCMAKE_BUILD_TYPE=MinSizeRel .. || exit $?
34 |
35 | echo "Building..."
36 | emmake cmake --build . --config MinSizeRel || exit $?
37 |
38 | set -e
39 | rm -rf "$TARBALL" physfs-emscripten
40 | mkdir -p physfs-emscripten
41 | echo "Archiving to '$TARBALL' ..."
42 | cp ../src/physfs.h libphysfs.a physfs-emscripten
43 | chmod -R a+r physfs-emscripten
44 | chmod a+x physfs-emscripten
45 | chmod -R go-w physfs-emscripten
46 | tar -cJvvf "$TARBALL" physfs-emscripten
47 | echo "Done."
48 |
49 | exit 0
50 |
51 | # end of emscripten-buildbot.sh ...
52 |
53 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: c
2 | sudo: false
3 |
4 | env:
5 | global:
6 | - LUAROCKS=2.4.2
7 | - ROCKSPEC=physfs-scm-1.rockspec
8 | matrix:
9 | - LUA="lua 5.1"
10 | - LUA="lua 5.2"
11 | - LUA="lua 5.3"
12 | - LUA="luajit 2.0"
13 | - LUA="luajit 2.1"
14 |
15 | branches:
16 | only:
17 | - master
18 |
19 | before_install:
20 | - pip install --user hererocks
21 | - hererocks env --$LUA -rlatest # Use latest LuaRocks, install into 'env' directory.
22 | - source env/bin/activate # Add directory with all installed binaries to PATH.
23 | # - luarocks install busted
24 | # - pip install cpp-coveralls
25 | # - luarocks install Lua-cURL --server=https://rocks.moonscript.org/dev
26 | # - luarocks install luacov-coveralls --server=https://rocks.moonscript.org/dev
27 | # - luarocks install lunitx
28 |
29 | install:
30 | # - sudo luarocks make $ROCKSPEC CFLAGS="-O2 -fPIC -ftest-coverage -fprofile-arcs" LIBFLAG="-shared --coverage"
31 | - luarocks make $ROCKSPEC CFLAGS="-O2 -fPIC" LIBFLAG="-shared"
32 |
33 | script:
34 | - lua test.lua
35 | # - lunit.sh test.lua
36 |
37 | #after_success:
38 | # - coveralls -b .. -r .. --dump c.report.json
39 | # - luacov-coveralls -j c.report.json -v
40 |
41 | notifications:
42 | email:
43 | on_success: change
44 | on_failure: always
45 |
46 | # vim: ft=yaml nu et sw=2 fdc=2 fdm=syntax
47 |
--------------------------------------------------------------------------------
/physfs/src/physfs_platform_winrt.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Windows Runtime (WinRT) support routines for PhysicsFS.
3 | *
4 | * Please see the file LICENSE.txt in the source's root directory.
5 | *
6 | * This file originally written by Martin "T-Bone" Ahrnbom, but was mostly
7 | * merged into physfs_platform_windows.c by Ryan C. Gordon (so please harass
8 | * Ryan about bugs and not Martin).
9 | */
10 |
11 | /* (There used to be instructions on how to make a WinRT project, but at
12 | this point, either CMake will do it for you or you should just drop
13 | PhysicsFS's sources into your existing project. --ryan.) */
14 |
15 | #define __PHYSICSFS_INTERNAL__
16 | #include "physfs_platforms.h"
17 |
18 | #ifdef PHYSFS_PLATFORM_WINRT
19 |
20 | #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
21 | #define _CRT_SECURE_NO_WARNINGS 1
22 | #endif
23 | #include
24 |
25 | #include "physfs_internal.h"
26 |
27 | const void *__PHYSFS_winrtCalcBaseDir(void)
28 | {
29 | return Windows::ApplicationModel::Package::Current->InstalledLocation->Path->Data();
30 | } /* __PHYSFS_winrtCalcBaseDir */
31 |
32 | const void *__PHYSFS_winrtCalcPrefDir(void)
33 | {
34 | return Windows::Storage::ApplicationData::Current->LocalFolder->Path->Data();
35 | } /* __PHYSFS_winrtCalcBaseDir */
36 |
37 |
38 | #endif /* PHYSFS_PLATFORM_WINRT */
39 |
40 | /* end of physfs_platform_winrt.cpp ... */
41 |
42 |
--------------------------------------------------------------------------------
/physfs-scm-2.rockspec:
--------------------------------------------------------------------------------
1 | package = "physfs"
2 | version = "scm-2"
3 |
4 | source = {
5 | url = "git://github.com/starwing/lua-physfs"
6 | }
7 |
8 | description = {
9 | homepage = "https://github.com/starwing/lua-physfs",
10 | license = "Lua License"
11 | }
12 |
13 | dependencies = {}
14 |
15 | build = {
16 | type = "builtin",
17 | platforms = {
18 | macosx = {
19 | type = "command",
20 | build_command = "sh osxbuild.sh",
21 | install = { lib = { physfs = "physfs.so" } }
22 | }
23 | },
24 | modules = {
25 | physfs = {
26 | defines = {
27 | "PHYSFS_SUPPORTS_7Z",
28 | "PHYSFS_SUPPORTS_QPAK",
29 | "PHYSFS_SUPPORTS_GRP",
30 | "PHYSFS_SUPPORTS_HOG",
31 | "PHYSFS_SUPPORTS_MVL",
32 | "PHYSFS_SUPPORTS_WAD",
33 | "PHYSFS_SUPPORTS_SLB",
34 | "PHYSFS_SUPPORTS_ISO9660",
35 | },
36 | sources = {
37 | "lua-physfs.c",
38 | "one.c",
39 | "physfs/src/physfs_platform_android.c",
40 | "physfs/src/physfs_platform_haiku.cpp",
41 | "physfs/src/physfs_platform_os2.c",
42 | "physfs/src/physfs_platform_posix.c",
43 | "physfs/src/physfs_platform_qnx.c",
44 | "physfs/src/physfs_platform_unix.c",
45 | "physfs/src/physfs_platform_windows.c",
46 | "physfs/src/physfs_platform_winrt.cpp",
47 | }
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/physfs/extras/buildbot-raspberrypi.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # This is the script physfs-buildbot.icculus.org uses to cross-compile
4 | # PhysicsFS from x86 Linux to Raspberry Pi. This script was originally from
5 | # Simple Directmedia Layer ( https://www.libsdl.org/ ).
6 |
7 | # The final tarball can be unpacked in the root directory of a RPi,
8 | # so the PhysicsFS install lands in /usr/local. Run ldconfig, and then
9 | # you should be able to build and run PhysicsFS-based software on your
10 | # Pi. Standard configure scripts should be able to find PhysicsFS and
11 | # build against it.
12 |
13 | TARBALL="$1"
14 | if [ -z $1 ]; then
15 | TARBALL=physfs-raspberrypi.tar.xz
16 | fi
17 |
18 | BUILDBOTDIR="buildbot"
19 | PARENTDIR="$PWD"
20 |
21 | set -e
22 | set -x
23 | rm -f $TARBALL
24 | rm -rf $BUILDBOTDIR
25 | mkdir -p $BUILDBOTDIR
26 | pushd $BUILDBOTDIR
27 |
28 | # the '-G "Ninja"' can be '-G "Unix Makefiles"' if you prefer to use GNU Make.
29 | SYSROOT="/opt/rpi-sysroot"
30 | cmake -G "Ninja" \
31 | -DCMAKE_C_COMPILER="/opt/rpi-tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/arm-linux-gnueabihf-gcc" \
32 | -DCMAKE_BUILD_TYPE=MinSizeRel \
33 | -DCMAKE_SYSROOT="$SYSROOT" \
34 | -DCMAKE_FIND_ROOT_PATH="$SYSROOT" \
35 | -DCMAKE_SYSTEM_NAME="Linux" \
36 | -DCMAKE_SYSTEM_VERSION=1 \
37 | -DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER \
38 | -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY \
39 | -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \
40 | ..
41 |
42 | cmake --build . --config MinSizeRel
43 |
44 | rm -rf "$TARBALL" physfs-raspberrypi
45 | mkdir -p physfs-raspberrypi
46 | echo "Archiving to '$TARBALL' ..."
47 | cp -a ../src/physfs.h libphysfs.a libphysfs.so* physfs-raspberrypi
48 | chmod -R a+r physfs-raspberrypi
49 | chmod a+x physfs-raspberrypi physfs-raspberrypi/*.so*
50 | chmod -R go-w physfs-raspberrypi
51 | tar -cJvvf "$TARBALL" physfs-raspberrypi
52 |
53 | set +x
54 | echo "Done."
55 |
56 |
57 |
--------------------------------------------------------------------------------
/physfs/extras/buildbot-checker.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # This is a script used by some Buildbot workers to push the project
4 | # through Clang's static analyzer and prepare the output to be uploaded
5 | # back to the buildmaster. You might find it useful too.
6 |
7 | # Install Clang (you already have it on Mac OS X, apt-get install clang
8 | # on Ubuntu, etc), Make sure "scan-build" is in your $PATH.
9 |
10 | FINALDIR="$1"
11 |
12 | set -x
13 | set -e
14 |
15 | cd `dirname "$0"`
16 | cd ..
17 |
18 | rm -rf checker-buildbot analysis
19 | if [ ! -z "$FINALDIR" ]; then
20 | rm -rf "$FINALDIR"
21 | fi
22 |
23 | mkdir checker-buildbot
24 | cd checker-buildbot
25 |
26 | # We turn off deprecated declarations, because we don't care about these warnings during static analysis.
27 | # The -Wno-liblto is new since our checker-279 upgrade, I think; checker otherwise warns "libLTO.dylib relative to clang installed dir not found"
28 |
29 | # You might want to do this for CMake-backed builds instead...
30 | 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" ..
31 |
32 | rm -rf analysis
33 | scan-build -o analysis cmake --build . --config Debug
34 |
35 | if [ `ls -A analysis |wc -l` == 0 ] ; then
36 | mkdir analysis/zarro
37 | echo 'Zarro boogsStatic analysis: no issues to report.' >analysis/zarro/index.html
38 | fi
39 |
40 | mv analysis/* ../analysis
41 | rmdir analysis # Make sure this is empty.
42 | cd ..
43 | chmod -R a+r analysis
44 | chmod -R go-w analysis
45 | find analysis -type d -exec chmod a+x {} \;
46 | if [ -x /usr/bin/xattr ]; then find analysis -exec /usr/bin/xattr -d com.apple.quarantine {} \; 2>/dev/null ; fi
47 |
48 | if [ ! -z "$FINALDIR" ]; then
49 | mv analysis "$FINALDIR"
50 | else
51 | FINALDIR=analysis
52 | fi
53 |
54 | rm -rf checker-buildbot
55 |
56 | echo "Done. Final output is in '$FINALDIR' ..."
57 |
58 | # end of checker-buildbot.sh ...
59 |
60 |
--------------------------------------------------------------------------------
/physfs/docs/TODO.txt:
--------------------------------------------------------------------------------
1 | Stuff that needs to be done and wishlist:
2 |
3 | These are in no particular order.
4 | Some might be dupes, some might be done already, some might be bad ideas.
5 |
6 |
7 | From https://icculus.org/pipermail/physfs/2009-March/000698.html ...
8 |
9 | - Write support for various archives. I haven't decided how to do this yet,
10 | but I'd like to.
11 | - Add an API to expose a file's extended attributes to the application?
12 | - Deprecate PHYSFS_setSaneConfig(). It really should have been in the extras
13 | directory.
14 | - Clean up the sources to match my ever-changing coding style. :)
15 |
16 |
17 |
18 | From https://icculus.org/pipermail/physfs/2010-January/000826.html ...
19 |
20 | - Lua bindings
21 |
22 |
23 | From https://icculus.org/pipermail/physfs/2010-January/000833.html ...
24 |
25 | - SWIG bindings
26 |
27 |
28 |
29 | From old TODO.txt...
30 |
31 | - Other archivers: perhaps tar(.gz|.bz2), RPM, ARJ, etc. These are less
32 | important, since streaming archives aren't of much value to games (which
33 | is why zipfiles are king: random access), but it could have uses for, say,
34 | an installer/updater.
35 | - Do symlinks in zip archiver work when they point to dirs?
36 | - Enable more warnings?
37 | - Use __cdecl in physfs.h?
38 | - Look for FIXMEs (many marked with "!!!" in comments).
39 | - fscanf and fprintf support in extras dir.
40 | - Sanity check byte order at runtime.
41 | - Memory locking?
42 | - General code audit.
43 | - Multiple write dirs with mount points?
44 |
45 |
46 | Other stuff I thought of...
47 | - moar asserts!
48 | - constify!
49 | - Does iPhone work?
50 | - Fix CMake vs Doxygen.
51 | - Doxygen replacement? (manpages suck.)
52 | - Fix coding standards to match.
53 | - See if we can ditch some #include lines...
54 | - LZMA support in zip archiver?
55 | - bzip2 support in zip archiver?
56 | - Reduce the BAIL and GOTO macro use. A lot of these don't add anything.
57 | - Change the term "search path" to something less confusing.
58 |
59 | Probably other stuff. Requests and recommendations are welcome.
60 |
61 | // end of TODO.txt ...
62 |
63 |
--------------------------------------------------------------------------------
/physfs/extras/selfextract.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This code shows how to read a zipfile included in an app's binary.
3 | *
4 | * License: this code is public domain. I make no warranty that it is useful,
5 | * correct, harmless, or environmentally safe.
6 | *
7 | * This particular file may be used however you like, including copying it
8 | * verbatim into a closed-source project, exploiting it commercially, and
9 | * removing any trace of my name from the source (although I hope you won't
10 | * do that). I welcome enhancements and corrections to this file, but I do
11 | * not require you to send me patches if you make changes. This code has
12 | * NO WARRANTY.
13 | *
14 | * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
15 | * Please see LICENSE.txt in the root of the source tree.
16 | *
17 | * This file was written by Ryan C. Gordon. (icculus@icculus.org).
18 | */
19 |
20 | /*
21 | * Compile this program and then attach a .zip file to the end of the
22 | * compiled binary.
23 | *
24 | * On Linux, something like this will build the final binary:
25 | * gcc -o selfextract.tmp selfextract.c -lphysfs && \
26 | * cat selfextract.tmp myzipfile.zip >> selfextract && \
27 | * chmod a+x selfextract && \
28 | * rm -f selfextract.tmp
29 | *
30 | * This may not work on all platforms, and it probably only works with
31 | * .zip files, since they are designed to be appended to another file.
32 | */
33 |
34 | #include
35 | #include "physfs.h"
36 |
37 | int main(int argc, char **argv)
38 | {
39 | int rc = 0;
40 |
41 | if (!PHYSFS_init(argv[0]))
42 | {
43 | printf("PHYSFS_init() failed: %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
44 | return 42;
45 | } /* if */
46 |
47 | rc = PHYSFS_addToSearchPath(argv[0], 0);
48 | if (!rc)
49 | {
50 | printf("Couldn't find self-extract data: %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
51 | printf("This might mean you didn't append a zipfile to the binary.\n");
52 | return 42;
53 | } /* if */
54 |
55 | char **files = PHYSFS_enumerateFiles("/");
56 | char **i;
57 | for (i = files; *i != NULL; i++)
58 | {
59 | const char *dirorfile = PHYSFS_isDirectory(*i) ? "Directory" : "File";
60 | printf(" * %s '%s' is in root of attached data.\n", dirorfile, *i);
61 | } /* for */
62 | PHYSFS_freeList(files);
63 |
64 | return 0;
65 | } /* main */
66 |
67 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | # This is a basic workflow to help you get started with Actions
2 |
3 | name: CI
4 |
5 | # Controls when the action will run.
6 | on:
7 | # Triggers the workflow on push or pull request events but only for the master branch
8 | push:
9 | branches: [ master ]
10 | pull_request:
11 | branches: [ master ]
12 |
13 | # Allows you to run this workflow manually from the Actions tab
14 | workflow_dispatch:
15 |
16 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
17 | jobs:
18 | test_ubuntu:
19 | if: "! contains(toJSON(github.event.commits.*.message), '[skip ci]')"
20 | runs-on: ${{ matrix.os }}
21 | env:
22 | ROCKSPEC: physfs-scm-2.rockspec
23 | strategy:
24 | matrix:
25 | luaVersion: ["5.1", "5.2", "5.3", "5.4", "luajit-2.0.5", "luajit-2.1.0-beta3"]
26 | os: ["ubuntu-latest"]
27 | steps:
28 | - name: Install LCov
29 | run: |
30 | sudo apt install libperlio-gzip-perl libjson-perl libcapture-tiny-perl libdatetime-perl
31 | wget "https://github.com/linux-test-project/lcov/archive/master.zip"
32 | unzip "master.zip"
33 | cd "lcov-master"
34 | sudo make install
35 | - uses: actions/checkout@master
36 | - name: Install Lua ${{ matrix.luaVersion }}
37 | uses: leafo/gh-actions-lua@master
38 | with:
39 | luaVersion: ${{ matrix.luaVersion }}
40 | - name: Install Luarocks
41 | uses: leafo/gh-actions-luarocks@master
42 | - name: Build
43 | run: |
44 | luarocks make $ROCKSPEC CFLAGS="-O3 -fPIC -Wall -Wextra --coverage" LIBFLAG="-shared --coverage"
45 | - name: Run Tests
46 | run: |
47 | lua test.lua
48 | - name: Run LCov
49 | run: |
50 | mkdir -p coverage
51 | lcov -c -d . -o coverage/lcov.info.all
52 | lcov -r coverage/lcov.info.all '/usr/*' 'physfs/src/*' -o coverage/lcov.info
53 | - name: Coveralls
54 | uses: coverallsapp/github-action@master
55 | with:
56 | github-token: ${{ secrets.GITHUB_TOKEN }}
57 | flag-name: run-${{ matrix.luaVersion }}
58 | parallel: true
59 | finish:
60 | needs: test_ubuntu
61 | runs-on: ubuntu-latest
62 | steps:
63 | - name: Coveralls Finished
64 | uses: coverallsapp/github-action@master
65 | with:
66 | github-token: ${{ secrets.github_token }}
67 | parallel-finished: true
68 |
--------------------------------------------------------------------------------
/physfs/extras/buildbot-os2.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # This is used by the buildbot to cross-compile for OS/2 from Linux, using
4 | # OpenWatcom. In an ideal world, we wouldn't need this, but we need a few
5 | # things to do this "properly" ...
6 | #
7 | # - OS/2 running as a VMware guest on the build machine
8 | # - Buildbot-worker running on that OS/2 guest
9 | # - CMake for OS/2 that...
10 | # - ... has Open Watcom compiler support and...
11 | # - ... a Watcom WMake project generator.
12 | #
13 | # Some of these things are doable (there is a CMake port for OS/2, you can
14 | # use GCC with it), but since OpenWatcom will just target OS/2 on Linux just
15 | # like it could on OS/2, it's easier and more efficient to just have a
16 | # buildbot script compile it here.
17 | #
18 | # Note that we just blast all the C files through the wcc386 compiler and
19 | # skip CMake entirely. We should fix this at some point.
20 |
21 | set -e
22 |
23 | ZIPFILE="$1"
24 | if [ -z $ZIPFILE ]; then
25 | ZIPFILE=physfs-os2.zip
26 | fi
27 |
28 | export WATCOM="/usr/local/share/watcom"
29 | export PATH="$PATH:$WATCOM/binl"
30 |
31 | CFLAGS="-i=\"$WATCOM/h;$WATCOM/h/os2;../src\" -wx -d0 -otexan -6r -zq -bt=os2 -fo=.obj -mf"
32 | WLIBFLAGS="-b -c -n -q -p=512"
33 |
34 | cd `dirname "$0"`
35 | cd ..
36 | mkdir -p buildbot
37 | cd buildbot
38 |
39 | rm -f test_physfs.obj
40 |
41 | OKAY="1"
42 | for src in ../src/*.c ; do
43 | echo wcc386 $src $CFLAGS
44 | wcc386 $src $CFLAGS || OKAY="0"
45 | done
46 |
47 | if [ "$OKAY" == "1" ]; then
48 | echo wlib $WLIBFLAGS physfs.lib *.obj
49 | wlib $WLIBFLAGS physfs.lib *.obj || OKAY="0"
50 | fi
51 |
52 | echo wcc386 ../test/test_physfs.c $CFLAGS
53 | wcc386 ../test/test_physfs.c $CFLAGS || OKAY="0"
54 |
55 | if [ "$OKAY" == "1" ]; then
56 | LDFLAGS="name test_physfs d all sys os2v2 op m libr physfs op q op symf FIL test_physfs.obj"
57 | echo wlink $LDFLAGS
58 | wlink $LDFLAGS || OKAY="0"
59 | fi
60 |
61 | if [ "$OKAY" == "1" ]; then
62 | F=`file test_physfs.exe`
63 | echo "$F"
64 | if [ "$F" != 'test_physfs.exe: MS-DOS executable, LX for OS/2 (console) i80386' ]; then
65 | echo 1>&2 "ERROR: final binary doesn't appear to be OS/2 executable."
66 | OKAY=0
67 | fi
68 | fi
69 |
70 | if [ "$OKAY" == "1" ]; then
71 | echo 1>&2 "Build succeeded."
72 | set -e
73 | rm -rf "$ZIPFILE" physfs-os2
74 | mkdir -p physfs-os2
75 | echo "Zipping to '$ZIPFILE' ..."
76 | cp ../src/physfs.h physfs.lib physfs-os2
77 | chmod -R a+r physfs-os2
78 | chmod a+x physfs-os2
79 | chmod -R go-w physfs-os2
80 | zip -9r "$ZIPFILE" physfs-os2
81 | echo "Done."
82 | exit 0
83 | else
84 | echo 1>&2 "Build failed."
85 | exit 1
86 | fi
87 |
88 |
--------------------------------------------------------------------------------
/physfs/src/Makefile.os2:
--------------------------------------------------------------------------------
1 | # Open Watcom makefile to build PhysicsFS for OS/2
2 | # wmake -f Makefile.os2
3 |
4 | LIBNAME = physfs
5 | VERSION = 3.3.0
6 |
7 | LIBFILE = $(LIBNAME).lib
8 | DLLFILE = $(LIBNAME).dll
9 | LNKFILE = $(LIBNAME).lnk
10 |
11 | TITLENAME = $(LIBNAME) $(VERSION)
12 |
13 | SRCS = physfs.c &
14 | physfs_byteorder.c &
15 | physfs_unicode.c &
16 | physfs_platform_os2.c &
17 | physfs_archiver_dir.c &
18 | physfs_archiver_unpacked.c &
19 | physfs_archiver_grp.c &
20 | physfs_archiver_hog.c &
21 | physfs_archiver_7z.c &
22 | physfs_archiver_mvl.c &
23 | physfs_archiver_qpak.c &
24 | physfs_archiver_wad.c &
25 | physfs_archiver_zip.c &
26 | physfs_archiver_slb.c &
27 | physfs_archiver_iso9660.c &
28 | physfs_archiver_csm.c &
29 | physfs_archiver_vdf.c
30 |
31 |
32 | OBJS = $(SRCS:.c=.obj)
33 |
34 | CFLAGS_BASE = -bt=os2 -d0 -q -bm -5s -fp5 -fpi87 -sg -oeatxh -ei -j
35 | CFLAGS_BASE+= -DNDEBUG
36 | # warnings:
37 | CFLAGS_BASE+= -wx
38 | # newer OpenWatcom versions enable W303 by default
39 | CFLAGS_BASE+= -wcd=303
40 | # include paths:
41 | CFLAGS_BASE+= -I"$(%WATCOM)/h/os2" -I"$(%WATCOM)/h"
42 | CFLAGS = $(CFLAGS_BASE)
43 | # to build a dll:
44 | CFLAGS+= -bd
45 |
46 | .extensions:
47 | .extensions: .lib .dll .obj .c
48 |
49 | all: $(DLLFILE) test_physfs.exe
50 |
51 | .c: decoders
52 | .c: examples
53 |
54 | $(LIBFILE): $(DLLFILE)
55 | @echo * Create library: $@...
56 | wlib -b -n -q -c -pa -s -t -zld -ii -io $@ $(DLLFILE)
57 |
58 | $(DLLFILE): $(OBJS) $(MODPLIB) $(TIMILIB) $(LNKFILE)
59 | @echo * Link: $@
60 | wlink @$(LNKFILE)
61 |
62 | $(LNKFILE):
63 | @%create $@
64 | @%append $@ SYSTEM os2v2_dll INITINSTANCE TERMINSTANCE
65 | @%append $@ NAME $(LIBNAME)
66 | @for %i in ($(OBJS)) do @%append $@ FILE %i
67 | @%append $@ OPTION QUIET
68 | @%append $@ OPTION DESCRIPTION '@$#icculus org:$(VERSION)$#@PhysicsFS'
69 | @%append $@ OPTION MAP=$^&.map
70 | @%append $@ OPTION ELIMINATE
71 | @%append $@ OPTION MANYAUTODATA
72 | @%append $@ OPTION OSNAME='OS/2 and eComStation'
73 | @%append $@ OPTION SHOWDEAD
74 |
75 | .c.obj:
76 | wcc386 $(CFLAGS) -fo=$^@ $<
77 |
78 | test_physfs.obj: "../test/test_physfs.c"
79 | wcc386 $(CFLAGS_BASE) -fo=$^@ $<
80 |
81 | test_physfs.exe: $(LIBFILE) test_physfs.obj
82 | @echo * Link: $@
83 | wlink SYS os2v2 LIBR {$(LIBFILE)} op q op el F {test_physfs.obj} N test_physfs.exe
84 |
85 | clean: .SYMBOLIC
86 | @echo * Clean: $(TITLENAME)
87 | @if exist *.obj rm *.obj
88 | @if exist *.err rm *.err
89 | @if exist $(LNKFILE) rm $(LNKFILE)
90 | distclean: .SYMBOLIC clean
91 | @if exist $(DLLFILE) rm $(DLLFILE)
92 | @if exist $(LIBFILE) rm $(LIBFILE)
93 | @if exist *.map rm *.map
94 | @if exist *.exe rm *.exe
95 |
--------------------------------------------------------------------------------
/physfs/docs/CREDITS.txt:
--------------------------------------------------------------------------------
1 | Maintainer and general codemonkey:
2 | Ryan C. Gordon
3 |
4 | Tons of win32 help:
5 | Adam Gates
6 |
7 | More win32 hacking:
8 | Gregory S. Read
9 |
10 | Fixes for missing current working directories,
11 | PHYSFS_setSaneConfig() improvements,
12 | other bugfixes:
13 | David Hedbor
14 |
15 | Darwin support:
16 | Patrick Stein
17 |
18 | configure fixes,
19 | RPM specfile:
20 | Edward Rudd
21 |
22 | GetLastModTime API,
23 | other stuff:
24 | John R. Hall
25 |
26 | Various support, fixes and suggestions:
27 | Alexander Pipelka
28 |
29 | Russian translation,
30 | QPAK archiver:
31 | Ed Sinjiashvili
32 |
33 | French translation:
34 | Stéphane Peter
35 |
36 | Debian package support:
37 | Colin Bayer
38 |
39 | "abs-file.h" in "extras" dir:
40 | Adam D. Moss
41 |
42 | WinCE port and other Win32 patches:
43 | Corona688
44 |
45 | German translation:
46 | Michael Renner
47 |
48 | Apple Project Builder support,
49 | Mac OS X improvements:
50 | Eric Wing
51 |
52 | iPhone support:
53 | Christian Gmeiner
54 |
55 | WinRT support:
56 | Martin Ahrnbom
57 |
58 | HOG archiver,
59 | MVL archiver:
60 | Bradley Bell
61 |
62 | MIX archiver:
63 | Sebastian Steinhauer
64 |
65 | Bug fixes:
66 | Tolga Dalman
67 |
68 | Initial PHYSFS_mount() work:
69 | Philip D. Bober
70 |
71 | Brazillian Portuguese translation:
72 | Danny Angelo Carminati Grein
73 |
74 | Spanish translation:
75 | Pedro J. Pérez
76 |
77 | MacOS Classic fixes,
78 | MPW support,
79 | bug fixes:
80 | Chris Taylor
81 |
82 | Mingw support,
83 | General bug fixes:
84 | Matze Braun
85 |
86 | Haiku support:
87 | scott mc
88 |
89 | Bug fixes:
90 | Jörg Walter
91 |
92 | Bug fixes:
93 | Olivier Boudeville
94 |
95 | Bug fixes:
96 | Henk Boom
97 |
98 | Build system fixes:
99 | Marc Kleine-Budde
100 |
101 | Windows .rc file,
102 | 7zip/lzma archiver:
103 | Dennis Schridde
104 |
105 | OS/2 updates:
106 | Dave Yeo
107 |
108 | Bug fixes:
109 | Patrice Mandin
110 |
111 | PHYSFS_stat() API:
112 | Christoph Nelles
113 | Indy Sams
114 |
115 | ISO9660 archiver:
116 | Christoph Nelles
117 |
118 | Bug fixes:
119 | Steven Fuller
120 |
121 | Bug fixes:
122 | Tolga Dalman
123 |
124 | Bug fixes:
125 | Frank Becker
126 |
127 | Bug fixes:
128 | Norfanin
129 |
130 | Bug fixes:
131 | Evgeny Podjachev
132 |
133 | Haiku fixes:
134 | Chris Roberts
135 |
136 | SLB archiver:
137 | Aleksi Nurmi
138 |
139 | Bug fixes:
140 | Dmitry Marakasov
141 |
142 | Bug fixes:
143 | Andreas Karlsson
144 |
145 | Bug fixes:
146 | Michael Bacon
147 |
148 | Bug fixes:
149 | Xian Nox
150 |
151 | Bug fixes:
152 | Reto Schneider
153 |
154 | pkg-config support:
155 | Jonas Kulla
156 |
157 | Bug fixes,
158 | VDF archiver:
159 | Francesco Bertolaccini
160 |
161 | CMake fixes:
162 | Tobias Markus
163 |
164 | Bug fixes,
165 | Rémi Verschelde
166 |
167 | Bug fixes:
168 | Rob Loach
169 |
170 | Other stuff:
171 | Your name here! Patches go to icculus@icculus.org ...
172 |
173 | /* end of CREDITS.txt ... */
174 |
175 |
--------------------------------------------------------------------------------
/physfs/src/physfs_platforms.h:
--------------------------------------------------------------------------------
1 | #ifndef _INCL_PHYSFS_PLATFORMS
2 | #define _INCL_PHYSFS_PLATFORMS
3 |
4 | #ifndef __PHYSICSFS_INTERNAL__
5 | #error Do not include this header from your applications.
6 | #endif
7 |
8 | /*
9 | * These only define the platforms to determine which files in the platforms
10 | * directory should be compiled. For example, technically BeOS can be called
11 | * a "unix" system, but since it doesn't use unix.c, we don't define
12 | * PHYSFS_PLATFORM_UNIX on that system.
13 | */
14 |
15 | #if (defined __HAIKU__)
16 | # define PHYSFS_PLATFORM_HAIKU 1
17 | # define PHYSFS_PLATFORM_POSIX 1
18 | #elif ((defined __BEOS__) || (defined __beos__))
19 | # error BeOS support was dropped since PhysicsFS 2.1. Sorry. Try Haiku!
20 | #elif (defined _WIN32_WCE) || (defined _WIN64_WCE)
21 | # error PocketPC support was dropped since PhysicsFS 2.1. Sorry. Try WinRT!
22 | #elif (defined(_MSC_VER) && (_MSC_VER >= 1700) && !_USING_V110_SDK71_) /* _MSC_VER==1700 for MSVC 2012 */
23 | # include
24 | # define PHYSFS_PLATFORM_WINDOWS 1
25 | # if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
26 | # define PHYSFS_NO_CDROM_SUPPORT 1
27 | # define PHYSFS_PLATFORM_WINRT 1
28 | # endif
29 | #elif (((defined _WIN32) || (defined _WIN64)) && (!defined __CYGWIN__))
30 | # define PHYSFS_PLATFORM_WINDOWS 1
31 | #elif defined(__OS2__) || defined(OS2)
32 | # define PHYSFS_PLATFORM_OS2 1
33 | #elif ((defined __MACH__) && (defined __APPLE__))
34 | /* To check if iOS or not, we need to include this file */
35 | # include
36 | # if ((TARGET_IPHONE_SIMULATOR) || (TARGET_OS_IPHONE))
37 | # define PHYSFS_NO_CDROM_SUPPORT 1
38 | # endif
39 | # define PHYSFS_PLATFORM_APPLE 1
40 | # define PHYSFS_PLATFORM_POSIX 1
41 | #elif defined(macintosh)
42 | # error Classic Mac OS support was dropped from PhysicsFS 2.0. Move to OS X.
43 | #elif defined(__ANDROID__)
44 | # define PHYSFS_PLATFORM_LINUX 1
45 | # define PHYSFS_PLATFORM_ANDROID 1
46 | # define PHYSFS_PLATFORM_POSIX 1
47 | # define PHYSFS_NO_CDROM_SUPPORT 1
48 | #elif defined(__linux)
49 | # define PHYSFS_PLATFORM_LINUX 1
50 | # define PHYSFS_PLATFORM_UNIX 1
51 | # define PHYSFS_PLATFORM_POSIX 1
52 | #elif defined(__sun) || defined(sun)
53 | # define PHYSFS_PLATFORM_SOLARIS 1
54 | # define PHYSFS_PLATFORM_UNIX 1
55 | # define PHYSFS_PLATFORM_POSIX 1
56 | #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
57 | # define PHYSFS_PLATFORM_FREEBSD 1
58 | # define PHYSFS_PLATFORM_BSD 1
59 | # define PHYSFS_PLATFORM_UNIX 1
60 | # define PHYSFS_PLATFORM_POSIX 1
61 | #elif defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__)
62 | # define PHYSFS_PLATFORM_BSD 1
63 | # define PHYSFS_PLATFORM_UNIX 1
64 | # define PHYSFS_PLATFORM_POSIX 1
65 | #elif defined(__EMSCRIPTEN__)
66 | # define PHYSFS_NO_CDROM_SUPPORT 1
67 | # define PHYSFS_PLATFORM_UNIX 1
68 | # define PHYSFS_PLATFORM_POSIX 1
69 | #elif defined(__QNX__)
70 | # define PHYSFS_PLATFORM_QNX 1
71 | # define PHYSFS_PLATFORM_POSIX 1
72 | #elif defined(unix) || defined(__unix__)
73 | # define PHYSFS_PLATFORM_UNIX 1
74 | # define PHYSFS_PLATFORM_POSIX 1
75 | #else
76 | # error Unknown platform.
77 | #endif
78 |
79 | #endif /* include-once blocker. */
80 |
81 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | physfs binding for Lua
2 | ----------------------
3 | [](https://github.com/starwing/lua-physfs/actions?query=branch%3Amaster)[](https://coveralls.io/github/starwing/lua-physfs?branch=master)
4 |
5 | lua-physfs is a [physfs][1] binding for the Lua language. it expose
6 | most physfs API, except the `mountIo()` and `register()` routines.
7 |
8 | [1]: https://github.com/icculus/physfs
9 | [2]: https://luarocks.org
10 |
11 | PhysicsFS is a library to provide abstract access to various archives.
12 |
13 | to use this binding, easiest way is use [luarocks][2]:
14 |
15 | ```
16 | luarocks install physfs
17 | ```
18 |
19 | this library is in Lua license, same as the Lua language.
20 |
21 | API List
22 | -------------
23 |
24 | - physfs.File:
25 | - `#file -> number|error`
26 | - `file:buffSize(number) -> file|(nil, errmsg)`
27 | - `file:close() -> file|(nil, errmsg)`
28 | - `file:eof() -> boolean`
29 | - `file:flush() -> file|(nil, errmsg)`
30 | - `file:length() -> number|(nil, errmsg)`
31 | - `file:read(fmt...) -> (nil|number|string)...`
32 | - `file:seek(number) -> file|(nil, errmsg)`
33 | - `file:tell() -> number|(nil, errmsg)`
34 | - `file:write(string...) -> file|(nil, errmsg)`
35 | - `file:writeInt(fmt, number...) -> file|(nil, errmsg)`
36 | - `tostring(file) -> string`
37 |
38 | - `physfs.cdRomDirs([table]) -> table, number`
39 | - `physfs.convInt(fmt, number...) -> number...`
40 | - `physfs.delete(string) -> string|(nil, errmsg)`
41 | - `physfs.exists(string) -> boolean`
42 | - `physfs.files(string[, table]) -> table, number`
43 | - `physfs.lastError() -> string`
44 | - `physfs.lastError(string) -> none`
45 | - `physfs.mkdir(string) -> string|(nil, errmsg)`
46 | - `physfs.mount(name[, point[, preppend]]) -> name|(nil, errmsg)`
47 | - `physfs.mountFile(file[, name[, point[, preppend]]]) -> file|(nil, errmsg)`
48 | - `physfs.mountMemory(string[, name[, point[, preppend]]]) -> string|(nil, errmsg)`
49 | - `physfs.mountPoint(string) -> string`
50 | - `physfs.openAppend(string) -> file|(nil, errmsg)`
51 | - `physfs.openRead(string) -> file|(nil, errmsg)`
52 | - `physfs.openWrite(string) -> file|(nil, errmsg)`
53 | - `physfs.prefDir(org, app) -> org|(nil, errmsg)`
54 | - `physfs.realDir(string) -> string`
55 | - `physfs.saneConfig(org, app[, ext[, includeCdRoms[, archiveFirst]]]) -> org|(nil, errmsg)`
56 | - `physfs.searchPath([table]) -> table, number`
57 | - `physfs.stat(string[, table]) -> table`
58 | - `physfs.supportedArchiveTypes([table]) -> table, number`
59 | - `physfs.unmount(string) -> string|(nil, errmsg)`
60 | - `physfs.useSymlink() -> boolean`
61 | - `physfs.useSymlink(boolean) -> none`
62 | - `physfs.version() -> number, number, number`
63 | - `physfs.writeDir() -> string`
64 | - `physfs.writeDir(string) -> string|(nil, errmsg)`
65 |
66 |
--------------------------------------------------------------------------------
/physfs/src/physfs_archiver_mvl.c:
--------------------------------------------------------------------------------
1 | /*
2 | * MVL support routines for PhysicsFS.
3 | *
4 | * This driver handles Descent II Movielib archives.
5 | *
6 | * The file format of MVL is quite easy...
7 | *
8 | * //MVL File format - Written by Heiko Herrmann
9 | * char sig[4] = {'D','M', 'V', 'L'}; // "DMVL"=Descent MoVie Library
10 | *
11 | * int num_files; // the number of files in this MVL
12 | *
13 | * struct {
14 | * char file_name[13]; // Filename, padded to 13 bytes with 0s
15 | * int file_size; // filesize in bytes
16 | * }DIR_STRUCT[num_files];
17 | *
18 | * struct {
19 | * char data[file_size]; // The file data
20 | * }FILE_STRUCT[num_files];
21 | *
22 | * (That info is from http://www.descent2.com/ddn/specs/mvl/)
23 | *
24 | * Please see the file LICENSE.txt in the source's root directory.
25 | *
26 | * This file written by Bradley Bell.
27 | * Based on grp.c by Ryan C. Gordon.
28 | */
29 |
30 | #define __PHYSICSFS_INTERNAL__
31 | #include "physfs_internal.h"
32 |
33 | #if PHYSFS_SUPPORTS_MVL
34 |
35 | static int mvlLoadEntries(PHYSFS_Io *io, const PHYSFS_uint32 count, void *arc)
36 | {
37 | PHYSFS_uint32 pos = 8 + (17 * count); /* past sig+metadata. */
38 | PHYSFS_uint32 i;
39 |
40 | for (i = 0; i < count; i++)
41 | {
42 | PHYSFS_uint32 size;
43 | char name[13];
44 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, name, 13), 0);
45 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &size, 4), 0);
46 | name[12] = '\0'; /* just in case. */
47 | size = PHYSFS_swapULE32(size);
48 | BAIL_IF_ERRPASS(!UNPK_addEntry(arc, name, 0, -1, -1, pos, size), 0);
49 | pos += size;
50 | } /* for */
51 |
52 | return 1;
53 | } /* mvlLoadEntries */
54 |
55 |
56 | static void *MVL_openArchive(PHYSFS_Io *io, const char *name,
57 | int forWriting, int *claimed)
58 | {
59 | PHYSFS_uint8 buf[4];
60 | PHYSFS_uint32 count = 0;
61 | void *unpkarc;
62 |
63 | assert(io != NULL); /* shouldn't ever happen. */
64 | BAIL_IF(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
65 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, buf, 4), NULL);
66 | BAIL_IF(memcmp(buf, "DMVL", 4) != 0, PHYSFS_ERR_UNSUPPORTED, NULL);
67 |
68 | *claimed = 1;
69 |
70 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &count, sizeof(count)), NULL);
71 | count = PHYSFS_swapULE32(count);
72 |
73 | unpkarc = UNPK_openArchive(io, 0, 1);
74 | BAIL_IF_ERRPASS(!unpkarc, NULL);
75 |
76 | if (!mvlLoadEntries(io, count, unpkarc))
77 | {
78 | UNPK_abandonArchive(unpkarc);
79 | return NULL;
80 | } /* if */
81 |
82 | return unpkarc;
83 | } /* MVL_openArchive */
84 |
85 |
86 | const PHYSFS_Archiver __PHYSFS_Archiver_MVL =
87 | {
88 | CURRENT_PHYSFS_ARCHIVER_API_VERSION,
89 | {
90 | "MVL",
91 | "Descent II Movielib format",
92 | "Bradley Bell ",
93 | "https://icculus.org/physfs/",
94 | 0, /* supportsSymlinks */
95 | },
96 | MVL_openArchive,
97 | UNPK_enumerate,
98 | UNPK_openRead,
99 | UNPK_openWrite,
100 | UNPK_openAppend,
101 | UNPK_remove,
102 | UNPK_mkdir,
103 | UNPK_stat,
104 | UNPK_closeArchive
105 | };
106 |
107 | #endif /* defined PHYSFS_SUPPORTS_MVL */
108 |
109 | /* end of physfs_archiver_mvl.c ... */
110 |
111 |
--------------------------------------------------------------------------------
/physfs/extras/physfsrwops.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This code provides a glue layer between PhysicsFS and Simple Directmedia
3 | * Layer's (SDL) RWops i/o abstraction.
4 | *
5 | * License: this code is public domain. I make no warranty that it is useful,
6 | * correct, harmless, or environmentally safe.
7 | *
8 | * This particular file may be used however you like, including copying it
9 | * verbatim into a closed-source project, exploiting it commercially, and
10 | * removing any trace of my name from the source (although I hope you won't
11 | * do that). I welcome enhancements and corrections to this file, but I do
12 | * not require you to send me patches if you make changes. This code has
13 | * NO WARRANTY.
14 | *
15 | * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
16 | * Please see LICENSE.txt in the root of the source tree.
17 | *
18 | * SDL 1.2 falls under the LGPL license. SDL 1.3+ is zlib, like PhysicsFS.
19 | * You can get SDL at https://www.libsdl.org/
20 | *
21 | * This file was written by Ryan C. Gordon. (icculus@icculus.org).
22 | */
23 |
24 | #ifndef _INCLUDE_PHYSFSRWOPS_H_
25 | #define _INCLUDE_PHYSFSRWOPS_H_
26 |
27 | #include "physfs.h"
28 | #include "SDL.h"
29 |
30 | #ifdef __cplusplus
31 | extern "C" {
32 | #endif
33 |
34 | /**
35 | * Open a platform-independent filename for reading, and make it accessible
36 | * via an SDL_RWops structure. The file will be closed in PhysicsFS when the
37 | * RWops is closed. PhysicsFS should be configured to your liking before
38 | * opening files through this method.
39 | *
40 | * @param filename File to open in platform-independent notation.
41 | * @return A valid SDL_RWops structure on success, NULL on error. Specifics
42 | * of the error can be gleaned from PHYSFS_getLastError().
43 | */
44 | PHYSFS_DECL SDL_RWops *PHYSFSRWOPS_openRead(const char *fname);
45 |
46 | /**
47 | * Open a platform-independent filename for writing, and make it accessible
48 | * via an SDL_RWops structure. The file will be closed in PhysicsFS when the
49 | * RWops is closed. PhysicsFS should be configured to your liking before
50 | * opening files through this method.
51 | *
52 | * @param filename File to open in platform-independent notation.
53 | * @return A valid SDL_RWops structure on success, NULL on error. Specifics
54 | * of the error can be gleaned from PHYSFS_getLastError().
55 | */
56 | PHYSFS_DECL SDL_RWops *PHYSFSRWOPS_openWrite(const char *fname);
57 |
58 | /**
59 | * Open a platform-independent filename for appending, and make it accessible
60 | * via an SDL_RWops structure. The file will be closed in PhysicsFS when the
61 | * RWops is closed. PhysicsFS should be configured to your liking before
62 | * opening files through this method.
63 | *
64 | * @param filename File to open in platform-independent notation.
65 | * @return A valid SDL_RWops structure on success, NULL on error. Specifics
66 | * of the error can be gleaned from PHYSFS_getLastError().
67 | */
68 | PHYSFS_DECL SDL_RWops *PHYSFSRWOPS_openAppend(const char *fname);
69 |
70 | /**
71 | * Make a SDL_RWops from an existing PhysicsFS file handle. You should
72 | * dispose of any references to the handle after successful creation of
73 | * the RWops. The actual PhysicsFS handle will be destroyed when the
74 | * RWops is closed.
75 | *
76 | * @param handle a valid PhysicsFS file handle.
77 | * @return A valid SDL_RWops structure on success, NULL on error. Specifics
78 | * of the error can be gleaned from PHYSFS_getLastError().
79 | */
80 | PHYSFS_DECL SDL_RWops *PHYSFSRWOPS_makeRWops(PHYSFS_File *handle);
81 |
82 | #ifdef __cplusplus
83 | }
84 | #endif
85 |
86 | #endif /* include-once blocker */
87 |
88 | /* end of physfsrwops.h ... */
89 |
90 |
--------------------------------------------------------------------------------
/physfs/extras/ignorecase.h:
--------------------------------------------------------------------------------
1 | #ifndef INCL_PHYSFSEXT_IGNORECASE_H
2 | #define INCL_PHYSFSEXT_IGNORECASE_H
3 |
4 | /** \file ignorecase.h */
5 |
6 | /**
7 | * \mainpage PhysicsFS ignorecase
8 | *
9 | * This is an extension to PhysicsFS to let you handle files in a
10 | * case-insensitive manner, regardless of what sort of filesystem or
11 | * archive they reside in. It does this by enumerating directories as
12 | * needed and manually locating matching entries.
13 | *
14 | * Please note that this brings with it some caveats:
15 | * - On filesystems that are case-insensitive to start with, such as those
16 | * used on Windows or MacOS, you are adding extra overhead.
17 | * - On filesystems that are case-sensitive, you might select the wrong dir
18 | * or file (which brings security considerations and potential bugs). This
19 | * code favours exact case matches, but you will lose access to otherwise
20 | * duplicate filenames, or you might go down a wrong directory tree, etc.
21 | * In practice, this is rarely a problem, but you need to be aware of it.
22 | * - This doesn't do _anything_ with the write directory; you're on your
23 | * own for opening the right files for writing. You can sort of get around
24 | * this by adding your write directory to the search path, but then the
25 | * interpolated directory tree can screw you up even more.
26 | *
27 | * This code should be considered an aid for legacy code. New development
28 | * shouldn't do things that require this aid in the first place. :)
29 | *
30 | * Usage: Set up PhysicsFS as you normally would, then use
31 | * PHYSFSEXT_locateCorrectCase() to get a "correct" pathname to pass to
32 | * functions like PHYSFS_openRead(), etc.
33 | *
34 | * License: this code is public domain. I make no warranty that it is useful,
35 | * correct, harmless, or environmentally safe.
36 | *
37 | * This particular file may be used however you like, including copying it
38 | * verbatim into a closed-source project, exploiting it commercially, and
39 | * removing any trace of my name from the source (although I hope you won't
40 | * do that). I welcome enhancements and corrections to this file, but I do
41 | * not require you to send me patches if you make changes. This code has
42 | * NO WARRANTY.
43 | *
44 | * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
45 | * Please see LICENSE.txt in the root of the source tree.
46 | *
47 | * \author Ryan C. Gordon.
48 | */
49 |
50 | #ifdef __cplusplus
51 | extern "C" {
52 | #endif
53 |
54 | /**
55 | * \fn int PHYSFSEXT_locateCorrectCase(char *buf)
56 | * \brief Find an existing filename with matching case.
57 | *
58 | * This function will look for a path/filename that matches the passed in
59 | * buffer. Each element of the buffer's path is checked for a
60 | * case-insensitive match. The buffer must specify a null-terminated string
61 | * in platform-independent notation.
62 | *
63 | * Please note results may be skewed differently depending on whether symlinks
64 | * are enabled or not.
65 | *
66 | * Each element of the buffer is overwritten with the actual case of an
67 | * existing match. If there is no match, the search aborts and reports an
68 | * error. Exact matches are favored over case-insensitive matches.
69 | *
70 | * THIS IS RISKY. Please do not use this function for anything but legacy code.
71 | *
72 | * \param buf Buffer with null-terminated string of path/file to locate.
73 | * This buffer will be modified by this function.
74 | * \return zero if match was found, -1 if the final element (the file itself)
75 | * is missing, -2 if one of the parent directories is missing.
76 | */
77 | int PHYSFSEXT_locateCorrectCase(char *buf);
78 |
79 | #ifdef __cplusplus
80 | }
81 | #endif
82 |
83 | #endif /* include-once blocker. */
84 |
85 | /* end of ignorecase.h ... */
86 |
87 |
--------------------------------------------------------------------------------
/physfs/src/physfs_archiver_grp.c:
--------------------------------------------------------------------------------
1 | /*
2 | * GRP support routines for PhysicsFS.
3 | *
4 | * This driver handles BUILD engine archives ("groupfiles"). This format
5 | * (but not this driver) was put together by Ken Silverman.
6 | *
7 | * The format is simple enough. In Ken's words:
8 | *
9 | * What's the .GRP file format?
10 | *
11 | * The ".grp" file format is just a collection of a lot of files stored
12 | * into 1 big one. I tried to make the format as simple as possible: The
13 | * first 12 bytes contains my name, "KenSilverman". The next 4 bytes is
14 | * the number of files that were compacted into the group file. Then for
15 | * each file, there is a 16 byte structure, where the first 12 bytes are
16 | * the filename, and the last 4 bytes are the file's size. The rest of
17 | * the group file is just the raw data packed one after the other in the
18 | * same order as the list of files.
19 | *
20 | * (That info is from http://www.advsys.net/ken/build.htm ...)
21 | *
22 | * Please see the file LICENSE.txt in the source's root directory.
23 | *
24 | * This file written by Ryan C. Gordon.
25 | */
26 |
27 | #define __PHYSICSFS_INTERNAL__
28 | #include "physfs_internal.h"
29 |
30 | #if PHYSFS_SUPPORTS_GRP
31 |
32 | static int grpLoadEntries(PHYSFS_Io *io, const PHYSFS_uint32 count, void *arc)
33 | {
34 | PHYSFS_uint32 pos = 16 + (16 * count); /* past sig+metadata. */
35 | PHYSFS_uint32 i;
36 |
37 | for (i = 0; i < count; i++)
38 | {
39 | char *ptr;
40 | char name[13];
41 | PHYSFS_uint32 size;
42 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, name, 12), 0);
43 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &size, 4), 0);
44 |
45 | name[12] = '\0'; /* name isn't null-terminated in file. */
46 | if ((ptr = strchr(name, ' ')) != NULL)
47 | *ptr = '\0'; /* trim extra spaces. */
48 |
49 | size = PHYSFS_swapULE32(size);
50 | BAIL_IF_ERRPASS(!UNPK_addEntry(arc, name, 0, -1, -1, pos, size), 0);
51 |
52 | pos += size;
53 | } /* for */
54 |
55 | return 1;
56 | } /* grpLoadEntries */
57 |
58 |
59 | static void *GRP_openArchive(PHYSFS_Io *io, const char *name,
60 | int forWriting, int *claimed)
61 | {
62 | PHYSFS_uint8 buf[12];
63 | PHYSFS_uint32 count = 0;
64 | void *unpkarc = NULL;
65 |
66 | assert(io != NULL); /* shouldn't ever happen. */
67 |
68 | BAIL_IF(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
69 |
70 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, buf, sizeof (buf)), NULL);
71 | if (memcmp(buf, "KenSilverman", sizeof (buf)) != 0)
72 | BAIL(PHYSFS_ERR_UNSUPPORTED, NULL);
73 |
74 | *claimed = 1;
75 |
76 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &count, sizeof(count)), NULL);
77 | count = PHYSFS_swapULE32(count);
78 |
79 | unpkarc = UNPK_openArchive(io, 0, 1);
80 | BAIL_IF_ERRPASS(!unpkarc, NULL);
81 |
82 | if (!grpLoadEntries(io, count, unpkarc))
83 | {
84 | UNPK_abandonArchive(unpkarc);
85 | return NULL;
86 | } /* if */
87 |
88 | return unpkarc;
89 | } /* GRP_openArchive */
90 |
91 |
92 | const PHYSFS_Archiver __PHYSFS_Archiver_GRP =
93 | {
94 | CURRENT_PHYSFS_ARCHIVER_API_VERSION,
95 | {
96 | "GRP",
97 | "Build engine Groupfile format",
98 | "Ryan C. Gordon ",
99 | "https://icculus.org/physfs/",
100 | 0, /* supportsSymlinks */
101 | },
102 | GRP_openArchive,
103 | UNPK_enumerate,
104 | UNPK_openRead,
105 | UNPK_openWrite,
106 | UNPK_openAppend,
107 | UNPK_remove,
108 | UNPK_mkdir,
109 | UNPK_stat,
110 | UNPK_closeArchive
111 | };
112 |
113 | #endif /* defined PHYSFS_SUPPORTS_GRP */
114 |
115 | /* end of physfs_archiver_grp.c ... */
116 |
117 |
--------------------------------------------------------------------------------
/physfs/src/physfs_archiver_qpak.c:
--------------------------------------------------------------------------------
1 | /*
2 | * QPAK support routines for PhysicsFS.
3 | *
4 | * This archiver handles the archive format utilized by Quake 1 and 2.
5 | * Quake3-based games use the PkZip/Info-Zip format (which our
6 | * physfs_archiver_zip.c handles).
7 | *
8 | * ========================================================================
9 | *
10 | * This format info (in more detail) comes from:
11 | * https://web.archive.org/web/20040209101748/http://debian.fmi.uni-sofia.bg/~sergei/cgsr/docs/pak.txt
12 | *
13 | * Quake PAK Format
14 | *
15 | * Header
16 | * (4 bytes) signature = 'PACK'
17 | * (4 bytes) directory offset
18 | * (4 bytes) directory length
19 | *
20 | * Directory
21 | * (56 bytes) file name
22 | * (4 bytes) file position
23 | * (4 bytes) file length
24 | *
25 | * ========================================================================
26 | *
27 | * Please see the file LICENSE.txt in the source's root directory.
28 | *
29 | * This file written by Ryan C. Gordon.
30 | */
31 |
32 | #define __PHYSICSFS_INTERNAL__
33 | #include "physfs_internal.h"
34 |
35 | #if PHYSFS_SUPPORTS_QPAK
36 |
37 | #define QPAK_SIG 0x4B434150 /* "PACK" in ASCII. */
38 |
39 | static int qpakLoadEntries(PHYSFS_Io *io, const PHYSFS_uint32 count, void *arc)
40 | {
41 | PHYSFS_uint32 i;
42 | for (i = 0; i < count; i++)
43 | {
44 | PHYSFS_uint32 size;
45 | PHYSFS_uint32 pos;
46 | char name[56];
47 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, name, 56), 0);
48 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &pos, 4), 0);
49 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &size, 4), 0);
50 | size = PHYSFS_swapULE32(size);
51 | pos = PHYSFS_swapULE32(pos);
52 | BAIL_IF_ERRPASS(!UNPK_addEntry(arc, name, 0, -1, -1, pos, size), 0);
53 | } /* for */
54 |
55 | return 1;
56 | } /* qpakLoadEntries */
57 |
58 |
59 | static void *QPAK_openArchive(PHYSFS_Io *io, const char *name,
60 | int forWriting, int *claimed)
61 | {
62 | PHYSFS_uint32 val = 0;
63 | PHYSFS_uint32 pos = 0;
64 | PHYSFS_uint32 count = 0;
65 | void *unpkarc;
66 |
67 | assert(io != NULL); /* shouldn't ever happen. */
68 |
69 | BAIL_IF(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
70 |
71 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &val, 4), NULL);
72 | if (PHYSFS_swapULE32(val) != QPAK_SIG)
73 | BAIL(PHYSFS_ERR_UNSUPPORTED, NULL);
74 |
75 | *claimed = 1;
76 |
77 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &val, 4), NULL);
78 | pos = PHYSFS_swapULE32(val); /* directory table offset. */
79 |
80 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &val, 4), NULL);
81 | count = PHYSFS_swapULE32(val);
82 |
83 | /* corrupted archive? */
84 | BAIL_IF((count % 64) != 0, PHYSFS_ERR_CORRUPT, NULL);
85 | count /= 64;
86 |
87 | BAIL_IF_ERRPASS(!io->seek(io, pos), NULL);
88 |
89 | /* !!! FIXME: check case_sensitive and only_usascii params for this archive. */
90 | unpkarc = UNPK_openArchive(io, 1, 0);
91 | BAIL_IF_ERRPASS(!unpkarc, NULL);
92 |
93 | if (!qpakLoadEntries(io, count, unpkarc))
94 | {
95 | UNPK_abandonArchive(unpkarc);
96 | return NULL;
97 | } /* if */
98 |
99 | return unpkarc;
100 | } /* QPAK_openArchive */
101 |
102 |
103 | const PHYSFS_Archiver __PHYSFS_Archiver_QPAK =
104 | {
105 | CURRENT_PHYSFS_ARCHIVER_API_VERSION,
106 | {
107 | "PAK",
108 | "Quake I/II format",
109 | "Ryan C. Gordon ",
110 | "https://icculus.org/physfs/",
111 | 0, /* supportsSymlinks */
112 | },
113 | QPAK_openArchive,
114 | UNPK_enumerate,
115 | UNPK_openRead,
116 | UNPK_openWrite,
117 | UNPK_openAppend,
118 | UNPK_remove,
119 | UNPK_mkdir,
120 | UNPK_stat,
121 | UNPK_closeArchive
122 | };
123 |
124 | #endif /* defined PHYSFS_SUPPORTS_QPAK */
125 |
126 | /* end of physfs_archiver_qpak.c ... */
127 |
128 |
--------------------------------------------------------------------------------
/physfs/src/physfs_archiver_csm.c:
--------------------------------------------------------------------------------
1 | /*
2 | * CSM support routines for PhysicsFS.
3 | *
4 | * This driver handles Chasm: The Rift engine archives ("CSM.BINs").
5 | * This format (but not this driver) was developed by Action Forms Ltd.
6 | * and published by Megamedia for use with the Chasm: The Rift engine.
7 | * The specs of the format are from http://github.com/Panzerschrek/Chasm-Reverse
8 | * The format of the archive: (from the specs)
9 | *
10 | * A CSM file has three parts:
11 | * (1) a 6 byte header
12 | * (2) a TOC that contains the names, offsets, and
13 | * sizes of all the entries in the CSM.BIN
14 | *
15 | * The header consists of three four-byte parts:
16 | * (a) an ASCII string which must be "CSid"
17 | * (b) a uint16 which is the number of TOC entries in the CSM.BIN
18 | *
19 | * The TOC has one -byte entry for every lump. Each entry consists
20 | * of three parts:
21 | *
22 | * (a) a uint8, the length of the filename
23 | * (b) an 12-byte ASCII string, the name of the entry, padded with zeros.
24 | * (c) a uint32, the size of the entry in bytes
25 | * (d) a uint32, the file offset to the start of the entry
26 | *
27 | *
28 | *
29 | * Please see the file LICENSE.txt in the source's root directory.
30 | *
31 | * This file written by Jon Daniel, based on the WAD archiver by
32 | * Travis Wells.
33 | */
34 |
35 | #define __PHYSICSFS_INTERNAL__
36 | #include "physfs_internal.h"
37 |
38 | #if PHYSFS_SUPPORTS_CSM
39 |
40 | static int csmLoadEntries(PHYSFS_Io *io, const PHYSFS_uint16 count, void *arc)
41 | {
42 | PHYSFS_uint16 i;
43 | for (i = 0; i < count; i++)
44 | {
45 | PHYSFS_uint8 fn_len;
46 | char name[12];
47 | PHYSFS_uint32 size;
48 | PHYSFS_uint32 pos;
49 |
50 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &fn_len, 1), 0);
51 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, name, 12), 0);
52 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &size, 4), 0);
53 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &pos, 4), 0);
54 |
55 | if(fn_len > 12) fn_len = 12;
56 | name[fn_len] = '\0'; /* name might not be null-terminated in file. */
57 | size = PHYSFS_swapULE32(size);
58 | pos = PHYSFS_swapULE32(pos);
59 | BAIL_IF_ERRPASS(!UNPK_addEntry(arc, name, 0, -1, -1, pos, size), 0);
60 | } /* for */
61 |
62 | return 1;
63 | } /* csmLoadEntries */
64 |
65 |
66 | static void *CSM_openArchive(PHYSFS_Io *io, const char *name,
67 | int forWriting, int *claimed)
68 | {
69 | PHYSFS_uint8 buf[4];
70 | PHYSFS_uint16 count;
71 | void *unpkarc;
72 |
73 | assert(io != NULL); /* shouldn't ever happen. */
74 |
75 | BAIL_IF(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
76 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, buf, sizeof (buf)), NULL);
77 | if (memcmp(buf, "CSid", 4) != 0)
78 | BAIL(PHYSFS_ERR_UNSUPPORTED, NULL);
79 |
80 | *claimed = 1;
81 |
82 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &count, sizeof (count)), NULL);
83 | count = PHYSFS_swapULE16(count);
84 |
85 |
86 | unpkarc = UNPK_openArchive(io, 0, 1);
87 | BAIL_IF_ERRPASS(!unpkarc, NULL);
88 |
89 | if (!csmLoadEntries(io, count, unpkarc))
90 | {
91 | UNPK_abandonArchive(unpkarc);
92 | return NULL;
93 | } /* if */
94 |
95 | return unpkarc;
96 | } /* CSM_openArchive */
97 |
98 |
99 | const PHYSFS_Archiver __PHYSFS_Archiver_CSM =
100 | {
101 | CURRENT_PHYSFS_ARCHIVER_API_VERSION,
102 | {
103 | "BIN",
104 | "Chasm: The Rift engine format",
105 | "Jon Daniel ",
106 | "http://www.github.com/Panzerschrek/Chasm-Reverse",
107 | 0, /* supportsSymlinks */
108 | },
109 | CSM_openArchive,
110 | UNPK_enumerate,
111 | UNPK_openRead,
112 | UNPK_openWrite,
113 | UNPK_openAppend,
114 | UNPK_remove,
115 | UNPK_mkdir,
116 | UNPK_stat,
117 | UNPK_closeArchive
118 | };
119 |
120 | #endif /* defined PHYSFS_SUPPORTS_CSM */
121 |
122 | /* end of physfs_archiver_CSM.c ... */
123 |
124 |
--------------------------------------------------------------------------------
/physfs/src/physfs_platform_android.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Android support routines for PhysicsFS.
3 | *
4 | * Please see the file LICENSE.txt in the source's root directory.
5 | *
6 | * This file written by Ryan C. Gordon.
7 | */
8 |
9 | #define __PHYSICSFS_INTERNAL__
10 | #include "physfs_platforms.h"
11 |
12 | #ifdef PHYSFS_PLATFORM_ANDROID
13 |
14 | #include
15 | #include
16 | #include "physfs_internal.h"
17 |
18 | static char *prefpath = NULL;
19 |
20 |
21 | int __PHYSFS_platformInit(void)
22 | {
23 | return 1; /* always succeed. */
24 | } /* __PHYSFS_platformInit */
25 |
26 |
27 | void __PHYSFS_platformDeinit(void)
28 | {
29 | if (prefpath)
30 | {
31 | allocator.Free(prefpath);
32 | prefpath = NULL;
33 | } /* if */
34 | } /* __PHYSFS_platformDeinit */
35 |
36 |
37 | void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
38 | {
39 | /* no-op. */
40 | } /* __PHYSFS_platformDetectAvailableCDs */
41 |
42 |
43 | char *__PHYSFS_platformCalcBaseDir(const char *argv0)
44 | {
45 | /* as a cheat, we expect argv0 to be a PHYSFS_AndroidInit* on Android. */
46 | PHYSFS_AndroidInit *ainit = (PHYSFS_AndroidInit *) argv0;
47 | char *retval = NULL;
48 | JNIEnv *jenv = NULL;
49 | jobject jcontext;
50 |
51 | if (ainit == NULL)
52 | return __PHYSFS_strdup("/"); /* oh well. */
53 |
54 | jenv = (JNIEnv *) ainit->jnienv;
55 | jcontext = (jobject) ainit->context;
56 |
57 | if ((*jenv)->PushLocalFrame(jenv, 16) >= 0)
58 | {
59 | jobject jfileobj = 0;
60 | jmethodID jmeth = 0;
61 | jthrowable jexception = 0;
62 | jstring jstr = 0;
63 |
64 | jmeth = (*jenv)->GetMethodID(jenv, (*jenv)->GetObjectClass(jenv, jcontext), "getPackageResourcePath", "()Ljava/lang/String;");
65 | jstr = (jstring)(*jenv)->CallObjectMethod(jenv, jcontext, jmeth);
66 | jexception = (*jenv)->ExceptionOccurred(jenv); /* this can't throw an exception, right? Just in case. */
67 | if (jexception != NULL)
68 | (*jenv)->ExceptionClear(jenv);
69 | else
70 | {
71 | const char *path = (*jenv)->GetStringUTFChars(jenv, jstr, NULL);
72 | retval = __PHYSFS_strdup(path);
73 | (*jenv)->ReleaseStringUTFChars(jenv, jstr, path);
74 | } /* else */
75 |
76 | /* We only can rely on the Activity being valid during this function call,
77 | so go ahead and grab the prefpath too. */
78 | jmeth = (*jenv)->GetMethodID(jenv, (*jenv)->GetObjectClass(jenv, jcontext), "getFilesDir", "()Ljava/io/File;");
79 | jfileobj = (*jenv)->CallObjectMethod(jenv, jcontext, jmeth);
80 | if (jfileobj)
81 | {
82 | jmeth = (*jenv)->GetMethodID(jenv, (*jenv)->GetObjectClass(jenv, jfileobj), "getCanonicalPath", "()Ljava/lang/String;");
83 | jstr = (jstring)(*jenv)->CallObjectMethod(jenv, jfileobj, jmeth);
84 | jexception = (*jenv)->ExceptionOccurred(jenv);
85 | if (jexception != NULL)
86 | (*jenv)->ExceptionClear(jenv);
87 | else
88 | {
89 | const char *path = (*jenv)->GetStringUTFChars(jenv, jstr, NULL);
90 | const size_t len = strlen(path) + 2;
91 | prefpath = allocator.Malloc(len);
92 | if (prefpath)
93 | snprintf(prefpath, len, "%s/", path);
94 | (*jenv)->ReleaseStringUTFChars(jenv, jstr, path);
95 | } /* else */
96 | } /* if */
97 |
98 | (*jenv)->PopLocalFrame(jenv, NULL);
99 | } /* if */
100 |
101 | /* we can't return NULL because then PhysicsFS will treat argv0 as a string, but it's a non-NULL jobject! */
102 | if (retval == NULL)
103 | retval = __PHYSFS_strdup("/"); /* we pray this works. */
104 |
105 | return retval;
106 | } /* __PHYSFS_platformCalcBaseDir */
107 |
108 |
109 | char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
110 | {
111 | return __PHYSFS_strdup(prefpath ? prefpath : "/");
112 | } /* __PHYSFS_platformCalcPrefDir */
113 |
114 | #endif /* PHYSFS_PLATFORM_ANDROID */
115 |
116 | /* end of physfs_platform_android.c ... */
117 |
118 |
--------------------------------------------------------------------------------
/physfs/src/physfs_archiver_wad.c:
--------------------------------------------------------------------------------
1 | /*
2 | * WAD support routines for PhysicsFS.
3 | *
4 | * This driver handles DOOM engine archives ("wads").
5 | * This format (but not this driver) was designed by id Software for use
6 | * with the DOOM engine.
7 | * The specs of the format are from the unofficial doom specs v1.666
8 | * found here: http://www.gamers.org/dhs/helpdocs/dmsp1666.html
9 | * The format of the archive: (from the specs)
10 | *
11 | * A WAD file has three parts:
12 | * (1) a twelve-byte header
13 | * (2) one or more "lumps"
14 | * (3) a directory or "info table" that contains the names, offsets, and
15 | * sizes of all the lumps in the WAD
16 | *
17 | * The header consists of three four-byte parts:
18 | * (a) an ASCII string which must be either "IWAD" or "PWAD"
19 | * (b) a uint32 which is the number of lumps in the wad
20 | * (c) a uint32 which is the file offset to the start of
21 | * the directory
22 | *
23 | * The directory has one 16-byte entry for every lump. Each entry consists
24 | * of three parts:
25 | *
26 | * (a) a uint32, the file offset to the start of the lump
27 | * (b) a uint32, the size of the lump in bytes
28 | * (c) an 8-byte ASCII string, the name of the lump, padded with zeros.
29 | * For example, the "DEMO1" entry in hexadecimal would be
30 | * (44 45 4D 4F 31 00 00 00)
31 | *
32 | * Note that there is no way to tell if an opened WAD archive is a
33 | * IWAD or PWAD with this archiver.
34 | * I couldn't think of a way to provide that information, without being too
35 | * hacky.
36 | * I don't think it's really that important though.
37 | *
38 | *
39 | * Please see the file LICENSE.txt in the source's root directory.
40 | *
41 | * This file written by Travis Wells, based on the GRP archiver by
42 | * Ryan C. Gordon.
43 | */
44 |
45 | #define __PHYSICSFS_INTERNAL__
46 | #include "physfs_internal.h"
47 |
48 | #if PHYSFS_SUPPORTS_WAD
49 |
50 | static int wadLoadEntries(PHYSFS_Io *io, const PHYSFS_uint32 count, void *arc)
51 | {
52 | PHYSFS_uint32 i;
53 | for (i = 0; i < count; i++)
54 | {
55 | PHYSFS_uint32 pos;
56 | PHYSFS_uint32 size;
57 | char name[9];
58 |
59 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &pos, 4), 0);
60 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &size, 4), 0);
61 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, name, 8), 0);
62 |
63 | name[8] = '\0'; /* name might not be null-terminated in file. */
64 | size = PHYSFS_swapULE32(size);
65 | pos = PHYSFS_swapULE32(pos);
66 | BAIL_IF_ERRPASS(!UNPK_addEntry(arc, name, 0, -1, -1, pos, size), 0);
67 | } /* for */
68 |
69 | return 1;
70 | } /* wadLoadEntries */
71 |
72 |
73 | static void *WAD_openArchive(PHYSFS_Io *io, const char *name,
74 | int forWriting, int *claimed)
75 | {
76 | PHYSFS_uint8 buf[4];
77 | PHYSFS_uint32 count;
78 | PHYSFS_uint32 directoryOffset;
79 | void *unpkarc;
80 |
81 | assert(io != NULL); /* shouldn't ever happen. */
82 |
83 | BAIL_IF(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
84 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, buf, sizeof (buf)), NULL);
85 | if ((memcmp(buf, "IWAD", 4) != 0) && (memcmp(buf, "PWAD", 4) != 0))
86 | BAIL(PHYSFS_ERR_UNSUPPORTED, NULL);
87 |
88 | *claimed = 1;
89 |
90 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &count, sizeof (count)), NULL);
91 | count = PHYSFS_swapULE32(count);
92 |
93 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &directoryOffset, 4), 0);
94 | directoryOffset = PHYSFS_swapULE32(directoryOffset);
95 |
96 | BAIL_IF_ERRPASS(!io->seek(io, directoryOffset), 0);
97 |
98 | unpkarc = UNPK_openArchive(io, 0, 1);
99 | BAIL_IF_ERRPASS(!unpkarc, NULL);
100 |
101 | if (!wadLoadEntries(io, count, unpkarc))
102 | {
103 | UNPK_abandonArchive(unpkarc);
104 | return NULL;
105 | } /* if */
106 |
107 | return unpkarc;
108 | } /* WAD_openArchive */
109 |
110 |
111 | const PHYSFS_Archiver __PHYSFS_Archiver_WAD =
112 | {
113 | CURRENT_PHYSFS_ARCHIVER_API_VERSION,
114 | {
115 | "WAD",
116 | "DOOM engine format",
117 | "Travis Wells ",
118 | "http://www.3dmm2.com/doom/",
119 | 0, /* supportsSymlinks */
120 | },
121 | WAD_openArchive,
122 | UNPK_enumerate,
123 | UNPK_openRead,
124 | UNPK_openWrite,
125 | UNPK_openAppend,
126 | UNPK_remove,
127 | UNPK_mkdir,
128 | UNPK_stat,
129 | UNPK_closeArchive
130 | };
131 |
132 | #endif /* defined PHYSFS_SUPPORTS_WAD */
133 |
134 | /* end of physfs_archiver_wad.c ... */
135 |
136 |
--------------------------------------------------------------------------------
/physfs/src/physfs_archiver_slb.c:
--------------------------------------------------------------------------------
1 | /*
2 | * SLB support routines for PhysicsFS.
3 | *
4 | * This driver handles SLB archives ("slab files"). This uncompressed format
5 | * is used in I-War / Independence War and Independence War: Defiance.
6 | *
7 | * The format begins with four zero bytes (version?), the file count and the
8 | * location of the table of contents. Each ToC entry contains a 64-byte buffer
9 | * containing a zero-terminated filename, the offset of the data, and its size.
10 | * All the filenames begin with the separator character '\'.
11 | *
12 | * Please see the file LICENSE.txt in the source's root directory.
13 | *
14 | * This file written by Aleksi Nurmi, based on the GRP archiver by
15 | * Ryan C. Gordon.
16 | */
17 |
18 | #define __PHYSICSFS_INTERNAL__
19 | #include "physfs_internal.h"
20 |
21 | #if PHYSFS_SUPPORTS_SLB
22 |
23 | static int slbLoadEntries(PHYSFS_Io *io, const PHYSFS_uint32 count, void *arc)
24 | {
25 | PHYSFS_uint32 i;
26 | for (i = 0; i < count; i++)
27 | {
28 | PHYSFS_uint32 pos;
29 | PHYSFS_uint32 size;
30 | char name[64];
31 | char backslash;
32 | char *ptr;
33 |
34 | /* don't include the '\' in the beginning */
35 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &backslash, 1), 0);
36 | BAIL_IF(backslash != '\\', PHYSFS_ERR_CORRUPT, 0);
37 |
38 | /* read the rest of the buffer, 63 bytes */
39 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, name, 63), 0);
40 | name[63] = '\0'; /* in case the name lacks the null terminator */
41 |
42 | /* convert backslashes */
43 | for (ptr = name; *ptr; ptr++)
44 | {
45 | if (*ptr == '\\')
46 | *ptr = '/';
47 | } /* for */
48 |
49 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &pos, 4), 0);
50 | pos = PHYSFS_swapULE32(pos);
51 |
52 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &size, 4), 0);
53 | size = PHYSFS_swapULE32(size);
54 |
55 | BAIL_IF_ERRPASS(!UNPK_addEntry(arc, name, 0, -1, -1, pos, size), 0);
56 | } /* for */
57 |
58 | return 1;
59 | } /* slbLoadEntries */
60 |
61 |
62 | static void *SLB_openArchive(PHYSFS_Io *io, const char *name,
63 | int forWriting, int *claimed)
64 | {
65 | PHYSFS_uint32 version;
66 | PHYSFS_uint32 count;
67 | PHYSFS_uint32 tocPos;
68 | void *unpkarc;
69 |
70 | /* There's no identifier on an SLB file, so we assume it's _not_ if the
71 | file count or tocPos is zero. Beyond that, we'll assume it's
72 | bogus/corrupt if the entries' filenames don't start with '\' or the
73 | tocPos is past the end of the file (seek will fail). This probably
74 | covers all meaningful cases where we would accidentally accept a non-SLB
75 | file with this archiver. */
76 |
77 | assert(io != NULL); /* shouldn't ever happen. */
78 |
79 | BAIL_IF(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
80 |
81 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &version, sizeof (version)), NULL);
82 | version = PHYSFS_swapULE32(version);
83 | BAIL_IF(version != 0, PHYSFS_ERR_UNSUPPORTED, NULL);
84 |
85 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &count, sizeof (count)), NULL);
86 | count = PHYSFS_swapULE32(count);
87 | BAIL_IF(!count, PHYSFS_ERR_UNSUPPORTED, NULL);
88 |
89 | /* offset of the table of contents */
90 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &tocPos, sizeof (tocPos)), NULL);
91 | tocPos = PHYSFS_swapULE32(tocPos);
92 | BAIL_IF(!tocPos, PHYSFS_ERR_UNSUPPORTED, NULL);
93 |
94 | /* seek to the table of contents */
95 | BAIL_IF_ERRPASS(!io->seek(io, tocPos), NULL);
96 |
97 | /* !!! FIXME: check case_sensitive and only_usascii params for this archive. */
98 | unpkarc = UNPK_openArchive(io, 1, 0);
99 | BAIL_IF_ERRPASS(!unpkarc, NULL);
100 |
101 | if (!slbLoadEntries(io, count, unpkarc))
102 | {
103 | UNPK_abandonArchive(unpkarc);
104 | return NULL;
105 | } /* if */
106 |
107 | *claimed = 1; /* oh well. */
108 |
109 | return unpkarc;
110 | } /* SLB_openArchive */
111 |
112 |
113 | const PHYSFS_Archiver __PHYSFS_Archiver_SLB =
114 | {
115 | CURRENT_PHYSFS_ARCHIVER_API_VERSION,
116 | {
117 | "SLB",
118 | "I-War / Independence War Slab file",
119 | "Aleksi Nurmi ",
120 | "https://bitbucket.org/ahnurmi/",
121 | 0, /* supportsSymlinks */
122 | },
123 | SLB_openArchive,
124 | UNPK_enumerate,
125 | UNPK_openRead,
126 | UNPK_openWrite,
127 | UNPK_openAppend,
128 | UNPK_remove,
129 | UNPK_mkdir,
130 | UNPK_stat,
131 | UNPK_closeArchive
132 | };
133 |
134 | #endif /* defined PHYSFS_SUPPORTS_SLB */
135 |
136 | /* end of physfs_archiver_slb.c ... */
137 |
--------------------------------------------------------------------------------
/physfs/extras/physfsunpack.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | #include "physfs.h"
7 |
8 |
9 | static int failure = 0;
10 |
11 | static void modTimeToStr(PHYSFS_sint64 modtime, char *modstr, size_t strsize)
12 | {
13 | const char *str = "unknown modtime";
14 | if (modtime != -1)
15 | {
16 | time_t t = (time_t) modtime;
17 | str = ctime(&t);
18 | } /* if */
19 |
20 | strncpy(modstr, str, strsize);
21 | modstr[strsize-1] = '\0';
22 | strsize = strlen(modstr);
23 | while ((modstr[strsize-1] == '\n') || (modstr[strsize-1] == '\r'))
24 | modstr[--strsize] = '\0';
25 | } /* modTimeToStr */
26 |
27 |
28 | static void fail(const char *what, const char *why)
29 | {
30 | if (why == NULL)
31 | why = PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode());
32 | fprintf(stderr, "%s failed: %s\n", what, why);
33 | failure = 1;
34 | } /* fail */
35 |
36 |
37 | static void dumpFile(const char *fname)
38 | {
39 | const int origfailure = failure;
40 | PHYSFS_File *out = NULL;
41 | PHYSFS_File *in = NULL;
42 |
43 | failure = 0;
44 |
45 | if ((in = PHYSFS_openRead(fname)) == NULL)
46 | fail("\nPHYSFS_openRead", NULL);
47 | else if ((out = PHYSFS_openWrite(fname)) == NULL)
48 | fail("\nPHYSFS_openWrite", NULL);
49 | else
50 | {
51 | char modstr[64];
52 | PHYSFS_sint64 size = PHYSFS_fileLength(in);
53 |
54 | printf("(");
55 | if (size == -1)
56 | printf("?");
57 | else
58 | printf("%lld", (long long) size);
59 | printf(" bytes");
60 |
61 | modTimeToStr(PHYSFS_getLastModTime(fname), modstr, sizeof (modstr));
62 | printf(", %s)\n", modstr);
63 |
64 | while ( (!failure) && (!PHYSFS_eof(in)) )
65 | {
66 | static char buf[64 * 1024];
67 | PHYSFS_sint64 br = PHYSFS_read(in, buf, 1, sizeof (buf));
68 | if (br == -1)
69 | fail("PHYSFS_read", NULL);
70 | else
71 | {
72 | PHYSFS_sint64 bw = PHYSFS_write(out, buf, 1, br);
73 | if (bw != br)
74 | fail("PHYSFS_write", NULL);
75 | else
76 | size -= bw;
77 | } /* else */
78 | } /* while */
79 |
80 | if ((!failure) && (size != 0))
81 | fail("PHYSFS_eof", "BUG! eof != PHYSFS_fileLength bytes!");
82 | } /* else */
83 |
84 | if (in != NULL)
85 | PHYSFS_close(in);
86 |
87 | if (out != NULL)
88 | {
89 | if (!PHYSFS_close(out))
90 | fail("PHYSFS_close", NULL);
91 | } /* if */
92 |
93 | if (failure)
94 | PHYSFS_delete(fname);
95 | else
96 | failure = origfailure;
97 | } /* dumpFile */
98 |
99 |
100 | static void unpackCallback(void *_depth, const char *origdir, const char *str)
101 | {
102 | int depth = *((int *) _depth);
103 | const int len = strlen(origdir) + strlen(str) + 2;
104 | char *fname = (char *) malloc(len);
105 | if (fname == NULL)
106 | fail("malloc", "Out of memory!");
107 | else
108 | {
109 | if (strcmp(origdir, "/") == 0)
110 | origdir = "";
111 |
112 | snprintf(fname, len, "%s/%s", origdir, str);
113 |
114 | printf("%s ", fname);
115 | if (PHYSFS_isDirectory(fname))
116 | {
117 | depth++;
118 | printf("(directory)\n");
119 | if (!PHYSFS_mkdir(fname))
120 | fail("PHYSFS_mkdir", NULL);
121 | else
122 | PHYSFS_enumerateFilesCallback(fname, unpackCallback, &depth);
123 | } /* if */
124 |
125 | else if (PHYSFS_isSymbolicLink(fname))
126 | {
127 | printf("(symlink)\n");
128 | /* !!! FIXME: ? if (!symlink(fname, */
129 | } /* else if */
130 |
131 | else /* ...file. */
132 | {
133 | dumpFile(fname);
134 | } /* else */
135 |
136 | free(fname);
137 | } /* else */
138 | } /* unpackCallback */
139 |
140 |
141 | int main(int argc, char **argv)
142 | {
143 | int zero = 0;
144 |
145 | if (argc != 3)
146 | {
147 | fprintf(stderr, "USAGE: %s \n", argv[0]);
148 | return 1;
149 | } /* if */
150 |
151 | if (!PHYSFS_init(argv[0]))
152 | {
153 | fprintf(stderr, "PHYSFS_init() failed: %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
154 | return 2;
155 | } /* if */
156 |
157 | if (!PHYSFS_setWriteDir(argv[2]))
158 | {
159 | fprintf(stderr, "PHYSFS_setWriteDir('%s') failed: %s\n",
160 | argv[2], PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
161 | return 3;
162 | } /* if */
163 |
164 | if (!PHYSFS_mount(argv[1], NULL, 1))
165 | {
166 | fprintf(stderr, "PHYSFS_mount('%s') failed: %s\n",
167 | argv[1], PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
168 | return 4;
169 | } /* if */
170 |
171 | PHYSFS_permitSymbolicLinks(1);
172 | PHYSFS_enumerateFilesCallback("/", unpackCallback, &zero);
173 | PHYSFS_deinit();
174 | if (failure)
175 | return 5;
176 |
177 | return 0;
178 | } /* main */
179 |
180 | /* end of physfsunpack.c ... */
181 |
182 |
--------------------------------------------------------------------------------
/physfs/src/physfs_platform_qnx.c:
--------------------------------------------------------------------------------
1 | /*
2 | * QNX support routines for PhysicsFS.
3 | *
4 | * Please see the file LICENSE.txt in the source's root directory.
5 | *
6 | * This file written by Ryan C. Gordon.
7 | */
8 |
9 | /* This is tested against QNX 7 at the moment. */
10 |
11 | #define __PHYSICSFS_INTERNAL__
12 | #include "physfs_platforms.h"
13 |
14 | #ifdef PHYSFS_PLATFORM_QNX
15 |
16 | #include
17 | #include
18 | #include
19 | #include
20 |
21 | #include "physfs_internal.h"
22 |
23 | int __PHYSFS_platformInit(void)
24 | {
25 | return 1; /* always succeed. */
26 | } /* __PHYSFS_platformInit */
27 |
28 |
29 | void __PHYSFS_platformDeinit(void)
30 | {
31 | /* no-op */
32 | } /* __PHYSFS_platformDeinit */
33 |
34 |
35 | char *__PHYSFS_platformCalcBaseDir(const char *argv0)
36 | {
37 | char *retval = (char *) allocator.Malloc(PATH_MAX+1);
38 | if (retval == NULL)
39 | BAIL(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
40 | else
41 | {
42 | const int fd = open("/proc/self/exefile", O_RDONLY);
43 | const ssize_t br = (fd == -1) ? -1 : read(fd, retval, PATH_MAX);
44 | char *ptr;
45 |
46 | if (fd != -1)
47 | close(fd);
48 |
49 | if ((br < 0) || (br > PATH_MAX))
50 | {
51 | allocator.Free(retval);
52 | BAIL(PHYSFS_ERR_OS_ERROR, NULL);
53 | } /* if */
54 |
55 | retval[br] = '\0';
56 | ptr = strrchr(retval, '/');
57 | if (ptr == NULL) /* uhoh! */
58 | {
59 | allocator.Free(retval);
60 | BAIL(PHYSFS_ERR_OS_ERROR, NULL);
61 | } /* if */
62 |
63 | ptr[1] = '\0'; /* chop off filename, leave dirs and '/' */
64 |
65 | ptr = (char *) allocator.Realloc(retval, (ptr - retval) + 2);
66 | if (ptr != NULL) /* just shrinking buffer; don't care if it failed. */
67 | retval = ptr;
68 | } /* else */
69 |
70 | return retval;
71 | } /* __PHYSFS_platformCalcBaseDir */
72 |
73 |
74 | char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
75 | {
76 | /* !!! FIXME: this might be wrong; I don't know if there's a better method
77 | on QNX, or if it follows XDG specs, etc. */
78 | char *retval = NULL;
79 | const char *home = __PHYSFS_getUserDir();
80 | if (home)
81 | {
82 | const size_t len = strlen(home) + strlen(app) + 3;
83 | retval = (char *) allocator.Malloc(len);
84 | BAIL_IF(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
85 | snprintf(retval, len, "%s.%s/", home, app);
86 | } /* if */
87 | return retval;
88 | } /* __PHYSFS_platformCalcPrefDir */
89 |
90 |
91 | #if !PHYSFS_NO_CDROM_SUPPORT
92 | #include
93 | #include
94 | #include
95 | #include
96 | #include
97 |
98 | static void checkPathForCD(const char *path, PHYSFS_StringCallback cb, void *d)
99 | {
100 | struct stat statbuf;
101 | int fd;
102 |
103 | /* The devctl() thing is QNX-specific. In this case, we query what is
104 | probably the mountpoint for the device. statvfs() on that mountpoint
105 | will tell use its filesystem type. */
106 |
107 | if ( (stat(path, &statbuf) == 0) &&
108 | (S_ISBLK(statbuf.st_mode)) &&
109 | ((fd = open(path, O_RDONLY | O_NONBLOCK)) != -1) )
110 | {
111 | char mnt[256] = { 0 };
112 | const int rc = devctl(fd, DCMD_FSYS_MOUNTED_BY, mnt, sizeof (mnt), 0);
113 | close(fd);
114 | if ( (rc == EOK) && (mnt[0]) )
115 | {
116 | struct statvfs statvfsbuf;
117 | if (statvfs(mnt, &statvfsbuf) == 0)
118 | {
119 | /* I don't know if this is a complete or accurate list. */
120 | const char *fstype = statvfsbuf.f_basetype;
121 | const int iscd = ( (strcmp(fstype, "cd") == 0) ||
122 | (strcmp(fstype, "udf") == 0) );
123 | if (iscd)
124 | cb(d, mnt);
125 | } /* if */
126 | } /* if */
127 | } /* if */
128 | } /* checkPathForCD */
129 |
130 | static void checkDevForCD(const char *dev, PHYSFS_StringCallback cb, void *d)
131 | {
132 | size_t len;
133 | char *path;
134 |
135 | if (dev[0] == '.') /* ignore "." and ".." */
136 | {
137 | if ((dev[1] == '\0') || ((dev[1] == '.') && (dev[2] == '\0')))
138 | return;
139 | } /* if */
140 |
141 | len = strlen(dev) + 6;
142 | path = (char *) __PHYSFS_smallAlloc(len);
143 | if (!path)
144 | return; /* oh well. */
145 |
146 | snprintf(path, len, "/dev/%s", dev);
147 | checkPathForCD(path, cb, d);
148 | __PHYSFS_smallFree(path);
149 | } /* checkDevForCD */
150 | #endif /* !PHYSFS_NO_CDROM_SUPPORT */
151 |
152 | void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
153 | {
154 | #if !PHYSFS_NO_CDROM_SUPPORT
155 | DIR *dirp = opendir("/dev");
156 | if (dirp)
157 | {
158 | struct dirent *dent;
159 | while ((dent = readdir(dirp)) != NULL)
160 | checkDevForCD(dent->d_name, cb, data);
161 | closedir(dirp);
162 | } /* if */
163 | #endif
164 | } /* __PHYSFS_platformDetectAvailableCDs */
165 |
166 | #endif /* PHYSFS_PLATFORM_QNX */
167 |
168 | /* end of physfs_platform_qnx.c ... */
169 |
170 |
--------------------------------------------------------------------------------
/physfs/src/physfs_platform_haiku.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Haiku platform-dependent support routines for PhysicsFS.
3 | *
4 | * Please see the file LICENSE.txt in the source's root directory.
5 | *
6 | * This file written by Ryan C. Gordon.
7 | */
8 |
9 | #define __PHYSICSFS_INTERNAL__
10 | #include "physfs_platforms.h"
11 |
12 | #ifdef PHYSFS_PLATFORM_HAIKU
13 |
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 |
24 | #include
25 | #include
26 |
27 | #include "physfs_internal.h"
28 |
29 | int __PHYSFS_platformInit(void)
30 | {
31 | return 1; /* always succeed. */
32 | } /* __PHYSFS_platformInit */
33 |
34 |
35 | void __PHYSFS_platformDeinit(void)
36 | {
37 | /* no-op */
38 | } /* __PHYSFS_platformDeinit */
39 |
40 |
41 | static char *getMountPoint(const char *devname, char *buf, size_t bufsize)
42 | {
43 | BVolumeRoster mounts;
44 | BVolume vol;
45 |
46 | mounts.Rewind();
47 | while (mounts.GetNextVolume(&vol) == B_NO_ERROR)
48 | {
49 | fs_info fsinfo;
50 | fs_stat_dev(vol.Device(), &fsinfo);
51 | if (strcmp(devname, fsinfo.device_name) == 0)
52 | {
53 | BDirectory directory;
54 | BEntry entry;
55 | BPath path;
56 | const char *str;
57 |
58 | if ( (vol.GetRootDirectory(&directory) < B_OK) ||
59 | (directory.GetEntry(&entry) < B_OK) ||
60 | (entry.GetPath(&path) < B_OK) ||
61 | ( (str = path.Path()) == NULL) )
62 | return NULL;
63 |
64 | strncpy(buf, str, bufsize-1);
65 | buf[bufsize-1] = '\0';
66 | return buf;
67 | } /* if */
68 | } /* while */
69 |
70 | return NULL;
71 | } /* getMountPoint */
72 |
73 |
74 | /*
75 | * This function is lifted from Simple Directmedia Layer (SDL):
76 | * https://www.libsdl.org/ ... this is zlib-licensed code, too.
77 | */
78 | static void tryDir(const char *d, PHYSFS_StringCallback callback, void *data)
79 | {
80 | BDirectory dir;
81 | dir.SetTo(d);
82 | if (dir.InitCheck() != B_NO_ERROR)
83 | return;
84 |
85 | dir.Rewind();
86 | BEntry entry;
87 | while (dir.GetNextEntry(&entry) >= 0)
88 | {
89 | BPath path;
90 | const char *name;
91 | entry_ref e;
92 |
93 | if (entry.GetPath(&path) != B_NO_ERROR)
94 | continue;
95 |
96 | name = path.Path();
97 |
98 | if (entry.GetRef(&e) != B_NO_ERROR)
99 | continue;
100 |
101 | if (entry.IsDirectory())
102 | {
103 | if (strcmp(e.name, "floppy") != 0)
104 | tryDir(name, callback, data);
105 | continue;
106 | } /* if */
107 |
108 | const int devfd = open(name, O_RDONLY);
109 | if (devfd < 0)
110 | continue;
111 |
112 | device_geometry g;
113 | const int rc = ioctl(devfd, B_GET_GEOMETRY, &g, sizeof (g));
114 | close(devfd);
115 | if (rc < 0)
116 | continue;
117 |
118 | if (g.device_type != B_CD)
119 | continue;
120 |
121 | char mntpnt[B_FILE_NAME_LENGTH];
122 | if (getMountPoint(name, mntpnt, sizeof (mntpnt)))
123 | callback(data, mntpnt);
124 | } /* while */
125 | } /* tryDir */
126 |
127 |
128 | void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
129 | {
130 | tryDir("/dev/disk", cb, data);
131 | } /* __PHYSFS_platformDetectAvailableCDs */
132 |
133 |
134 | static team_id getTeamID(void)
135 | {
136 | thread_info info;
137 | thread_id tid = find_thread(NULL);
138 | get_thread_info(tid, &info);
139 | return info.team;
140 | } /* getTeamID */
141 |
142 |
143 | char *__PHYSFS_platformCalcBaseDir(const char *argv0)
144 | {
145 | image_info info;
146 | int32 cookie = 0;
147 |
148 | while (get_next_image_info(0, &cookie, &info) == B_OK)
149 | {
150 | if (info.type == B_APP_IMAGE)
151 | break;
152 | } /* while */
153 |
154 | BEntry entry(info.name, true);
155 | BPath path;
156 | status_t rc = entry.GetPath(&path); /* (path) now has binary's path. */
157 | assert(rc == B_OK);
158 | rc = path.GetParent(&path); /* chop filename, keep directory. */
159 | assert(rc == B_OK);
160 | const char *str = path.Path();
161 | assert(str != NULL);
162 | const size_t len = strlen(str);
163 | char *retval = (char *) allocator.Malloc(len + 2);
164 | BAIL_IF(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
165 | strcpy(retval, str);
166 | retval[len] = '/';
167 | retval[len+1] = '\0';
168 | return retval;
169 | } /* __PHYSFS_platformCalcBaseDir */
170 |
171 |
172 | char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
173 | {
174 | const char *userdir = __PHYSFS_getUserDir();
175 | const char *append = "config/settings/";
176 | const size_t len = strlen(userdir) + strlen(append) + strlen(app) + 2;
177 | char *retval = (char *) allocator.Malloc(len);
178 | BAIL_IF(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
179 | snprintf(retval, len, "%s%s%s/", userdir, append, app);
180 | return retval;
181 | } /* __PHYSFS_platformCalcPrefDir */
182 |
183 | #endif /* PHYSFS_PLATFORM_HAIKU */
184 |
185 | /* end of physfs_platform_haiku.cpp ... */
186 |
187 |
--------------------------------------------------------------------------------
/physfs/src/physfs_byteorder.c:
--------------------------------------------------------------------------------
1 | /**
2 | * PhysicsFS; a portable, flexible file i/o abstraction.
3 | *
4 | * Documentation is in physfs.h. It's verbose, honest. :)
5 | *
6 | * Please see the file LICENSE.txt in the source's root directory.
7 | *
8 | * This file written by Ryan C. Gordon.
9 | */
10 |
11 | #define __PHYSICSFS_INTERNAL__
12 | #include "physfs_internal.h"
13 |
14 | #ifndef PHYSFS_Swap16
15 | static inline PHYSFS_uint16 PHYSFS_Swap16(PHYSFS_uint16 D)
16 | {
17 | return ((D<<8)|(D>>8));
18 | }
19 | #endif
20 | #ifndef PHYSFS_Swap32
21 | static inline PHYSFS_uint32 PHYSFS_Swap32(PHYSFS_uint32 D)
22 | {
23 | return ((D<<24)|((D<<8)&0x00FF0000)|((D>>8)&0x0000FF00)|(D>>24));
24 | }
25 | #endif
26 | #ifndef PHYSFS_NO_64BIT_SUPPORT
27 | #ifndef PHYSFS_Swap64
28 | static inline PHYSFS_uint64 PHYSFS_Swap64(PHYSFS_uint64 val) {
29 | PHYSFS_uint32 hi, lo;
30 |
31 | /* Separate into high and low 32-bit values and swap them */
32 | lo = (PHYSFS_uint32)(val&0xFFFFFFFF);
33 | val >>= 32;
34 | hi = (PHYSFS_uint32)(val&0xFFFFFFFF);
35 | val = PHYSFS_Swap32(lo);
36 | val <<= 32;
37 | val |= PHYSFS_Swap32(hi);
38 | return val;
39 | }
40 | #endif
41 | #else
42 | #ifndef PHYSFS_Swap64
43 | /* This is mainly to keep compilers from complaining in PHYSFS code.
44 | If there is no real 64-bit datatype, then compilers will complain about
45 | the fake 64-bit datatype that PHYSFS provides when it compiles user code.
46 | */
47 | #define PHYSFS_Swap64(X) (X)
48 | #endif
49 | #endif /* PHYSFS_NO_64BIT_SUPPORT */
50 |
51 |
52 | /* Byteswap item from the specified endianness to the native endianness */
53 | #if PHYSFS_BYTEORDER == PHYSFS_LIL_ENDIAN
54 | PHYSFS_uint16 PHYSFS_swapULE16(PHYSFS_uint16 x) { return x; }
55 | PHYSFS_sint16 PHYSFS_swapSLE16(PHYSFS_sint16 x) { return x; }
56 | PHYSFS_uint32 PHYSFS_swapULE32(PHYSFS_uint32 x) { return x; }
57 | PHYSFS_sint32 PHYSFS_swapSLE32(PHYSFS_sint32 x) { return x; }
58 | PHYSFS_uint64 PHYSFS_swapULE64(PHYSFS_uint64 x) { return x; }
59 | PHYSFS_sint64 PHYSFS_swapSLE64(PHYSFS_sint64 x) { return x; }
60 |
61 | PHYSFS_uint16 PHYSFS_swapUBE16(PHYSFS_uint16 x) { return PHYSFS_Swap16(x); }
62 | PHYSFS_sint16 PHYSFS_swapSBE16(PHYSFS_sint16 x) { return PHYSFS_Swap16(x); }
63 | PHYSFS_uint32 PHYSFS_swapUBE32(PHYSFS_uint32 x) { return PHYSFS_Swap32(x); }
64 | PHYSFS_sint32 PHYSFS_swapSBE32(PHYSFS_sint32 x) { return PHYSFS_Swap32(x); }
65 | PHYSFS_uint64 PHYSFS_swapUBE64(PHYSFS_uint64 x) { return PHYSFS_Swap64(x); }
66 | PHYSFS_sint64 PHYSFS_swapSBE64(PHYSFS_sint64 x) { return PHYSFS_Swap64(x); }
67 | #else
68 | PHYSFS_uint16 PHYSFS_swapULE16(PHYSFS_uint16 x) { return PHYSFS_Swap16(x); }
69 | PHYSFS_sint16 PHYSFS_swapSLE16(PHYSFS_sint16 x) { return PHYSFS_Swap16(x); }
70 | PHYSFS_uint32 PHYSFS_swapULE32(PHYSFS_uint32 x) { return PHYSFS_Swap32(x); }
71 | PHYSFS_sint32 PHYSFS_swapSLE32(PHYSFS_sint32 x) { return PHYSFS_Swap32(x); }
72 | PHYSFS_uint64 PHYSFS_swapULE64(PHYSFS_uint64 x) { return PHYSFS_Swap64(x); }
73 | PHYSFS_sint64 PHYSFS_swapSLE64(PHYSFS_sint64 x) { return PHYSFS_Swap64(x); }
74 |
75 | PHYSFS_uint16 PHYSFS_swapUBE16(PHYSFS_uint16 x) { return x; }
76 | PHYSFS_sint16 PHYSFS_swapSBE16(PHYSFS_sint16 x) { return x; }
77 | PHYSFS_uint32 PHYSFS_swapUBE32(PHYSFS_uint32 x) { return x; }
78 | PHYSFS_sint32 PHYSFS_swapSBE32(PHYSFS_sint32 x) { return x; }
79 | PHYSFS_uint64 PHYSFS_swapUBE64(PHYSFS_uint64 x) { return x; }
80 | PHYSFS_sint64 PHYSFS_swapSBE64(PHYSFS_sint64 x) { return x; }
81 | #endif
82 |
83 | static inline int readAll(PHYSFS_File *file, void *val, const size_t len)
84 | {
85 | return (PHYSFS_readBytes(file, val, len) == len);
86 | } /* readAll */
87 |
88 | #define PHYSFS_BYTEORDER_READ(datatype, swaptype) \
89 | int PHYSFS_read##swaptype(PHYSFS_File *file, PHYSFS_##datatype *val) { \
90 | PHYSFS_##datatype in; \
91 | BAIL_IF(val == NULL, PHYSFS_ERR_INVALID_ARGUMENT, 0); \
92 | BAIL_IF_ERRPASS(!readAll(file, &in, sizeof (in)), 0); \
93 | *val = PHYSFS_swap##swaptype(in); \
94 | return 1; \
95 | }
96 |
97 | PHYSFS_BYTEORDER_READ(sint16, SLE16)
98 | PHYSFS_BYTEORDER_READ(uint16, ULE16)
99 | PHYSFS_BYTEORDER_READ(sint16, SBE16)
100 | PHYSFS_BYTEORDER_READ(uint16, UBE16)
101 | PHYSFS_BYTEORDER_READ(sint32, SLE32)
102 | PHYSFS_BYTEORDER_READ(uint32, ULE32)
103 | PHYSFS_BYTEORDER_READ(sint32, SBE32)
104 | PHYSFS_BYTEORDER_READ(uint32, UBE32)
105 | PHYSFS_BYTEORDER_READ(sint64, SLE64)
106 | PHYSFS_BYTEORDER_READ(uint64, ULE64)
107 | PHYSFS_BYTEORDER_READ(sint64, SBE64)
108 | PHYSFS_BYTEORDER_READ(uint64, UBE64)
109 |
110 |
111 | static inline int writeAll(PHYSFS_File *f, const void *val, const size_t len)
112 | {
113 | return (PHYSFS_writeBytes(f, val, len) == len);
114 | } /* writeAll */
115 |
116 | #define PHYSFS_BYTEORDER_WRITE(datatype, swaptype) \
117 | int PHYSFS_write##swaptype(PHYSFS_File *file, PHYSFS_##datatype val) { \
118 | const PHYSFS_##datatype out = PHYSFS_swap##swaptype(val); \
119 | BAIL_IF_ERRPASS(!writeAll(file, &out, sizeof (out)), 0); \
120 | return 1; \
121 | }
122 |
123 | PHYSFS_BYTEORDER_WRITE(sint16, SLE16)
124 | PHYSFS_BYTEORDER_WRITE(uint16, ULE16)
125 | PHYSFS_BYTEORDER_WRITE(sint16, SBE16)
126 | PHYSFS_BYTEORDER_WRITE(uint16, UBE16)
127 | PHYSFS_BYTEORDER_WRITE(sint32, SLE32)
128 | PHYSFS_BYTEORDER_WRITE(uint32, ULE32)
129 | PHYSFS_BYTEORDER_WRITE(sint32, SBE32)
130 | PHYSFS_BYTEORDER_WRITE(uint32, UBE32)
131 | PHYSFS_BYTEORDER_WRITE(sint64, SLE64)
132 | PHYSFS_BYTEORDER_WRITE(uint64, ULE64)
133 | PHYSFS_BYTEORDER_WRITE(sint64, SBE64)
134 | PHYSFS_BYTEORDER_WRITE(uint64, UBE64)
135 |
136 | /* end of physfs_byteorder.c ... */
137 |
138 |
--------------------------------------------------------------------------------
/physfs/src/physfs_archiver_dir.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Standard directory I/O support routines for PhysicsFS.
3 | *
4 | * Please see the file LICENSE.txt in the source's root directory.
5 | *
6 | * This file written by Ryan C. Gordon.
7 | */
8 |
9 | #define __PHYSICSFS_INTERNAL__
10 | #include "physfs_internal.h"
11 |
12 | /* There's no PHYSFS_Io interface here. Use __PHYSFS_createNativeIo(). */
13 |
14 |
15 |
16 | static char *cvtToDependent(const char *prepend, const char *path,
17 | char *buf, const size_t buflen)
18 | {
19 | BAIL_IF(buf == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
20 | snprintf(buf, buflen, "%s%s", prepend ? prepend : "", path);
21 |
22 | #if !__PHYSFS_STANDARD_DIRSEP
23 | assert(__PHYSFS_platformDirSeparator != '/');
24 | {
25 | char *p;
26 | for (p = strchr(buf, '/'); p != NULL; p = strchr(p + 1, '/'))
27 | *p = __PHYSFS_platformDirSeparator;
28 | } /* if */
29 | #endif
30 |
31 | return buf;
32 | } /* cvtToDependent */
33 |
34 |
35 | #define CVT_TO_DEPENDENT(buf, pre, dir) { \
36 | const size_t len = ((pre) ? strlen((char *) pre) : 0) + strlen(dir) + 1; \
37 | buf = cvtToDependent((char*)pre,dir,(char*)__PHYSFS_smallAlloc(len),len); \
38 | }
39 |
40 |
41 |
42 | static void *DIR_openArchive(PHYSFS_Io *io, const char *name,
43 | int forWriting, int *claimed)
44 | {
45 | PHYSFS_Stat st;
46 | const char dirsep = __PHYSFS_platformDirSeparator;
47 | char *retval = NULL;
48 | const size_t namelen = strlen(name);
49 | const size_t seplen = 1;
50 |
51 | assert(io == NULL); /* shouldn't create an Io for these. */
52 | BAIL_IF_ERRPASS(!__PHYSFS_platformStat(name, &st, 1), NULL);
53 |
54 | if (st.filetype != PHYSFS_FILETYPE_DIRECTORY)
55 | BAIL(PHYSFS_ERR_UNSUPPORTED, NULL);
56 |
57 | *claimed = 1;
58 | retval = allocator.Malloc(namelen + seplen + 1);
59 | BAIL_IF(retval == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
60 |
61 | strcpy(retval, name);
62 |
63 | /* make sure there's a dir separator at the end of the string */
64 | if (retval[namelen - 1] != dirsep)
65 | {
66 | retval[namelen] = dirsep;
67 | retval[namelen + 1] = '\0';
68 | } /* if */
69 |
70 | return retval;
71 | } /* DIR_openArchive */
72 |
73 |
74 | static PHYSFS_EnumerateCallbackResult DIR_enumerate(void *opaque,
75 | const char *dname, PHYSFS_EnumerateCallback cb,
76 | const char *origdir, void *callbackdata)
77 | {
78 | char *d;
79 | PHYSFS_EnumerateCallbackResult retval;
80 | CVT_TO_DEPENDENT(d, opaque, dname);
81 | BAIL_IF_ERRPASS(!d, PHYSFS_ENUM_ERROR);
82 | retval = __PHYSFS_platformEnumerate(d, cb, origdir, callbackdata);
83 | __PHYSFS_smallFree(d);
84 | return retval;
85 | } /* DIR_enumerate */
86 |
87 |
88 | static PHYSFS_Io *doOpen(void *opaque, const char *name, const int mode)
89 | {
90 | PHYSFS_Io *io = NULL;
91 | char *f = NULL;
92 |
93 | CVT_TO_DEPENDENT(f, opaque, name);
94 | BAIL_IF_ERRPASS(!f, NULL);
95 |
96 | io = __PHYSFS_createNativeIo(f, mode);
97 | if (io == NULL)
98 | {
99 | const PHYSFS_ErrorCode err = PHYSFS_getLastErrorCode();
100 | PHYSFS_Stat statbuf;
101 | __PHYSFS_platformStat(f, &statbuf, 0); /* !!! FIXME: why are we stating here? */
102 | PHYSFS_setErrorCode(err);
103 | } /* if */
104 |
105 | __PHYSFS_smallFree(f);
106 |
107 | return io;
108 | } /* doOpen */
109 |
110 |
111 | static PHYSFS_Io *DIR_openRead(void *opaque, const char *filename)
112 | {
113 | return doOpen(opaque, filename, 'r');
114 | } /* DIR_openRead */
115 |
116 |
117 | static PHYSFS_Io *DIR_openWrite(void *opaque, const char *filename)
118 | {
119 | return doOpen(opaque, filename, 'w');
120 | } /* DIR_openWrite */
121 |
122 |
123 | static PHYSFS_Io *DIR_openAppend(void *opaque, const char *filename)
124 | {
125 | return doOpen(opaque, filename, 'a');
126 | } /* DIR_openAppend */
127 |
128 |
129 | static int DIR_remove(void *opaque, const char *name)
130 | {
131 | int retval;
132 | char *f;
133 |
134 | CVT_TO_DEPENDENT(f, opaque, name);
135 | BAIL_IF_ERRPASS(!f, 0);
136 | retval = __PHYSFS_platformDelete(f);
137 | __PHYSFS_smallFree(f);
138 | return retval;
139 | } /* DIR_remove */
140 |
141 |
142 | static int DIR_mkdir(void *opaque, const char *name)
143 | {
144 | int retval;
145 | char *f;
146 |
147 | CVT_TO_DEPENDENT(f, opaque, name);
148 | BAIL_IF_ERRPASS(!f, 0);
149 | retval = __PHYSFS_platformMkDir(f);
150 | __PHYSFS_smallFree(f);
151 | return retval;
152 | } /* DIR_mkdir */
153 |
154 |
155 | static void DIR_closeArchive(void *opaque)
156 | {
157 | allocator.Free(opaque);
158 | } /* DIR_closeArchive */
159 |
160 |
161 | static int DIR_stat(void *opaque, const char *name, PHYSFS_Stat *stat)
162 | {
163 | int retval = 0;
164 | char *d;
165 |
166 | CVT_TO_DEPENDENT(d, opaque, name);
167 | BAIL_IF_ERRPASS(!d, 0);
168 | retval = __PHYSFS_platformStat(d, stat, 0);
169 | __PHYSFS_smallFree(d);
170 | return retval;
171 | } /* DIR_stat */
172 |
173 |
174 | const PHYSFS_Archiver __PHYSFS_Archiver_DIR =
175 | {
176 | CURRENT_PHYSFS_ARCHIVER_API_VERSION,
177 | {
178 | "",
179 | "Non-archive, direct filesystem I/O",
180 | "Ryan C. Gordon ",
181 | "https://icculus.org/physfs/",
182 | 1, /* supportsSymlinks */
183 | },
184 | DIR_openArchive,
185 | DIR_enumerate,
186 | DIR_openRead,
187 | DIR_openWrite,
188 | DIR_openAppend,
189 | DIR_remove,
190 | DIR_mkdir,
191 | DIR_stat,
192 | DIR_closeArchive
193 | };
194 |
195 | /* end of physfs_archiver_dir.c ... */
196 |
197 |
--------------------------------------------------------------------------------
/physfs/src/physfs_archiver_hog.c:
--------------------------------------------------------------------------------
1 | /*
2 | * HOG support routines for PhysicsFS.
3 | *
4 | * This driver handles Descent I/II/III HOG archives.
5 | *
6 | * The Descent I/II format is very simple:
7 | *
8 | * The file always starts with the 3-byte signature "DHF" (Descent
9 | * HOG file). After that the files of a HOG are just attached after
10 | * another, divided by a 17 bytes header, which specifies the name
11 | * and length (in bytes) of the forthcoming file! So you just read
12 | * the header with its information of how big the following file is,
13 | * and then skip exact that number of bytes to get to the next file
14 | * in that HOG.
15 | *
16 | * char sig[3] = {'D', 'H', 'F'}; // "DHF"=Descent HOG File
17 | *
18 | * struct {
19 | * char file_name[13]; // Filename, padded to 13 bytes with 0s
20 | * int file_size; // filesize in bytes
21 | * char data[file_size]; // The file data
22 | * } FILE_STRUCT; // Repeated until the end of the file.
23 | *
24 | * (That info is from http://www.descent2.com/ddn/specs/hog/)
25 | *
26 | * Descent 3 moved to HOG2 format, which starts with the chars "HOG2",
27 | * then 32-bits for the number of contained files, 32 bits for the offset
28 | * to the first file's data, then 56 bytes of 0xFF (reserved?). Then for
29 | * each file, there's 36 bytes for filename (null-terminated, rest of bytes
30 | * are garbage), 32-bits unknown/reserved (always zero?), 32-bits of length
31 | * of file data, 32-bits of time since Unix epoch. Then immediately following,
32 | * for each file is their uncompressed content, you can find its offset
33 | * by starting at the initial data offset and adding the filesize of each
34 | * prior file.
35 | *
36 | * This information was found at:
37 | * https://web.archive.org/web/20020213004051/http://descent-3.com/ddn/specs/hog/
38 | *
39 | *
40 | * Please see the file LICENSE.txt in the source's root directory.
41 | *
42 | * This file written by Bradley Bell and Ryan C. Gordon.
43 | */
44 |
45 | #define __PHYSICSFS_INTERNAL__
46 | #include "physfs_internal.h"
47 |
48 | #if PHYSFS_SUPPORTS_HOG
49 |
50 | static int readui32(PHYSFS_Io *io, PHYSFS_uint32 *val)
51 | {
52 | PHYSFS_uint32 v;
53 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &v, sizeof (v)), 0);
54 | *val = PHYSFS_swapULE32(v);
55 | return 1;
56 | } /* readui32 */
57 |
58 | static int hog1LoadEntries(PHYSFS_Io *io, void *arc)
59 | {
60 | const PHYSFS_uint64 iolen = io->length(io);
61 | PHYSFS_uint32 pos = 3;
62 |
63 | while (pos < iolen)
64 | {
65 | PHYSFS_uint32 size;
66 | char name[13];
67 |
68 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, name, 13), 0);
69 | BAIL_IF_ERRPASS(!readui32(io, &size), 0);
70 | name[12] = '\0'; /* just in case. */
71 | pos += 13 + 4;
72 |
73 | BAIL_IF_ERRPASS(!UNPK_addEntry(arc, name, 0, -1, -1, pos, size), 0);
74 | pos += size;
75 |
76 | /* skip over entry */
77 | BAIL_IF_ERRPASS(!io->seek(io, pos), 0);
78 | } /* while */
79 |
80 | return 1;
81 | } /* hogLoadEntries */
82 |
83 | static int hog2LoadEntries(PHYSFS_Io *io, void *arc)
84 | {
85 | PHYSFS_uint32 numfiles;
86 | PHYSFS_uint32 pos;
87 | PHYSFS_uint32 i;
88 |
89 | BAIL_IF_ERRPASS(!readui32(io, &numfiles), 0);
90 | BAIL_IF_ERRPASS(!readui32(io, &pos), 0);
91 | BAIL_IF_ERRPASS(!io->seek(io, 68), 0); /* skip to end of header. */
92 |
93 | for (i = 0; i < numfiles; i++) {
94 | char name[37];
95 | PHYSFS_uint32 reserved;
96 | PHYSFS_uint32 size;
97 | PHYSFS_uint32 mtime;
98 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, name, 36), 0);
99 | BAIL_IF_ERRPASS(!readui32(io, &reserved), 0);
100 | BAIL_IF_ERRPASS(!readui32(io, &size), 0);
101 | BAIL_IF_ERRPASS(!readui32(io, &mtime), 0);
102 | name[36] = '\0'; /* just in case */
103 | BAIL_IF_ERRPASS(!UNPK_addEntry(arc, name, 0, mtime, mtime, pos, size), 0);
104 | pos += size;
105 | }
106 |
107 | return 1;
108 | } /* hog2LoadEntries */
109 |
110 |
111 | static void *HOG_openArchive(PHYSFS_Io *io, const char *name,
112 | int forWriting, int *claimed)
113 | {
114 | PHYSFS_uint8 buf[3];
115 | void *unpkarc = NULL;
116 | int hog1 = 0;
117 |
118 | assert(io != NULL); /* shouldn't ever happen. */
119 | BAIL_IF(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
120 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, buf, 3), NULL);
121 |
122 | if (memcmp(buf, "DHF", 3) == 0)
123 | hog1 = 1; /* original HOG (Descent 1 and 2) archive */
124 | else
125 | {
126 | BAIL_IF(memcmp(buf, "HOG", 3) != 0, PHYSFS_ERR_UNSUPPORTED, NULL); /* Not HOG2 */
127 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, buf, 1), NULL);
128 | BAIL_IF(buf[0] != '2', PHYSFS_ERR_UNSUPPORTED, NULL); /* Not HOG2 */
129 | } /* else */
130 |
131 | *claimed = 1;
132 |
133 | unpkarc = UNPK_openArchive(io, 0, 1);
134 | BAIL_IF_ERRPASS(!unpkarc, NULL);
135 |
136 | if (!(hog1 ? hog1LoadEntries(io, unpkarc) : hog2LoadEntries(io, unpkarc)))
137 | {
138 | UNPK_abandonArchive(unpkarc);
139 | return NULL;
140 | } /* if */
141 |
142 | return unpkarc;
143 | } /* HOG_openArchive */
144 |
145 |
146 | const PHYSFS_Archiver __PHYSFS_Archiver_HOG =
147 | {
148 | CURRENT_PHYSFS_ARCHIVER_API_VERSION,
149 | {
150 | "HOG",
151 | "Descent I/II/III HOG file format",
152 | "Bradley Bell ",
153 | "https://icculus.org/physfs/",
154 | 0, /* supportsSymlinks */
155 | },
156 | HOG_openArchive,
157 | UNPK_enumerate,
158 | UNPK_openRead,
159 | UNPK_openWrite,
160 | UNPK_openAppend,
161 | UNPK_remove,
162 | UNPK_mkdir,
163 | UNPK_stat,
164 | UNPK_closeArchive
165 | };
166 |
167 | #endif /* defined PHYSFS_SUPPORTS_HOG */
168 |
169 | /* end of physfs_archiver_hog.c ... */
170 |
171 |
--------------------------------------------------------------------------------
/physfs/extras/abs-file.h:
--------------------------------------------------------------------------------
1 | /*
2 | * stdio/physfs abstraction layer 2003-04-02
3 | *
4 | * Adam D. Moss
5 | *
6 | * These wrapper macros and functions are designed to allow a program
7 | * to perform file I/O with identical semantics and syntax regardless
8 | * of whether PhysicsFS is being used or not.
9 | */
10 | #ifndef _ABS_FILE_H
11 | #define _ABS_FILE_H
12 | /*
13 | PLEASE NOTE: This license applies to abs-file.h ONLY (to make it clear that
14 | you may embed this wrapper code within commercial software); PhysicsFS itself
15 | is (at the time of writing) released under a different license with
16 | additional restrictions.
17 |
18 | Copyright (C) 2002-2003 Adam D. Moss (the "Author"). All Rights Reserved.
19 |
20 | Permission is hereby granted, free of charge, to any person obtaining a copy
21 | of this software and associated documentation files (the "Software"), to deal
22 | in the Software without restriction, including without limitation the rights
23 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24 | copies of the Software, and to permit persons to whom the Software is fur-
25 | nished to do so, subject to the following conditions:
26 |
27 | The above copyright notice and this permission notice shall be included in
28 | all copies or substantial portions of the Software.
29 |
30 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
32 | NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33 | AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
34 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON-
35 | NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 |
37 | Except as contained in this notice, the name of the Author of the
38 | Software shall not be used in advertising or otherwise to promote the sale,
39 | use or other dealings in this Software without prior written authorization
40 | from the Author.
41 | */
42 |
43 | #include
44 | #include
45 |
46 | /*
47 | * API:
48 | *
49 | * Macro/function use like stdio equivalent...
50 | * -------------- ----------------------------
51 | * MY_FILETYPE FILE
52 | * MY_OPEN_FOR_READ fopen(..., "rb")
53 | * MY_READ fread(...)
54 | * MY_CLOSE fclose(...)
55 | * MY_GETC fgetc(...)
56 | * MY_GETS fgets(...)
57 | * MY_ATEOF feof(...)
58 | * MY_TELL ftell(...)
59 | * MY_SEEK fseek(..., SEEK_SET)
60 | * MY_REWIND rewind(...)
61 | * MY_SETBUFFER (not a standard for stdio, does nothing there)
62 | */
63 |
64 | /*
65 | * Important DEFINEs:
66 | * It is important to define these consistantly across the various
67 | * compilation modules of your program if you wish to exchange file
68 | * handles between them.
69 | *
70 | * USE_PHYSFS: Define USE_PHYSFS if PhysicsFS is being used; note that if
71 | * you do intend to use PhysicsFS then you will still need to initialize
72 | * PhysicsFS yourself and set up its search-paths.
73 | *
74 | * Optional DEFINEs:
75 | *
76 | * PHYSFS_DEFAULT_READ_BUFFER : If set then abs-file.h sets the
77 | * PhysicsFS buffer size to this value whenever you open a file. You
78 | * may over-ride this on a per-filehandle basis by using the
79 | * MY_SETBUFFER() macro (which simply does nothing when not using
80 | * PhysicsFS). If you have not defined this value explicitly then
81 | * abs-file.h will default to the same default buffer size as used by
82 | * stdio if it can be determined, or 8192 bytes otherwise.
83 | */
84 | #ifndef PHYSFS_DEFAULT_READ_BUFFER
85 | #ifdef BUFSIZ
86 | #define PHYSFS_DEFAULT_READ_BUFFER BUFSIZ
87 | #else
88 | #define PHYSFS_DEFAULT_READ_BUFFER 8192
89 | #endif
90 | #endif
91 |
92 | #ifdef USE_PHYSFS
93 |
94 | #include
95 | #define MY_FILETYPE PHYSFS_File
96 | #define MY_SETBUFFER(fp,size) PHYSFS_setBuffer(fp,size)
97 | #define MY_READ(p,s,n,fp) PHYSFS_read(fp,p,s,n)
98 | #if PHYSFS_DEFAULT_READ_BUFFER
99 | static MY_FILETYPE* MY_OPEN_FOR_READ(const char *const filename)
100 | {
101 | MY_FILETYPE *const file = PHYSFS_openRead(filename);
102 | if (file) {
103 | MY_SETBUFFER(file, PHYSFS_DEFAULT_READ_BUFFER);
104 | }
105 | return file;
106 | }
107 | #else
108 | #define MY_OPEN_FOR_READ(fn) PHYSFS_openRead(fn)
109 | #endif
110 | static int MY_GETC(MY_FILETYPE *const fp) {
111 | unsigned char c;
112 | /*if (PHYSFS_eof(fp)) {
113 | return EOF;
114 | }
115 | MY_READ(&c, 1, 1, fp);*/
116 | if (MY_READ(&c, 1, 1, fp) != 1) {
117 | return EOF;
118 | }
119 | return c;
120 | }
121 | static char * MY_GETS(char * const str, const int size,
122 | MY_FILETYPE *const fp) {
123 | int i = 0;
124 | int c;
125 | do {
126 | if (i == size-1) {
127 | break;
128 | }
129 | c = MY_GETC(fp);
130 | if (c == EOF) {
131 | break;
132 | }
133 | str[i++] = c;
134 | } while (c != '\0' &&
135 | c != -1 &&
136 | c != '\n');
137 | str[i] = '\0';
138 | if (i == 0) {
139 | return NULL;
140 | }
141 | return str;
142 | }
143 | #define MY_CLOSE(fp) PHYSFS_close(fp)
144 | #define MY_ATEOF(fp) PHYSFS_eof(fp)
145 | #define MY_TELL(fp) PHYSFS_tell(fp)
146 | #define MY_SEEK(fp,o) PHYSFS_seek(fp,o)
147 | #define MY_REWIND(fp) MY_SEEK(fp,0)
148 |
149 | #else
150 |
151 | #define MY_FILETYPE FILE
152 | #define MY_READ(p,s,n,fp) fread(p,s,n,fp)
153 | #define MY_OPEN_FOR_READ(n) fopen(n, "rb")
154 | #define MY_GETC(fp) fgetc(fp)
155 | #define MY_GETS(str,size,fp) fgets(str,size,fp)
156 | #define MY_CLOSE(fp) fclose(fp)
157 | #define MY_ATEOF(fp) feof(fp)
158 | #define MY_TELL(fp) ftell(fp)
159 | #define MY_SEEK(fp,o) fseek(fp,o, SEEK_SET)
160 | #define MY_REWIND(fp) rewind(fp)
161 | /*static void MY_SETBUFFER(const MY_FILETYPE *const file, const int num) { }*/
162 | #define MY_SETBUFFER(fp,size)
163 | #endif
164 |
165 | #endif
166 |
--------------------------------------------------------------------------------
/physfs/src/physfs_archiver_vdf.c:
--------------------------------------------------------------------------------
1 | /*
2 | * VDF support routines for PhysicsFS.
3 | *
4 | * This driver handles Gothic I/II VDF archives.
5 | * This format (but not this driver) was designed by Piranha Bytes for
6 | * use wih the ZenGin engine.
7 | *
8 | * This file was written by Francesco Bertolaccini, based on the UNPK archiver
9 | * by Ryan C. Gordon and the works of degenerated1123 and Nico Bendlin.
10 | */
11 |
12 | #define __PHYSICSFS_INTERNAL__
13 | #include "physfs_internal.h"
14 |
15 | #if PHYSFS_SUPPORTS_VDF
16 |
17 | #include
18 |
19 | #define VDF_COMMENT_LENGTH 256
20 | #define VDF_SIGNATURE_LENGTH 16
21 | #define VDF_ENTRY_NAME_LENGTH 64
22 | #define VDF_ENTRY_DIR 0x80000000
23 |
24 | static const char* VDF_SIGNATURE_G1 = "PSVDSC_V2.00\r\n\r\n";
25 | static const char* VDF_SIGNATURE_G2 = "PSVDSC_V2.00\n\r\n\r";
26 |
27 |
28 | static inline int readui32(PHYSFS_Io *io, PHYSFS_uint32 *val)
29 | {
30 | PHYSFS_uint32 v;
31 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &v, sizeof (v)), 0);
32 | *val = PHYSFS_swapULE32(v);
33 | return 1;
34 | } /* readui32 */
35 |
36 |
37 | static PHYSFS_sint64 vdfDosTimeToEpoch(const PHYSFS_uint32 dostime)
38 | {
39 | /* VDF stores timestamps as 32bit DOS dates: the seconds are counted in
40 | 2-seconds intervals and the years are counted since 1 Jan. 1980 */
41 | struct tm t;
42 | memset(&t, '\0', sizeof (t));
43 | t.tm_year = ((int) ((dostime >> 25) & 0x7F)) + 80; /* 1980 to 1900 */
44 | t.tm_mon = ((int) ((dostime >> 21) & 0xF)) - 1; /* 1-12 to 0-11 */
45 | t.tm_mday = (int) ((dostime >> 16) & 0x1F);
46 | t.tm_hour = (int) ((dostime >> 11) & 0x1F);
47 | t.tm_min = (int) ((dostime >> 5) & 0x3F);
48 | t.tm_sec = ((int) ((dostime >> 0) & 0x1F)) * 2; /* 2 seconds to 1. */
49 | return (PHYSFS_sint64) mktime(&t);
50 | } /* vdfDosTimeToEpoch */
51 |
52 |
53 | static int vdfLoadEntries(PHYSFS_Io *io, const PHYSFS_uint32 count,
54 | const PHYSFS_sint64 ts, void *arc)
55 | {
56 | PHYSFS_uint32 i;
57 |
58 | for (i = 0; i < count; i++)
59 | {
60 | char name[VDF_ENTRY_NAME_LENGTH + 1];
61 | int namei;
62 | PHYSFS_uint32 jump, size, type, attr;
63 |
64 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, name, sizeof (name) - 1), 0);
65 | BAIL_IF_ERRPASS(!readui32(io, &jump), 0);
66 | BAIL_IF_ERRPASS(!readui32(io, &size), 0);
67 | BAIL_IF_ERRPASS(!readui32(io, &type), 0);
68 | BAIL_IF_ERRPASS(!readui32(io, &attr), 0);
69 |
70 | /* Trim whitespace off the end of the filename */
71 | name[VDF_ENTRY_NAME_LENGTH] = '\0'; /* always null-terminated. */
72 | for (namei = VDF_ENTRY_NAME_LENGTH - 1; namei >= 0; namei--)
73 | {
74 | /* We assume the filenames are low-ASCII; consider the archive
75 | corrupt if we see something above 127, since we don't know the
76 | encoding. (We can change this later if we find out these exist
77 | and are intended to be, say, latin-1 or UTF-8 encoding). */
78 | BAIL_IF(((PHYSFS_uint8) name[namei]) > 127, PHYSFS_ERR_CORRUPT, 0);
79 |
80 | if (name[namei] == ' ')
81 | name[namei] = '\0';
82 | else
83 | break;
84 | } /* for */
85 |
86 | BAIL_IF(!name[0], PHYSFS_ERR_CORRUPT, 0);
87 | if (!(type & VDF_ENTRY_DIR)) {
88 | BAIL_IF_ERRPASS(!UNPK_addEntry(arc, name, 0, ts, ts, jump, size), 0);
89 | }
90 | } /* for */
91 |
92 | return 1;
93 | } /* vdfLoadEntries */
94 |
95 |
96 | static void *VDF_openArchive(PHYSFS_Io *io, const char *name,
97 | int forWriting, int *claimed)
98 | {
99 | PHYSFS_uint8 ignore[16];
100 | PHYSFS_uint8 sig[VDF_SIGNATURE_LENGTH];
101 | PHYSFS_uint32 count, timestamp, version, dataSize, rootCatOffset;
102 | void *unpkarc;
103 |
104 | assert(io != NULL); /* shouldn't ever happen. */
105 |
106 | BAIL_IF(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
107 |
108 | /* skip the 256-byte comment field. */
109 | BAIL_IF_ERRPASS(!io->seek(io, VDF_COMMENT_LENGTH), NULL);
110 |
111 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, sig, sizeof (sig)), NULL);
112 |
113 | if ((memcmp(sig, VDF_SIGNATURE_G1, VDF_SIGNATURE_LENGTH) != 0) &&
114 | (memcmp(sig, VDF_SIGNATURE_G2, VDF_SIGNATURE_LENGTH) != 0))
115 | {
116 | BAIL(PHYSFS_ERR_UNSUPPORTED, NULL);
117 | } /* if */
118 |
119 | *claimed = 1;
120 |
121 | BAIL_IF_ERRPASS(!readui32(io, &count), NULL);
122 | BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, ignore, 4), NULL); /* numFiles */
123 | BAIL_IF_ERRPASS(!readui32(io, ×tamp), NULL);
124 | BAIL_IF_ERRPASS(!readui32(io, &dataSize), NULL); /* dataSize */
125 | BAIL_IF_ERRPASS(!readui32(io, &rootCatOffset), NULL); /* rootCatOff */
126 | BAIL_IF_ERRPASS(!readui32(io, &version), NULL);
127 |
128 | BAIL_IF(version != 0x50, PHYSFS_ERR_UNSUPPORTED, NULL);
129 |
130 | BAIL_IF_ERRPASS(!io->seek(io, rootCatOffset), NULL);
131 |
132 | /* !!! FIXME: check case_sensitive and only_usascii params for this archive. */
133 | unpkarc = UNPK_openArchive(io, 1, 0);
134 | BAIL_IF_ERRPASS(!unpkarc, NULL);
135 |
136 | if (!vdfLoadEntries(io, count, vdfDosTimeToEpoch(timestamp), unpkarc))
137 | {
138 | UNPK_abandonArchive(unpkarc);
139 | return NULL;
140 | } /* if */
141 |
142 | return unpkarc;
143 | } /* VDF_openArchive */
144 |
145 |
146 | const PHYSFS_Archiver __PHYSFS_Archiver_VDF =
147 | {
148 | CURRENT_PHYSFS_ARCHIVER_API_VERSION,
149 | {
150 | "VDF",
151 | "Gothic I/II engine format",
152 | "Francesco Bertolaccini ",
153 | "https://github.com/frabert",
154 | 0, /* supportsSymlinks */
155 | },
156 | VDF_openArchive,
157 | UNPK_enumerate,
158 | UNPK_openRead,
159 | UNPK_openWrite,
160 | UNPK_openAppend,
161 | UNPK_remove,
162 | UNPK_mkdir,
163 | UNPK_stat,
164 | UNPK_closeArchive
165 | };
166 |
167 | #endif /* defined PHYSFS_SUPPORTS_VDF */
168 |
169 | /* end of physfs_archiver_vdf.c ... */
170 |
--------------------------------------------------------------------------------
/test.lua:
--------------------------------------------------------------------------------
1 | local lunit = require "luaunit"
2 | local physfs = require "physfs"
3 |
4 | local eq = lunit.assert_equals
5 | local match = lunit.assert_str_matches
6 | local fail = lunit.assert_error_msg_matches
7 |
8 | print("version: ", physfs.version())
9 | print("types: " .. #assert(physfs.supportedArchiveTypes()))
10 | print("cdRom: " .. #assert(physfs.cdRomDirs()))
11 | print("files: " .. #assert(physfs.files "/"))
12 |
13 | function _G.testBaseInfo()
14 | print("baseDir: " .. assert(physfs.baseDir))
15 |
16 | assert(physfs.mount ".")
17 | eq(physfs.mountPoint ".", "/")
18 | eq(#physfs.searchPath(), 1)
19 | assert(physfs.unmount ".")
20 | eq(physfs.mountPoint ".", nil)
21 | eq(#physfs.searchPath(), 0)
22 | assert(physfs.mount ".")
23 |
24 | local dir = assert(physfs.prefDir("github", "starwing"))
25 | match(dir, ".-starwing.*")
26 | assert(physfs.saneConfig("github", "starwing"))
27 | match(physfs.writeDir(), ".-starwing.*")
28 | assert(physfs.unmount(dir))
29 |
30 | local useSymlink = physfs.useSymlink()
31 | physfs.useSymlink(true)
32 | physfs.useSymlink(useSymlink)
33 |
34 | physfs.lastError "OUT_OF_MEMORY"
35 | eq(physfs.lastError(), "OUT_OF_MEMORY")
36 | physfs.lastError "OK"
37 |
38 | assert(physfs.writeDir ".")
39 | match(physfs.writeDir(), "%.")
40 | end
41 |
42 | function _G.testFile()
43 | local fh = assert(physfs.openWrite "_test_file")
44 | assert(#fh == 0)
45 | eq(fh:eof(), false) -- only openRead could return true
46 | fail("read: file open for writing", assert, fh:read())
47 | assert(fh:write())
48 | assert(fh:write("foobar"))
49 | fail("bad argument #2 to.-%(invalid empty format.*", fh.writeInt, fh, "")
50 | fail(".-invalid format char 'z'.*", fh.writeInt, fh, "z1i", 4), 4)
127 | eq(physfs.convInt(">2i", 4), 0x0400)
128 | eq(physfs.convInt(">4i", 4), 0x04000000)
129 | eq(physfs.convInt(">8i", 4), 0x0400000000000000)
130 | eq(physfs.convInt("<1u", 4), 4)
131 | eq(physfs.convInt("<2u", 4), 4)
132 | eq(physfs.convInt("<4u", 4), 4)
133 | eq(physfs.convInt("<8u", 4), 4)
134 | eq(physfs.convInt(">1u", 4), 4)
135 | eq(physfs.convInt(">2u", 4), 0x0400)
136 | eq(physfs.convInt(">4u", 4), 0x04000000)
137 | eq(physfs.convInt(">8u", 4), 0x0400000000000000)
138 | end
139 |
140 | function _G.testLoader()
141 | fail(".-physfs search path.*", require, "foobar")
142 |
143 | local function test_mod(m)
144 | eq(m.info(), "this is a test module from physfs")
145 | eq(m.add(1,2), 3)
146 | end
147 | assert(physfs.mount "test_mod.zip")
148 | test_mod(require "test_mod")
149 |
150 | local fh = assert(physfs.openRead "test_mod.zip")
151 | match(tostring(fh), "physfs.File: 0x%x+")
152 | local fh2 = assert(physfs.mountFile(fh, "fn2", "test2"))
153 | eq(fh, fh2)
154 | match(tostring(fh), "physfs.File: %(null%)")
155 | -- NOTICE there is a bug, if not given name to mount(File|Memory),
156 | -- physfs libary has several bugs about exists and searchPath.
157 | -- eq(physfs.exists("test2/test_mod.lua"), true) -- fail
158 | test_mod(require "test2.test_mod")
159 |
160 | fh = assert(physfs.openRead "test_mod.zip")
161 | local content = assert(fh:read())
162 | eq(#content, #fh)
163 | assert(fh:close())
164 | assert(physfs.mountMemory(content, "content", "test3"))
165 | test_mod(require "test3.test_mod")
166 | end
167 |
168 | os.exit(lunit.LuaUnit.run(), true)
169 |
170 |
--------------------------------------------------------------------------------
/physfs/extras/ignorecase.c:
--------------------------------------------------------------------------------
1 | /** \file ignorecase.c */
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include "physfs.h"
9 | #include "ignorecase.h"
10 |
11 | /**
12 | * Please see ignorecase.h for details.
13 | *
14 | * License: this code is public domain. I make no warranty that it is useful,
15 | * correct, harmless, or environmentally safe.
16 | *
17 | * This particular file may be used however you like, including copying it
18 | * verbatim into a closed-source project, exploiting it commercially, and
19 | * removing any trace of my name from the source (although I hope you won't
20 | * do that). I welcome enhancements and corrections to this file, but I do
21 | * not require you to send me patches if you make changes. This code has
22 | * NO WARRANTY.
23 | *
24 | * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
25 | * Please see LICENSE.txt in the root of the source tree.
26 | *
27 | * \author Ryan C. Gordon.
28 | */
29 |
30 | static int locateOneElement(char *buf)
31 | {
32 | char *ptr;
33 | char **rc;
34 | char **i;
35 |
36 | if (PHYSFS_exists(buf))
37 | return 1; /* quick rejection: exists in current case. */
38 |
39 | ptr = strrchr(buf, '/'); /* find entry at end of path. */
40 | if (ptr == NULL)
41 | {
42 | rc = PHYSFS_enumerateFiles("/");
43 | ptr = buf;
44 | } /* if */
45 | else
46 | {
47 | *ptr = '\0';
48 | rc = PHYSFS_enumerateFiles(buf);
49 | *ptr = '/';
50 | ptr++; /* point past dirsep to entry itself. */
51 | } /* else */
52 |
53 | if (rc != NULL)
54 | {
55 | for (i = rc; *i != NULL; i++)
56 | {
57 | if (PHYSFS_utf8stricmp(*i, ptr) == 0)
58 | {
59 | strcpy(ptr, *i); /* found a match. Overwrite with this case. */
60 | PHYSFS_freeList(rc);
61 | return 1;
62 | } /* if */
63 | } /* for */
64 |
65 | PHYSFS_freeList(rc);
66 | } /* if */
67 |
68 | /* no match at all... */
69 | return 0;
70 | } /* locateOneElement */
71 |
72 |
73 | int PHYSFSEXT_locateCorrectCase(char *buf)
74 | {
75 | int rc;
76 | char *ptr;
77 |
78 | while (*buf == '/') /* skip any '/' at start of string... */
79 | buf++;
80 |
81 | ptr = buf;
82 | if (*ptr == '\0')
83 | return 0; /* Uh...I guess that's success. */
84 |
85 | while ( (ptr = strchr(ptr + 1, '/')) != NULL )
86 | {
87 | *ptr = '\0'; /* block this path section off */
88 | rc = locateOneElement(buf);
89 | *ptr = '/'; /* restore path separator */
90 | if (!rc)
91 | return -2; /* missing element in path. */
92 | } /* while */
93 |
94 | /* check final element... */
95 | return locateOneElement(buf) ? 0 : -1;
96 | } /* PHYSFSEXT_locateCorrectCase */
97 |
98 |
99 | #ifdef TEST_PHYSFSEXT_LOCATECORRECTCASE
100 | int main(int argc, char **argv)
101 | {
102 | int rc;
103 | char buf[128];
104 | PHYSFS_File *f;
105 |
106 | if (!PHYSFS_init(argv[0]))
107 | {
108 | fprintf(stderr, "PHYSFS_init(): %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
109 | return 1;
110 | } /* if */
111 |
112 | if (!PHYSFS_addToSearchPath(".", 1))
113 | {
114 | fprintf(stderr, "PHYSFS_addToSearchPath(): %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
115 | PHYSFS_deinit();
116 | return 1;
117 | } /* if */
118 |
119 | if (!PHYSFS_setWriteDir("."))
120 | {
121 | fprintf(stderr, "PHYSFS_setWriteDir(): %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
122 | PHYSFS_deinit();
123 | return 1;
124 | } /* if */
125 |
126 | if (!PHYSFS_mkdir("/a/b/c"))
127 | {
128 | fprintf(stderr, "PHYSFS_mkdir(): %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
129 | PHYSFS_deinit();
130 | return 1;
131 | } /* if */
132 |
133 | if (!PHYSFS_mkdir("/a/b/C"))
134 | {
135 | fprintf(stderr, "PHYSFS_mkdir(): %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
136 | PHYSFS_deinit();
137 | return 1;
138 | } /* if */
139 |
140 | f = PHYSFS_openWrite("/a/b/c/x.txt");
141 | PHYSFS_close(f);
142 | if (f == NULL)
143 | {
144 | fprintf(stderr, "PHYSFS_openWrite(): %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
145 | PHYSFS_deinit();
146 | return 1;
147 | } /* if */
148 |
149 | f = PHYSFS_openWrite("/a/b/C/X.txt");
150 | PHYSFS_close(f);
151 | if (f == NULL)
152 | {
153 | fprintf(stderr, "PHYSFS_openWrite(): %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
154 | PHYSFS_deinit();
155 | return 1;
156 | } /* if */
157 |
158 | strcpy(buf, "/a/b/c/x.txt");
159 | rc = PHYSFSEXT_locateCorrectCase(buf);
160 | if ((rc != 0) || (strcmp(buf, "/a/b/c/x.txt") != 0))
161 | printf("test 1 failed\n");
162 |
163 | strcpy(buf, "/a/B/c/x.txt");
164 | rc = PHYSFSEXT_locateCorrectCase(buf);
165 | if ((rc != 0) || (strcmp(buf, "/a/b/c/x.txt") != 0))
166 | printf("test 2 failed\n");
167 |
168 | strcpy(buf, "/a/b/C/x.txt");
169 | rc = PHYSFSEXT_locateCorrectCase(buf);
170 | if ((rc != 0) || (strcmp(buf, "/a/b/C/X.txt") != 0))
171 | printf("test 3 failed\n");
172 |
173 | strcpy(buf, "/a/b/c/X.txt");
174 | rc = PHYSFSEXT_locateCorrectCase(buf);
175 | if ((rc != 0) || (strcmp(buf, "/a/b/c/x.txt") != 0))
176 | printf("test 4 failed\n");
177 |
178 | strcpy(buf, "/a/b/c/z.txt");
179 | rc = PHYSFSEXT_locateCorrectCase(buf);
180 | if ((rc != -1) || (strcmp(buf, "/a/b/c/z.txt") != 0))
181 | printf("test 5 failed\n");
182 |
183 | strcpy(buf, "/A/B/Z/z.txt");
184 | rc = PHYSFSEXT_locateCorrectCase(buf);
185 | if ((rc != -2) || (strcmp(buf, "/a/b/Z/z.txt") != 0))
186 | printf("test 6 failed\n");
187 |
188 | printf("Testing completed.\n");
189 | printf(" If no errors were reported, you're good to go.\n");
190 |
191 | PHYSFS_delete("/a/b/c/x.txt");
192 | PHYSFS_delete("/a/b/C/X.txt");
193 | PHYSFS_delete("/a/b/c");
194 | PHYSFS_delete("/a/b/C");
195 | PHYSFS_delete("/a/b");
196 | PHYSFS_delete("/a");
197 | PHYSFS_deinit();
198 | return 0;
199 | } /* main */
200 | #endif
201 |
202 | /* end of ignorecase.c ... */
203 |
204 |
--------------------------------------------------------------------------------
/physfs/src/physfs_platform_apple.m:
--------------------------------------------------------------------------------
1 | /*
2 | * Apple platform (macOS, iOS, watchOS, etc) support routines for PhysicsFS.
3 | *
4 | * Please see the file LICENSE.txt in the source's root directory.
5 | *
6 | * This file written by Ryan C. Gordon.
7 | */
8 |
9 | #define __PHYSICSFS_INTERNAL__
10 | #include "physfs_platforms.h"
11 |
12 | #ifdef PHYSFS_PLATFORM_APPLE
13 |
14 | #include
15 | #include
16 |
17 | #include "physfs_internal.h"
18 |
19 | int __PHYSFS_platformInit(void)
20 | {
21 | return 1; /* success. */
22 | } /* __PHYSFS_platformInit */
23 |
24 |
25 | void __PHYSFS_platformDeinit(void)
26 | {
27 | /* no-op */
28 | } /* __PHYSFS_platformDeinit */
29 |
30 |
31 | char *__PHYSFS_platformCalcBaseDir(const char *argv0)
32 | {
33 | @autoreleasepool
34 | {
35 | NSString *path = [[NSBundle mainBundle] bundlePath];
36 | BAIL_IF(!path, PHYSFS_ERR_OS_ERROR, NULL);
37 | size_t len = [path lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
38 | char *retval = (char *) allocator.Malloc(len + 2);
39 | BAIL_IF(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
40 | [path getCString:retval maxLength:len+1 encoding:NSUTF8StringEncoding];
41 | retval[len] = '/';
42 | retval[len+1] = '\0';
43 | return retval; /* whew. */
44 | } /* @autoreleasepool */
45 | } /* __PHYSFS_platformCalcBaseDir */
46 |
47 |
48 | char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
49 | {
50 | @autoreleasepool
51 | {
52 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, TRUE);
53 | BAIL_IF(!paths, PHYSFS_ERR_OS_ERROR, NULL);
54 | NSString *path = (NSString *) [paths objectAtIndex:0];
55 | BAIL_IF(!path, PHYSFS_ERR_OS_ERROR, NULL);
56 | size_t len = [path lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
57 | const size_t applen = strlen(app);
58 | char *retval = (char *) allocator.Malloc(len + applen + 3);
59 | BAIL_IF(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
60 | [path getCString:retval maxLength:len+1 encoding:NSUTF8StringEncoding];
61 | snprintf(retval + len, applen + 3, "/%s/", app);
62 | return retval; /* whew. */
63 | } /* @autoreleasepool */
64 | } /* __PHYSFS_platformCalcPrefDir */
65 |
66 |
67 | /* CD-ROM detection code... */
68 |
69 | /*
70 | * Code based on sample from Apple Developer Connection:
71 | * https://developer.apple.com/samplecode/Sample_Code/Devices_and_Hardware/Disks/VolumeToBSDNode/VolumeToBSDNode.c.htm
72 | */
73 |
74 | #if !defined(PHYSFS_NO_CDROM_SUPPORT)
75 |
76 | #include
77 | #include
78 | #include
79 | #include
80 | #include
81 |
82 | static int darwinIsWholeMedia(io_service_t service)
83 | {
84 | int retval = 0;
85 | CFTypeRef wholeMedia;
86 |
87 | if (!IOObjectConformsTo(service, kIOMediaClass))
88 | return 0;
89 |
90 | wholeMedia = IORegistryEntryCreateCFProperty(service,
91 | CFSTR(kIOMediaWholeKey),
92 | NULL, 0);
93 | if (wholeMedia == NULL)
94 | return 0;
95 |
96 | retval = CFBooleanGetValue(wholeMedia);
97 | CFRelease(wholeMedia);
98 |
99 | return retval;
100 | } /* darwinIsWholeMedia */
101 |
102 |
103 | static int darwinIsMountedDisc(char *bsdName, mach_port_t mainPort)
104 | {
105 | int retval = 0;
106 | CFMutableDictionaryRef matchingDict;
107 | kern_return_t rc;
108 | io_iterator_t iter;
109 | io_service_t service;
110 |
111 | if ((matchingDict = IOBSDNameMatching(mainPort, 0, bsdName)) == NULL)
112 | return 0;
113 |
114 | rc = IOServiceGetMatchingServices(mainPort, matchingDict, &iter);
115 | if ((rc != KERN_SUCCESS) || (!iter))
116 | return 0;
117 |
118 | service = IOIteratorNext(iter);
119 | IOObjectRelease(iter);
120 | if (!service)
121 | return 0;
122 |
123 | rc = IORegistryEntryCreateIterator(service, kIOServicePlane,
124 | kIORegistryIterateRecursively | kIORegistryIterateParents, &iter);
125 |
126 | if (!iter)
127 | return 0;
128 |
129 | if (rc != KERN_SUCCESS)
130 | {
131 | IOObjectRelease(iter);
132 | return 0;
133 | } /* if */
134 |
135 | IOObjectRetain(service); /* add an extra object reference... */
136 |
137 | do
138 | {
139 | if (darwinIsWholeMedia(service))
140 | {
141 | if ( (IOObjectConformsTo(service, kIOCDMediaClass)) ||
142 | (IOObjectConformsTo(service, kIODVDMediaClass)) )
143 | {
144 | retval = 1;
145 | } /* if */
146 | } /* if */
147 | IOObjectRelease(service);
148 | } while ((service = IOIteratorNext(iter)) && (!retval));
149 |
150 | IOObjectRelease(iter);
151 | IOObjectRelease(service);
152 |
153 | return retval;
154 | } /* darwinIsMountedDisc */
155 |
156 | #endif /* !defined(PHYSFS_NO_CDROM_SUPPORT) */
157 |
158 |
159 | void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
160 | {
161 | #if !defined(PHYSFS_NO_CDROM_SUPPORT)
162 | /* macOS 12.0 changed "master" names to "main". */
163 | typedef kern_return_t (*ioMainPortFn)(mach_port_t, mach_port_t *);
164 | static ioMainPortFn ioMainPort = NULL;
165 | const char *devPrefix = "/dev/";
166 | const int prefixLen = strlen(devPrefix);
167 | mach_port_t mainPort = 0;
168 | struct statfs *mntbufp;
169 | int i, mounts;
170 |
171 | if (ioMainPort == NULL)
172 | {
173 | ioMainPort = (ioMainPortFn) dlsym(RTLD_DEFAULT, "IOMainPort");
174 | if (!ioMainPort)
175 | ioMainPort = (ioMainPortFn) dlsym(RTLD_DEFAULT, "IOMasterPort");
176 | if (!ioMainPort)
177 | return; /* oh well, no CD-ROMs for you. */
178 | } /* if */
179 |
180 | if (ioMainPort(MACH_PORT_NULL, &mainPort) != KERN_SUCCESS)
181 | BAIL(PHYSFS_ERR_OS_ERROR, ) /*return void*/;
182 |
183 | mounts = getmntinfo(&mntbufp, MNT_WAIT); /* NOT THREAD SAFE! */
184 | for (i = 0; i < mounts; i++)
185 | {
186 | char *dev = mntbufp[i].f_mntfromname;
187 | char *mnt = mntbufp[i].f_mntonname;
188 | if (strncmp(dev, devPrefix, prefixLen) != 0) /* a virtual device? */
189 | continue;
190 |
191 | dev += prefixLen;
192 | if (darwinIsMountedDisc(dev, mainPort))
193 | cb(data, mnt);
194 | } /* for */
195 | #endif /* !defined(PHYSFS_NO_CDROM_SUPPORT) */
196 | } /* __PHYSFS_platformDetectAvailableCDs */
197 |
198 | #endif /* PHYSFS_PLATFORM_APPLE */
199 |
200 | /* end of physfs_platform_apple.m ... */
201 |
202 |
--------------------------------------------------------------------------------
/physfs/extras/globbing.h:
--------------------------------------------------------------------------------
1 | #ifndef INCL_PHYSFSEXT_GLOBBING_H
2 | #define INCL_PHYSFSEXT_GLOBBING_H
3 |
4 | /** \file globbing.h */
5 |
6 | #include "physfs.h"
7 |
8 | /**
9 | * \mainpage PhysicsFS globbing
10 | *
11 | * This is an extension to PhysicsFS to let you search for files with basic
12 | * wildcard matching, regardless of what sort of filesystem or archive they
13 | * reside in. It does this by enumerating directories as needed and manually
14 | * locating matching entries.
15 | *
16 | * Usage: Set up PhysicsFS as you normally would, then use
17 | * PHYSFSEXT_enumerateFilesWildcard() when enumerating files. This is just
18 | * like PHYSFS_enumerateFiles(), but it returns a subset that matches your
19 | * wildcard pattern. You must call PHYSFSEXT_freeEnumeration() on the results,
20 | * just PHYSFS_enumerateFiles() would do with PHYSFS_freeList().
21 | *
22 | * License: this code is public domain. I make no warranty that it is useful,
23 | * correct, harmless, or environmentally safe.
24 | *
25 | * This particular file may be used however you like, including copying it
26 | * verbatim into a closed-source project, exploiting it commercially, and
27 | * removing any trace of my name from the source (although I hope you won't
28 | * do that). I welcome enhancements and corrections to this file, but I do
29 | * not require you to send me patches if you make changes. This code has
30 | * NO WARRANTY.
31 | *
32 | * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
33 | * Please see LICENSE.txt in the source's "docs" directory.
34 | *
35 | * \author Ryan C. Gordon.
36 | */
37 |
38 | #ifdef __cplusplus
39 | extern "C" {
40 | #endif
41 |
42 | /**
43 | * \fn char **PHYSFS_enumerateFilesWildcard(const char *dir, const char *wildcard, int caseSensitive)
44 | * \brief Get a file listing of a search path's directory, filtered with a wildcard pattern.
45 | *
46 | * Matching directories are interpolated. That is, if "C:\mydir" is in the
47 | * search path and contains a directory "savegames" that contains "x.sav",
48 | * "y.Sav", and "z.txt", and there is also a "C:\userdir" in the search path
49 | * that has a "savegames" subdirectory with "w.sav", then the following code:
50 | *
51 | * \code
52 | * char **rc = PHYSFS_enumerateFilesWildcard("savegames", "*.sav", 0);
53 | * char **i;
54 | *
55 | * for (i = rc; *i != NULL; i++)
56 | * printf(" * We've got [%s].\n", *i);
57 | *
58 | * PHYSFS_freeList(rc);
59 | * \endcode
60 | *
61 | * ...will print:
62 | *
63 | * \verbatim
64 | * We've got [x.sav].
65 | * We've got [y.Sav].
66 | * We've got [w.sav].\endverbatim
67 | *
68 | * Feel free to sort the list however you like. We only promise there will
69 | * be no duplicates, but not what order the final list will come back in.
70 | *
71 | * Wildcard strings can use the '*' and '?' characters, currently.
72 | * Matches can be case-insensitive if you pass a zero for argument 3.
73 | *
74 | * Don't forget to call PHYSFSEXT_freeEnumerator() with the return value from
75 | * this function when you are done with it. As we use PhysicsFS's allocator
76 | * for this list, you must free it before calling PHYSFS_deinit().
77 | * Do not use PHYSFS_freeList() on the returned value!
78 | *
79 | * \param dir directory in platform-independent notation to enumerate.
80 | * \param wildcard Wildcard pattern to use for filtering.
81 | * \param caseSensitive Zero for case-insensitive matching,
82 | * non-zero for case-sensitive.
83 | * \return Null-terminated array of null-terminated strings.
84 | *
85 | * \sa PHYSFSEXT_freeEnumeration
86 | */
87 | PHYSFS_DECL char **PHYSFSEXT_enumerateFilesWildcard(const char *dir,
88 | const char *wildcard,
89 | int caseSensitive);
90 |
91 | /**
92 | * \fn void PHYSFSEXT_freeEnumeration(char **list)
93 | * \brief Free data returned by PHYSFSEXT_enumerateFilesWildcard
94 | *
95 | * Conceptually, this works like PHYSFS_freeList(), but is used with data
96 | * returned by PHYSFSEXT_enumerateFilesWildcard() only. Be sure to call this
97 | * on any returned data from that function before
98 | *
99 | * \param list Pointer previously returned by
100 | * PHYSFSEXT_enumerateFilesWildcard(). It is safe to pass a
101 | * NULL here.
102 | *
103 | * \sa PHYSFSEXT_enumerateFilesWildcard
104 | */
105 | PHYSFS_DECL void PHYSFSEXT_freeEnumeration(char **list);
106 |
107 |
108 | /**
109 | * \fn void PHYSFSEXT_enumerateFilesCallbackWildcard(const char *dir, const char *wildcard, int caseSensitive, PHYSFS_EnumFilesCallback c, void *d);
110 | * \brief Get a file listing of a search path's directory, filtered with a wildcard pattern, using an application-defined callback.
111 | *
112 | * This function is equivalent to PHYSFSEXT_enumerateFilesWildcard(). It
113 | * reports file listings, filtered by a wildcard pattern.
114 | *
115 | * Unlike PHYSFS_enumerateFiles(), this function does not return an array.
116 | * Rather, it calls a function specified by the application once per
117 | * element of the search path:
118 | *
119 | * \code
120 | *
121 | * static void printDir(void *data, const char *origdir, const char *fname)
122 | * {
123 | * printf(" * We've got [%s] in [%s].\n", fname, origdir);
124 | * }
125 | *
126 | * // ...
127 | * PHYSFS_enumerateFilesCallbackWildcard("savegames","*.sav",0,printDir,NULL);
128 | * \endcode
129 | *
130 | * Items sent to the callback are not guaranteed to be in any order whatsoever.
131 | * There is no sorting done at this level, and if you need that, you should
132 | * probably use PHYSFS_enumerateFilesWildcard() instead, which guarantees
133 | * alphabetical sorting. This form reports whatever is discovered in each
134 | * archive before moving on to the next. Even within one archive, we can't
135 | * guarantee what order it will discover data. Any sorting you find in
136 | * these callbacks is just pure luck. Do not rely on it. As this walks
137 | * the entire list of archives, you may receive duplicate filenames.
138 | *
139 | * Wildcard strings can use the '*' and '?' characters, currently.
140 | * Matches can be case-insensitive if you pass a zero for argument 3.
141 | *
142 | * \param dir Directory, in platform-independent notation, to enumerate.
143 | * \param wildcard Wildcard pattern to use for filtering.
144 | * \param caseSensitive Zero for case-insensitive matching,
145 | * non-zero for case-sensitive.
146 | * \param c Callback function to notify about search path elements.
147 | * \param d Application-defined data passed to callback. Can be NULL.
148 | *
149 | * \sa PHYSFS_EnumFilesCallback
150 | * \sa PHYSFS_enumerateFiles
151 | */
152 | PHYSFS_DECL void PHYSFSEXT_enumerateFilesCallbackWildcard(const char *dir,
153 | const char *wildcard,
154 | int caseSensitive,
155 | PHYSFS_EnumFilesCallback c,
156 | void *d);
157 |
158 | #ifdef __cplusplus
159 | }
160 | #endif
161 |
162 | #endif /* include-once blocker. */
163 |
164 | /* end of globbing.h ... */
165 |
166 |
--------------------------------------------------------------------------------
/physfs/docs/INSTALL.txt:
--------------------------------------------------------------------------------
1 |
2 | The latest PhysicsFS information and releases can be found at:
3 | https://icculus.org/physfs/
4 |
5 | Building is (ahem) very easy.
6 |
7 |
8 | ALL PLATFORMS:
9 |
10 | Please read the text file LICENSE.txt in the root of the source tree.
11 | The license is extremely liberal, even to closed-source, commercial
12 | applications.
13 |
14 | If you've got Doxygen (http://www.doxygen.org/) installed, you can run it
15 | without any command line arguments in the root of the source tree to generate
16 | the API reference (or build the "docs" target from your build system). This
17 | is optional. You can browse the API docs online here:
18 |
19 | https://icculus.org/physfs/docs/
20 |
21 |
22 |
23 | BUILD IT WITH YOUR OWN PROGRAM:
24 |
25 | If you don't care about formal packaging: just add everything in the "src"
26 | directory to whatever you use to build your program and compile it along with
27 | everything else, and you're done. It should compile with any reasonable
28 | ANSI C compiler, should build cleanly even with excessive compiler warnings
29 | enabled, needs no extra configuration, and allows static linking.
30 | WinRT and Haiku need C++ compilers for their system APIs, but if you aren't on
31 | these platforms and don't have a C++ compiler, don't build the .cpp files.
32 | Likewise: Apple platforms (macOS, iOS, etc) need an Objective-C compiler, but
33 | if you aren't on these platforms and don't have a Objective-C compiler, don't
34 | build the .m file. Everything you need is in the .c sources.
35 |
36 | If this all worked for your specific project, you can stop reading now.
37 |
38 |
39 |
40 | Unix:
41 |
42 | You will need CMake (https://www.cmake.org/) 2.4 or later installed.
43 |
44 | Make a directory, wherever you like. This will be your build directory.
45 |
46 | Chdir to your build directory. Run "cmake /where/i/unpacked/physfs" to
47 | generate Makefiles. You can then run "ccmake ." and customize the build,
48 | but the defaults are probably okay. You can have CMake generate KDevelop
49 | or Ninja project files or whatever, if you prefer these.
50 |
51 | Run "make". PhysicsFS will now build.
52 |
53 | As root, run "make install".
54 | If you get sick of the library, run "make uninstall" as root
55 | and it will remove all traces of the library from the system paths.
56 |
57 | Once you are satisfied, you can delete the build directory.
58 |
59 | Primary Unix development is done with GNU/Linux, but PhysicsFS is known to
60 | work out of the box with several flavors of Unix. It it doesn't work, patches
61 | to get it running can be sent to icculus@icculus.org.
62 |
63 |
64 | Windows:
65 |
66 | If building with Cygwin, mingw32, MSYS, or something else that uses the GNU
67 | toolchain, follow the Unix instructions, above.
68 |
69 | If you want to use Visual Studio, nmake, or the Platform SDK, you will need
70 | CMake (https://www.cmake.org/) 2.4 or later installed. Point CMake at the
71 | CMakeLists.txt file in the root of the source directory and hit the
72 | "Configure" button. After telling it what type of compiler you are targeting
73 | (Borland, Visual Studio, etc), CMake will process for while and then give you
74 | a list of options you can change (what archivers you want to support, etc).
75 | If you aren't sure, the defaults are probably fine. Hit the "Configure"
76 | button again, then "OK" once configuration has completed with options that
77 | match your liking. Now project files for your favorite programming
78 | environment will be generated for you in the directory you specified.
79 | Go there and use them to build PhysicsFS.
80 |
81 | PhysicsFS will only link directly against system libraries that have existed
82 | since Windows NT 3.51. If there's a newer API we want to use, we try to
83 | dynamically load it at runtime and fallback to a reasonable behaviour when
84 | we can't find it. Note that Windows 98 and later _should_
85 | work if you use the Microsoft Layer for Unicode (UNICOWS.DLL) to provide
86 | some missing system APIs, but this is no longer tested as of PhysicsFS 2.1.0.
87 | PhysicsFS 2.0.x is known to work with Windows 95 without UNICOWS.DLL.
88 |
89 | PhysicsFS works on 32-bit and 64-bit Windows. There is no 16-bit Windows
90 | support at all. Windows RT is covered below.
91 |
92 |
93 | Windows RT:
94 |
95 | Windows RT (Windows Phone, Windows Store, UWP) 8.0 and later are supported.
96 | Make sure you include both physfs_platform_windows.c _and_
97 | physfs_platform_winrt.cpp in your build, and that the C++ file has
98 | "Consume Windows Runtime Extension" set to "Yes" in its Visual Studio
99 | properties (from the command line, you want to compile this file with the
100 | "/ZW" compiler switch). CMake can, in theory, generate a project file for
101 | WinRT if you pick a recent Visual Studio target, choose manual cross-compile
102 | options, and set the system name to "WindowsPhone" or "WindowsStore" and the
103 | correct OS version (8.0 or later).
104 |
105 |
106 | PocketPC/WindowsCE:
107 |
108 | Support for PocketPC was removed in PhysicsFS 2.1.0. This was known to work
109 | in the 1.0 releases, but wasn't tested in 2.0 and later. PhysicsFS should
110 | work on modern Windows Phones (see "Windows RT" section).
111 |
112 |
113 | macOS:
114 |
115 | You will need CMake (https://www.cmake.org/) 2.4 or later installed.
116 |
117 | You can either generate a Unix makefile with CMake, or generate an Xcode
118 | project, whichever makes you more comfortable.
119 |
120 | PowerPC and Intel Macs should both be supported.
121 |
122 |
123 | MAC OS 8/9 ("Mac OS Classic"):
124 |
125 | Classic Mac OS support has been dropped in PhysicsFS 2.0. Apple hasn't updated
126 | pre-OSX versions in more than a decade at this point, none of the hardware
127 | they've shipped will boot it for almost as many years, and finding
128 | developer tools for it is becoming almost impossible. As the switch to Intel
129 | hardware has removed the "Classic" emulation environment, it was time to
130 | remove support from PhysicsFS. That being said, the PhysicsFS 1.0 branch can
131 | still target back to Mac OS 8.5, so you can use that if you need support for
132 | this legacy OS. We still very much support modern macOS, though: see above.
133 |
134 |
135 | Emscripten:
136 |
137 | Use the "Unix" instructions, above. You can install the Emscripten SDK and use
138 | the extras/buildbot-emscripten.sh script to automate this for you.
139 |
140 |
141 | BeOS, Zeta, YellowTab:
142 |
143 | BeOS support was dropped in PhysicsFS 2.1.0. Consider installing Haiku, which
144 | we still support.
145 |
146 |
147 | Haiku:
148 |
149 | Use the "Unix" instructions, above.
150 |
151 |
152 | OS/2:
153 |
154 | OS/2 is known to work with OpenWatcom and GCC-based compilers. I couldn't get
155 | an OS/2 port of CMake to generate OpenWatcom project files (although it should
156 | be able to do that in theory), it should be able to do Unix Makefiles with
157 | GCC. It might be easier to just compile PhysicsFS along with the rest of
158 | your project on this platform.
159 |
160 |
161 |
162 | OTHER PLATFORMS:
163 |
164 | Many Unix-like platforms might "just work" with CMake. Some of these platforms
165 | are known to have worked at one time, but have not been heavily tested, if
166 | tested at all. PhysicsFS is, as far as we know, 64-bit and byteorder clean,
167 | and is known to compile on several compilers across many platforms. To
168 | implement a new platform or archiver, please read the heavily-commented
169 | physfs_internal.h and look at the physfs_platform_* and physfs_archiver_*
170 | source files for examples.
171 |
172 | --ryan. (icculus@icculus.org)
173 |
174 |
--------------------------------------------------------------------------------
/physfs/extras/globbing.c:
--------------------------------------------------------------------------------
1 | /** \file globbing.c */
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include "globbing.h"
10 |
11 | /**
12 | * Please see globbing.h for details.
13 | *
14 | * License: this code is public domain. I make no warranty that it is useful,
15 | * correct, harmless, or environmentally safe.
16 | *
17 | * This particular file may be used however you like, including copying it
18 | * verbatim into a closed-source project, exploiting it commercially, and
19 | * removing any trace of my name from the source (although I hope you won't
20 | * do that). I welcome enhancements and corrections to this file, but I do
21 | * not require you to send me patches if you make changes. This code has
22 | * NO WARRANTY.
23 | *
24 | * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
25 | * Please see the file LICENSE.txt in the source's root directory.
26 | *
27 | * \author Ryan C. Gordon.
28 | */
29 |
30 |
31 | static int matchesPattern(const char *fname, const char *wildcard,
32 | int caseSensitive)
33 | {
34 | char x, y;
35 | const char *fnameptr = fname;
36 | const char *wildptr = wildcard;
37 |
38 | while ((*wildptr) && (*fnameptr))
39 | {
40 | y = *wildptr;
41 | if (y == '*')
42 | {
43 | do
44 | {
45 | wildptr++; /* skip multiple '*' in a row... */
46 | } while (*wildptr == '*');
47 |
48 | y = (caseSensitive) ? *wildptr : (char) tolower(*wildptr);
49 |
50 | while (1)
51 | {
52 | x = (caseSensitive) ? *fnameptr : (char) tolower(*fnameptr);
53 | if ((!x) || (x == y))
54 | break;
55 | else
56 | fnameptr++;
57 | } /* while */
58 | } /* if */
59 |
60 | else if (y == '?')
61 | {
62 | wildptr++;
63 | fnameptr++;
64 | } /* else if */
65 |
66 | else
67 | {
68 | if (caseSensitive)
69 | x = *fnameptr;
70 | else
71 | {
72 | x = tolower(*fnameptr);
73 | y = tolower(y);
74 | } /* if */
75 |
76 | wildptr++;
77 | fnameptr++;
78 |
79 | if (x != y)
80 | return 0;
81 | } /* else */
82 | } /* while */
83 |
84 | while (*wildptr == '*')
85 | wildptr++;
86 |
87 | return (*fnameptr == *wildptr);
88 | } /* matchesPattern */
89 |
90 | typedef struct
91 | {
92 | const PHYSFS_Allocator *allocator;
93 | const char *wildcard;
94 | int caseSensitive;
95 | PHYSFS_EnumFilesCallback callback;
96 | void *origData;
97 | } WildcardCallbackData;
98 |
99 |
100 | /*
101 | * This callback sits between the enumerator and the enduser callback,
102 | * filtering out files that don't match the wildcard pattern.
103 | */
104 | static void wildcardCallback(void *_d, const char *origdir, const char *fname)
105 | {
106 | const WildcardCallbackData *data = (const WildcardCallbackData *) _d;
107 | if (matchesPattern(fname, data->wildcard, data->caseSensitive))
108 | data->callback(data->origData, origdir, fname);
109 | } /* wildcardCallback */
110 |
111 |
112 | void PHYSFSEXT_enumerateFilesCallbackWildcard(const char *dir,
113 | const char *wildcard,
114 | int caseSensitive,
115 | PHYSFS_EnumFilesCallback c,
116 | void *d)
117 | {
118 | WildcardCallbackData data;
119 | data.allocator = PHYSFS_getAllocator();
120 | data.wildcard = wildcard;
121 | data.caseSensitive = caseSensitive;
122 | data.callback = c;
123 | data.origData = d;
124 | PHYSFS_enumerateFilesCallback(dir, wildcardCallback, &data);
125 | } /* PHYSFSEXT_enumerateFilesCallbackWildcard */
126 |
127 |
128 | void PHYSFSEXT_freeEnumeration(char **list)
129 | {
130 | const PHYSFS_Allocator *allocator = PHYSFS_getAllocator();
131 | int i;
132 | if (list != NULL)
133 | {
134 | for (i = 0; list[i] != NULL; i++)
135 | allocator->Free(list[i]);
136 | allocator->Free(list);
137 | } /* if */
138 | } /* PHYSFSEXT_freeEnumeration */
139 |
140 |
141 | char **PHYSFSEXT_enumerateFilesWildcard(const char *dir, const char *wildcard,
142 | int caseSensitive)
143 | {
144 | const PHYSFS_Allocator *allocator = PHYSFS_getAllocator();
145 | char **list = PHYSFS_enumerateFiles(dir);
146 | char **retval = NULL;
147 | int totalmatches = 0;
148 | int matches = 0;
149 | char **i;
150 |
151 | for (i = list; *i != NULL; i++)
152 | {
153 | #if 0
154 | printf("matchesPattern: '%s' vs '%s' (%s) ... %s\n", *i, wildcard,
155 | caseSensitive ? "case" : "nocase",
156 | matchesPattern(*i, wildcard, caseSensitive) ? "true" : "false");
157 | #endif
158 | if (matchesPattern(*i, wildcard, caseSensitive))
159 | totalmatches++;
160 | } /* for */
161 |
162 | retval = (char **) allocator->Malloc(sizeof (char *) * (totalmatches+1));
163 | if (retval != NULL)
164 | {
165 | for (i = list; ((matches < totalmatches) && (*i != NULL)); i++)
166 | {
167 | if (matchesPattern(*i, wildcard, caseSensitive))
168 | {
169 | retval[matches] = (char *) allocator->Malloc(strlen(*i) + 1);
170 | if (retval[matches] == NULL)
171 | {
172 | while (matches--)
173 | allocator->Free(retval[matches]);
174 | allocator->Free(retval);
175 | retval = NULL;
176 | break;
177 | } /* if */
178 | strcpy(retval[matches], *i);
179 | matches++;
180 | } /* if */
181 | } /* for */
182 |
183 | if (retval != NULL)
184 | {
185 | assert(totalmatches == matches);
186 | retval[matches] = NULL;
187 | } /* if */
188 | } /* if */
189 |
190 | PHYSFS_freeList(list);
191 | return retval;
192 | } /* PHYSFSEXT_enumerateFilesWildcard */
193 |
194 |
195 | #ifdef TEST_PHYSFSEXT_ENUMERATEFILESWILDCARD
196 | int main(int argc, char **argv)
197 | {
198 | int rc;
199 | char **flist;
200 | char **i;
201 |
202 | if (argc != 3)
203 | {
204 | printf("USAGE: %s \n"
205 | " where is 1 or 0.\n", argv[0]);
206 | return 1;
207 | } /* if */
208 |
209 | if (!PHYSFS_init(argv[0]))
210 | {
211 | fprintf(stderr, "PHYSFS_init(): %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
212 | return 1;
213 | } /* if */
214 |
215 | if (!PHYSFS_addToSearchPath(".", 1))
216 | {
217 | fprintf(stderr, "PHYSFS_addToSearchPath(): %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
218 | PHYSFS_deinit();
219 | return 1;
220 | } /* if */
221 |
222 | flist = PHYSFSEXT_enumerateFilesWildcard("/", argv[1], atoi(argv[2]));
223 | rc = 0;
224 | for (i = flist; *i; i++)
225 | {
226 | printf("%s\n", *i);
227 | rc++;
228 | } /* for */
229 | printf("\n total %d files.\n\n", rc);
230 |
231 | PHYSFSEXT_freeEnumeration(flist);
232 | PHYSFS_deinit();
233 |
234 | return 0;
235 | } /* main */
236 | #endif
237 |
238 | /* end of globbing.c ... */
239 |
240 |
--------------------------------------------------------------------------------
/physfs/extras/physfsrwops.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This code provides a glue layer between PhysicsFS and Simple Directmedia
3 | * Layer's (SDL) RWops i/o abstraction.
4 | *
5 | * License: this code is public domain. I make no warranty that it is useful,
6 | * correct, harmless, or environmentally safe.
7 | *
8 | * This particular file may be used however you like, including copying it
9 | * verbatim into a closed-source project, exploiting it commercially, and
10 | * removing any trace of my name from the source (although I hope you won't
11 | * do that). I welcome enhancements and corrections to this file, but I do
12 | * not require you to send me patches if you make changes. This code has
13 | * NO WARRANTY.
14 | *
15 | * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
16 | * Please see LICENSE.txt in the root of the source tree.
17 | *
18 | * SDL 1.2 falls under the LGPL license. SDL 1.3+ is zlib, like PhysicsFS.
19 | * You can get SDL at https://www.libsdl.org/
20 | *
21 | * This file was written by Ryan C. Gordon. (icculus@icculus.org).
22 | */
23 |
24 | #include /* used for SEEK_SET, SEEK_CUR, SEEK_END ... */
25 | #include "physfsrwops.h"
26 |
27 | /* SDL's RWOPS interface changed a little in SDL 2.0... */
28 | #if defined(SDL_VERSION_ATLEAST)
29 | #if SDL_VERSION_ATLEAST(2, 0, 0)
30 | #define TARGET_SDL2 1
31 | #endif
32 | #endif
33 |
34 | #if !TARGET_SDL2
35 | #ifndef RW_SEEK_SET
36 | #define RW_SEEK_SET SEEK_SET
37 | #endif
38 | #ifndef RW_SEEK_CUR
39 | #define RW_SEEK_CUR SEEK_CUR
40 | #endif
41 | #ifndef RW_SEEK_END
42 | #define RW_SEEK_END SEEK_END
43 | #endif
44 | #endif
45 |
46 | #if TARGET_SDL2
47 | static Sint64 SDLCALL physfsrwops_size(struct SDL_RWops *rw)
48 | {
49 | PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
50 | return (Sint64) PHYSFS_fileLength(handle);
51 | } /* physfsrwops_size */
52 | #endif
53 |
54 |
55 | #if TARGET_SDL2
56 | static Sint64 SDLCALL physfsrwops_seek(struct SDL_RWops *rw, Sint64 offset, int whence)
57 | #else
58 | static int physfsrwops_seek(SDL_RWops *rw, int offset, int whence)
59 | #endif
60 | {
61 | PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
62 | PHYSFS_sint64 pos = 0;
63 |
64 | if (whence == RW_SEEK_SET)
65 | pos = (PHYSFS_sint64) offset;
66 |
67 | else if (whence == RW_SEEK_CUR)
68 | {
69 | const PHYSFS_sint64 current = PHYSFS_tell(handle);
70 | if (current == -1)
71 | {
72 | SDL_SetError("Can't find position in file: %s",
73 | PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
74 | return -1;
75 | } /* if */
76 |
77 | if (offset == 0) /* this is a "tell" call. We're done. */
78 | {
79 | #if TARGET_SDL2
80 | return (Sint64) current;
81 | #else
82 | return (int) current;
83 | #endif
84 | } /* if */
85 |
86 | pos = current + ((PHYSFS_sint64) offset);
87 | } /* else if */
88 |
89 | else if (whence == RW_SEEK_END)
90 | {
91 | const PHYSFS_sint64 len = PHYSFS_fileLength(handle);
92 | if (len == -1)
93 | {
94 | SDL_SetError("Can't find end of file: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
95 | return -1;
96 | } /* if */
97 |
98 | pos = len + ((PHYSFS_sint64) offset);
99 | } /* else if */
100 |
101 | else
102 | {
103 | SDL_SetError("Invalid 'whence' parameter.");
104 | return -1;
105 | } /* else */
106 |
107 | if ( pos < 0 )
108 | {
109 | SDL_SetError("Attempt to seek past start of file.");
110 | return -1;
111 | } /* if */
112 |
113 | if (!PHYSFS_seek(handle, (PHYSFS_uint64) pos))
114 | {
115 | SDL_SetError("PhysicsFS error: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
116 | return -1;
117 | } /* if */
118 |
119 | #if TARGET_SDL2
120 | return (Sint64) pos;
121 | #else
122 | return (int) pos;
123 | #endif
124 | } /* physfsrwops_seek */
125 |
126 |
127 | #if TARGET_SDL2
128 | static size_t SDLCALL physfsrwops_read(struct SDL_RWops *rw, void *ptr,
129 | size_t size, size_t maxnum)
130 | #else
131 | static int physfsrwops_read(SDL_RWops *rw, void *ptr, int size, int maxnum)
132 | #endif
133 | {
134 | PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
135 | const PHYSFS_uint64 readlen = (PHYSFS_uint64) (maxnum * size);
136 | const PHYSFS_sint64 rc = PHYSFS_readBytes(handle, ptr, readlen);
137 | if (rc != ((PHYSFS_sint64) readlen))
138 | {
139 | if (!PHYSFS_eof(handle)) /* not EOF? Must be an error. */
140 | {
141 | SDL_SetError("PhysicsFS error: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
142 |
143 | #if TARGET_SDL2
144 | return 0;
145 | #else
146 | return -1;
147 | #endif
148 | } /* if */
149 | } /* if */
150 |
151 | #if TARGET_SDL2
152 | return (size_t) rc / size;
153 | #else
154 | return (int) rc / size;
155 | #endif
156 | } /* physfsrwops_read */
157 |
158 |
159 | #if TARGET_SDL2
160 | static size_t SDLCALL physfsrwops_write(struct SDL_RWops *rw, const void *ptr,
161 | size_t size, size_t num)
162 | #else
163 | static int physfsrwops_write(SDL_RWops *rw, const void *ptr, int size, int num)
164 | #endif
165 | {
166 | PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
167 | const PHYSFS_uint64 writelen = (PHYSFS_uint64) (num * size);
168 | const PHYSFS_sint64 rc = PHYSFS_writeBytes(handle, ptr, writelen);
169 | if (rc != ((PHYSFS_sint64) writelen))
170 | SDL_SetError("PhysicsFS error: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
171 |
172 | #if TARGET_SDL2
173 | return (size_t) rc;
174 | #else
175 | return (int) rc;
176 | #endif
177 | } /* physfsrwops_write */
178 |
179 |
180 | static int physfsrwops_close(SDL_RWops *rw)
181 | {
182 | PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
183 | if (!PHYSFS_close(handle))
184 | {
185 | SDL_SetError("PhysicsFS error: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
186 | return -1;
187 | } /* if */
188 |
189 | SDL_FreeRW(rw);
190 | return 0;
191 | } /* physfsrwops_close */
192 |
193 |
194 | static SDL_RWops *create_rwops(PHYSFS_File *handle)
195 | {
196 | SDL_RWops *retval = NULL;
197 |
198 | if (handle == NULL)
199 | SDL_SetError("PhysicsFS error: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
200 | else
201 | {
202 | retval = SDL_AllocRW();
203 | if (retval != NULL)
204 | {
205 | #if TARGET_SDL2
206 | retval->size = physfsrwops_size;
207 | #endif
208 | retval->seek = physfsrwops_seek;
209 | retval->read = physfsrwops_read;
210 | retval->write = physfsrwops_write;
211 | retval->close = physfsrwops_close;
212 | retval->hidden.unknown.data1 = handle;
213 | } /* if */
214 | } /* else */
215 |
216 | return retval;
217 | } /* create_rwops */
218 |
219 |
220 | SDL_RWops *PHYSFSRWOPS_makeRWops(PHYSFS_File *handle)
221 | {
222 | SDL_RWops *retval = NULL;
223 | if (handle == NULL)
224 | SDL_SetError("NULL pointer passed to PHYSFSRWOPS_makeRWops().");
225 | else
226 | retval = create_rwops(handle);
227 |
228 | return retval;
229 | } /* PHYSFSRWOPS_makeRWops */
230 |
231 |
232 | SDL_RWops *PHYSFSRWOPS_openRead(const char *fname)
233 | {
234 | return create_rwops(PHYSFS_openRead(fname));
235 | } /* PHYSFSRWOPS_openRead */
236 |
237 |
238 | SDL_RWops *PHYSFSRWOPS_openWrite(const char *fname)
239 | {
240 | return create_rwops(PHYSFS_openWrite(fname));
241 | } /* PHYSFSRWOPS_openWrite */
242 |
243 |
244 | SDL_RWops *PHYSFSRWOPS_openAppend(const char *fname)
245 | {
246 | return create_rwops(PHYSFS_openAppend(fname));
247 | } /* PHYSFSRWOPS_openAppend */
248 |
249 |
250 | /* end of physfsrwops.c ... */
251 |
252 |
--------------------------------------------------------------------------------
/physfs/src/physfs_archiver_unpacked.c:
--------------------------------------------------------------------------------
1 | /*
2 | * High-level PhysicsFS archiver for simple unpacked file formats.
3 | *
4 | * This is a framework that basic archivers build on top of. It's for simple
5 | * formats that can just hand back a list of files and the offsets of their
6 | * uncompressed data. There are an alarming number of formats like this.
7 | *
8 | * RULES: Archive entries must be uncompressed. Dirs and files allowed, but no
9 | * symlinks, etc. We can relax some of these rules as necessary.
10 | *
11 | * Please see the file LICENSE.txt in the source's root directory.
12 | *
13 | * This file written by Ryan C. Gordon.
14 | */
15 |
16 | #define __PHYSICSFS_INTERNAL__
17 | #include "physfs_internal.h"
18 |
19 | typedef struct
20 | {
21 | __PHYSFS_DirTree tree;
22 | PHYSFS_Io *io;
23 | } UNPKinfo;
24 |
25 | typedef struct
26 | {
27 | __PHYSFS_DirTreeEntry tree;
28 | PHYSFS_uint64 startPos;
29 | PHYSFS_uint64 size;
30 | PHYSFS_sint64 ctime;
31 | PHYSFS_sint64 mtime;
32 | } UNPKentry;
33 |
34 | typedef struct
35 | {
36 | PHYSFS_Io *io;
37 | UNPKentry *entry;
38 | PHYSFS_uint32 curPos;
39 | } UNPKfileinfo;
40 |
41 |
42 | void UNPK_closeArchive(void *opaque)
43 | {
44 | UNPKinfo *info = ((UNPKinfo *) opaque);
45 | if (info)
46 | {
47 | __PHYSFS_DirTreeDeinit(&info->tree);
48 |
49 | if (info->io)
50 | info->io->destroy(info->io);
51 |
52 | allocator.Free(info);
53 | } /* if */
54 | } /* UNPK_closeArchive */
55 |
56 | void UNPK_abandonArchive(void *opaque)
57 | {
58 | UNPKinfo *info = ((UNPKinfo *) opaque);
59 | if (info)
60 | {
61 | info->io = NULL;
62 | UNPK_closeArchive(info);
63 | } /* if */
64 | } /* UNPK_abandonArchive */
65 |
66 | static PHYSFS_sint64 UNPK_read(PHYSFS_Io *io, void *buffer, PHYSFS_uint64 len)
67 | {
68 | UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque;
69 | const UNPKentry *entry = finfo->entry;
70 | const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos);
71 | PHYSFS_sint64 rc;
72 |
73 | if (bytesLeft < len)
74 | len = bytesLeft;
75 |
76 | rc = finfo->io->read(finfo->io, buffer, len);
77 | if (rc > 0)
78 | finfo->curPos += (PHYSFS_uint32) rc;
79 |
80 | return rc;
81 | } /* UNPK_read */
82 |
83 |
84 | static PHYSFS_sint64 UNPK_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
85 | {
86 | BAIL(PHYSFS_ERR_READ_ONLY, -1);
87 | } /* UNPK_write */
88 |
89 |
90 | static PHYSFS_sint64 UNPK_tell(PHYSFS_Io *io)
91 | {
92 | return ((UNPKfileinfo *) io->opaque)->curPos;
93 | } /* UNPK_tell */
94 |
95 |
96 | static int UNPK_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
97 | {
98 | UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque;
99 | const UNPKentry *entry = finfo->entry;
100 | int rc;
101 |
102 | BAIL_IF(offset >= entry->size, PHYSFS_ERR_PAST_EOF, 0);
103 | rc = finfo->io->seek(finfo->io, entry->startPos + offset);
104 | if (rc)
105 | finfo->curPos = (PHYSFS_uint32) offset;
106 |
107 | return rc;
108 | } /* UNPK_seek */
109 |
110 |
111 | static PHYSFS_sint64 UNPK_length(PHYSFS_Io *io)
112 | {
113 | const UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque;
114 | return ((PHYSFS_sint64) finfo->entry->size);
115 | } /* UNPK_length */
116 |
117 |
118 | static PHYSFS_Io *UNPK_duplicate(PHYSFS_Io *_io)
119 | {
120 | UNPKfileinfo *origfinfo = (UNPKfileinfo *) _io->opaque;
121 | PHYSFS_Io *io = NULL;
122 | PHYSFS_Io *retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
123 | UNPKfileinfo *finfo = (UNPKfileinfo *) allocator.Malloc(sizeof (UNPKfileinfo));
124 | GOTO_IF(!retval, PHYSFS_ERR_OUT_OF_MEMORY, UNPK_duplicate_failed);
125 | GOTO_IF(!finfo, PHYSFS_ERR_OUT_OF_MEMORY, UNPK_duplicate_failed);
126 |
127 | io = origfinfo->io->duplicate(origfinfo->io);
128 | if (!io) goto UNPK_duplicate_failed;
129 | finfo->io = io;
130 | finfo->entry = origfinfo->entry;
131 | finfo->curPos = 0;
132 | memcpy(retval, _io, sizeof (PHYSFS_Io));
133 | retval->opaque = finfo;
134 | return retval;
135 |
136 | UNPK_duplicate_failed:
137 | if (finfo != NULL) allocator.Free(finfo);
138 | if (retval != NULL) allocator.Free(retval);
139 | if (io != NULL) io->destroy(io);
140 | return NULL;
141 | } /* UNPK_duplicate */
142 |
143 | static int UNPK_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
144 |
145 | static void UNPK_destroy(PHYSFS_Io *io)
146 | {
147 | UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque;
148 | finfo->io->destroy(finfo->io);
149 | allocator.Free(finfo);
150 | allocator.Free(io);
151 | } /* UNPK_destroy */
152 |
153 |
154 | static const PHYSFS_Io UNPK_Io =
155 | {
156 | CURRENT_PHYSFS_IO_API_VERSION, NULL,
157 | UNPK_read,
158 | UNPK_write,
159 | UNPK_seek,
160 | UNPK_tell,
161 | UNPK_length,
162 | UNPK_duplicate,
163 | UNPK_flush,
164 | UNPK_destroy
165 | };
166 |
167 |
168 | static inline UNPKentry *findEntry(UNPKinfo *info, const char *path)
169 | {
170 | return (UNPKentry *) __PHYSFS_DirTreeFind(&info->tree, path);
171 | } /* findEntry */
172 |
173 |
174 | PHYSFS_Io *UNPK_openRead(void *opaque, const char *name)
175 | {
176 | PHYSFS_Io *retval = NULL;
177 | UNPKinfo *info = (UNPKinfo *) opaque;
178 | UNPKfileinfo *finfo = NULL;
179 | UNPKentry *entry = findEntry(info, name);
180 |
181 | BAIL_IF_ERRPASS(!entry, NULL);
182 | BAIL_IF(entry->tree.isdir, PHYSFS_ERR_NOT_A_FILE, NULL);
183 |
184 | retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
185 | GOTO_IF(!retval, PHYSFS_ERR_OUT_OF_MEMORY, UNPK_openRead_failed);
186 |
187 | finfo = (UNPKfileinfo *) allocator.Malloc(sizeof (UNPKfileinfo));
188 | GOTO_IF(!finfo, PHYSFS_ERR_OUT_OF_MEMORY, UNPK_openRead_failed);
189 |
190 | finfo->io = info->io->duplicate(info->io);
191 | GOTO_IF_ERRPASS(!finfo->io, UNPK_openRead_failed);
192 |
193 | if (!finfo->io->seek(finfo->io, entry->startPos))
194 | goto UNPK_openRead_failed;
195 |
196 | finfo->curPos = 0;
197 | finfo->entry = entry;
198 |
199 | memcpy(retval, &UNPK_Io, sizeof (*retval));
200 | retval->opaque = finfo;
201 | return retval;
202 |
203 | UNPK_openRead_failed:
204 | if (finfo != NULL)
205 | {
206 | if (finfo->io != NULL)
207 | finfo->io->destroy(finfo->io);
208 | allocator.Free(finfo);
209 | } /* if */
210 |
211 | if (retval != NULL)
212 | allocator.Free(retval);
213 |
214 | return NULL;
215 | } /* UNPK_openRead */
216 |
217 |
218 | PHYSFS_Io *UNPK_openWrite(void *opaque, const char *name)
219 | {
220 | BAIL(PHYSFS_ERR_READ_ONLY, NULL);
221 | } /* UNPK_openWrite */
222 |
223 |
224 | PHYSFS_Io *UNPK_openAppend(void *opaque, const char *name)
225 | {
226 | BAIL(PHYSFS_ERR_READ_ONLY, NULL);
227 | } /* UNPK_openAppend */
228 |
229 |
230 | int UNPK_remove(void *opaque, const char *name)
231 | {
232 | BAIL(PHYSFS_ERR_READ_ONLY, 0);
233 | } /* UNPK_remove */
234 |
235 |
236 | int UNPK_mkdir(void *opaque, const char *name)
237 | {
238 | BAIL(PHYSFS_ERR_READ_ONLY, 0);
239 | } /* UNPK_mkdir */
240 |
241 |
242 | int UNPK_stat(void *opaque, const char *path, PHYSFS_Stat *stat)
243 | {
244 | UNPKinfo *info = (UNPKinfo *) opaque;
245 | const UNPKentry *entry = findEntry(info, path);
246 |
247 | BAIL_IF_ERRPASS(!entry, 0);
248 |
249 | if (entry->tree.isdir)
250 | {
251 | stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
252 | stat->filesize = 0;
253 | } /* if */
254 | else
255 | {
256 | stat->filetype = PHYSFS_FILETYPE_REGULAR;
257 | stat->filesize = entry->size;
258 | } /* else */
259 |
260 | stat->modtime = entry->mtime;
261 | stat->createtime = entry->ctime;
262 | stat->accesstime = -1;
263 | stat->readonly = 1;
264 |
265 | return 1;
266 | } /* UNPK_stat */
267 |
268 |
269 | void *UNPK_addEntry(void *opaque, char *name, const int isdir,
270 | const PHYSFS_sint64 ctime, const PHYSFS_sint64 mtime,
271 | const PHYSFS_uint64 pos, const PHYSFS_uint64 len)
272 | {
273 | UNPKinfo *info = (UNPKinfo *) opaque;
274 | UNPKentry *entry;
275 |
276 | entry = (UNPKentry *) __PHYSFS_DirTreeAdd(&info->tree, name, isdir);
277 | BAIL_IF_ERRPASS(!entry, NULL);
278 |
279 | entry->startPos = isdir ? 0 : pos;
280 | entry->size = isdir ? 0 : len;
281 | entry->ctime = ctime;
282 | entry->mtime = mtime;
283 |
284 | return entry;
285 | } /* UNPK_addEntry */
286 |
287 |
288 | void *UNPK_openArchive(PHYSFS_Io *io, const int case_sensitive, const int only_usascii)
289 | {
290 | UNPKinfo *info = (UNPKinfo *) allocator.Malloc(sizeof (UNPKinfo));
291 | BAIL_IF(!info, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
292 |
293 | if (!__PHYSFS_DirTreeInit(&info->tree, sizeof (UNPKentry), case_sensitive, only_usascii))
294 | {
295 | allocator.Free(info);
296 | return NULL;
297 | } /* if */
298 |
299 | info->io = io;
300 |
301 | return info;
302 | } /* UNPK_openArchive */
303 |
304 | /* end of physfs_archiver_unpacked.c ... */
305 |
306 |
--------------------------------------------------------------------------------
/physfs/extras/makecasefoldhashtable.pl:
--------------------------------------------------------------------------------
1 | #!/usr/bin/perl -w
2 |
3 | use warnings;
4 | use strict;
5 |
6 | my $HASHBUCKETS1_16 = 256;
7 | my $HASHBUCKETS1_32 = 16;
8 | my $HASHBUCKETS2_16 = 16;
9 | my $HASHBUCKETS3_16 = 4;
10 |
11 | print <<__EOF__;
12 | /*
13 | * This file is part of PhysicsFS (https://icculus.org/physfs/)
14 | *
15 | * This data generated by physfs/extras/makecasefoldhashtable.pl ...
16 | * Do not manually edit this file!
17 | *
18 | * Please see the file LICENSE.txt in the source's root directory.
19 | */
20 |
21 | #ifndef _INCLUDE_PHYSFS_CASEFOLDING_H_
22 | #define _INCLUDE_PHYSFS_CASEFOLDING_H_
23 |
24 | #ifndef __PHYSICSFS_INTERNAL__
25 | #error Do not include this header from your applications.
26 | #endif
27 |
28 | /* We build three simple hashmaps here: one that maps Unicode codepoints to
29 | a one, two, or three lowercase codepoints. To retrieve this info: look at
30 | case_fold_hashX, where X is 1, 2, or 3. Most foldable codepoints fold to one,
31 | a few dozen fold to two, and a handful fold to three. If the codepoint isn't
32 | in any of these hashes, it doesn't fold (no separate upper and lowercase).
33 |
34 | Almost all these codepoints fit into 16 bits, so we hash them as such to save
35 | memory. If a codepoint is > 0xFFFF, we have separate hashes for them,
36 | since there are (currently) only about 120 of them and (currently) all of them
37 | map to a single lowercase codepoint. */
38 |
39 | typedef struct CaseFoldMapping1_32
40 | {
41 | PHYSFS_uint32 from;
42 | PHYSFS_uint32 to0;
43 | } CaseFoldMapping1_32;
44 |
45 | typedef struct CaseFoldMapping1_16
46 | {
47 | PHYSFS_uint16 from;
48 | PHYSFS_uint16 to0;
49 | } CaseFoldMapping1_16;
50 |
51 | typedef struct CaseFoldMapping2_16
52 | {
53 | PHYSFS_uint16 from;
54 | PHYSFS_uint16 to0;
55 | PHYSFS_uint16 to1;
56 | } CaseFoldMapping2_16;
57 |
58 | typedef struct CaseFoldMapping3_16
59 | {
60 | PHYSFS_uint16 from;
61 | PHYSFS_uint16 to0;
62 | PHYSFS_uint16 to1;
63 | PHYSFS_uint16 to2;
64 | } CaseFoldMapping3_16;
65 |
66 | typedef struct CaseFoldHashBucket1_16
67 | {
68 | const CaseFoldMapping1_16 *list;
69 | const PHYSFS_uint8 count;
70 | } CaseFoldHashBucket1_16;
71 |
72 | typedef struct CaseFoldHashBucket1_32
73 | {
74 | const CaseFoldMapping1_32 *list;
75 | const PHYSFS_uint8 count;
76 | } CaseFoldHashBucket1_32;
77 |
78 | typedef struct CaseFoldHashBucket2_16
79 | {
80 | const CaseFoldMapping2_16 *list;
81 | const PHYSFS_uint8 count;
82 | } CaseFoldHashBucket2_16;
83 |
84 | typedef struct CaseFoldHashBucket3_16
85 | {
86 | const CaseFoldMapping3_16 *list;
87 | const PHYSFS_uint8 count;
88 | } CaseFoldHashBucket3_16;
89 |
90 | __EOF__
91 |
92 |
93 | my @foldPairs1_16;
94 | my @foldPairs2_16;
95 | my @foldPairs3_16;
96 | my @foldPairs1_32;
97 |
98 | for (my $i = 0; $i < $HASHBUCKETS1_16; $i++) {
99 | $foldPairs1_16[$i] = '';
100 | }
101 |
102 | for (my $i = 0; $i < $HASHBUCKETS1_32; $i++) {
103 | $foldPairs1_32[$i] = '';
104 | }
105 |
106 | for (my $i = 0; $i < $HASHBUCKETS2_16; $i++) {
107 | $foldPairs2_16[$i] = '';
108 | }
109 |
110 | for (my $i = 0; $i < $HASHBUCKETS3_16; $i++) {
111 | $foldPairs3_16[$i] = '';
112 | }
113 |
114 | open(FH,'<','casefolding.txt') or die("failed to open casefolding.txt: $!\n");
115 | while () {
116 | chomp;
117 | # strip comments from textfile...
118 | s/\#.*\Z//;
119 |
120 | # strip whitespace...
121 | s/\A\s+//;
122 | s/\s+\Z//;
123 |
124 | next if not /\A([a-fA-F0-9]+)\;\s*(.)\;\s*(.+)\;/;
125 | my ($code, $status, $mapping) = ($1, $2, $3);
126 |
127 | my $hexxed = hex($code);
128 | #print("// code '$code' status '$status' mapping '$mapping'\n");
129 |
130 | if (($status eq 'C') or ($status eq 'F')) {
131 | my ($map1, $map2, $map3) = (undef, undef, undef);
132 | $map1 = $1 if $mapping =~ s/\A([a-fA-F0-9]+)(\s*|\Z)//;
133 | $map2 = $1 if $mapping =~ s/\A([a-fA-F0-9]+)(\s*|\Z)//;
134 | $map3 = $1 if $mapping =~ s/\A([a-fA-F0-9]+)(\s*|\Z)//;
135 | die("mapping space too small for '$code'\n") if ($mapping ne '');
136 | die("problem parsing mapping for '$code'\n") if (not defined($map1));
137 |
138 | if ($hexxed < 128) {
139 | # Just ignore these, we'll handle the low-ASCII ones ourselves.
140 | } elsif ($hexxed > 0xFFFF) {
141 | # We just need to add the 32-bit 2 and/or 3 codepoint maps if this die()'s here.
142 | die("Uhoh, a codepoint > 0xFFFF that folds to multiple codepoints! Fixme.") if defined($map2);
143 | my $hashed = (($hexxed ^ ($hexxed >> 8)) & ($HASHBUCKETS1_32-1));
144 | #print("// hexxed '$hexxed' hashed1 '$hashed'\n");
145 | $foldPairs1_32[$hashed] .= " { 0x$code, 0x$map1 },\n";
146 | } elsif (not defined($map2)) {
147 | my $hashed = (($hexxed ^ ($hexxed >> 8)) & ($HASHBUCKETS1_16-1));
148 | #print("// hexxed '$hexxed' hashed1 '$hashed'\n");
149 | $foldPairs1_16[$hashed] .= " { 0x$code, 0x$map1 },\n";
150 | } elsif (not defined($map3)) {
151 | my $hashed = (($hexxed ^ ($hexxed >> 8)) & ($HASHBUCKETS2_16-1));
152 | #print("// hexxed '$hexxed' hashed2 '$hashed'\n");
153 | $foldPairs2_16[$hashed] .= " { 0x$code, 0x$map1, 0x$map2 },\n";
154 | } else {
155 | my $hashed = (($hexxed ^ ($hexxed >> 8)) & ($HASHBUCKETS3_16-1));
156 | #print("// hexxed '$hexxed' hashed3 '$hashed'\n");
157 | $foldPairs3_16[$hashed] .= " { 0x$code, 0x$map1, 0x$map2, 0x$map3 },\n";
158 | }
159 | }
160 | }
161 | close(FH);
162 |
163 | for (my $i = 0; $i < $HASHBUCKETS1_16; $i++) {
164 | $foldPairs1_16[$i] =~ s/,\n\Z//;
165 | my $str = $foldPairs1_16[$i];
166 | next if $str eq '';
167 | my $num = '000' . $i;
168 | $num =~ s/\A.*?(\d\d\d)\Z/$1/;
169 | my $sym = "case_fold1_16_${num}";
170 | print("static const CaseFoldMapping1_16 ${sym}[] = {\n$str\n};\n\n");
171 | }
172 |
173 | for (my $i = 0; $i < $HASHBUCKETS1_32; $i++) {
174 | $foldPairs1_32[$i] =~ s/,\n\Z//;
175 | my $str = $foldPairs1_32[$i];
176 | next if $str eq '';
177 | my $num = '000' . $i;
178 | $num =~ s/\A.*?(\d\d\d)\Z/$1/;
179 | my $sym = "case_fold1_32_${num}";
180 | print("static const CaseFoldMapping1_32 ${sym}[] = {\n$str\n};\n\n");
181 | }
182 |
183 | for (my $i = 0; $i < $HASHBUCKETS2_16; $i++) {
184 | $foldPairs2_16[$i] =~ s/,\n\Z//;
185 | my $str = $foldPairs2_16[$i];
186 | next if $str eq '';
187 | my $num = '000' . $i;
188 | $num =~ s/\A.*?(\d\d\d)\Z/$1/;
189 | my $sym = "case_fold2_16_${num}";
190 | print("static const CaseFoldMapping2_16 ${sym}[] = {\n$str\n};\n\n");
191 | }
192 |
193 | for (my $i = 0; $i < $HASHBUCKETS3_16; $i++) {
194 | $foldPairs3_16[$i] =~ s/,\n\Z//;
195 | my $str = $foldPairs3_16[$i];
196 | next if $str eq '';
197 | my $num = '000' . $i;
198 | $num =~ s/\A.*?(\d\d\d)\Z/$1/;
199 | my $sym = "case_fold3_16_${num}";
200 | print("static const CaseFoldMapping3_16 ${sym}[] = {\n$str\n};\n\n");
201 | }
202 |
203 | print("static const CaseFoldHashBucket1_16 case_fold_hash1_16[] = {\n");
204 |
205 | for (my $i = 0; $i < $HASHBUCKETS1_16; $i++) {
206 | my $str = $foldPairs1_16[$i];
207 | if ($str eq '') {
208 | print(" { NULL, 0 },\n");
209 | } else {
210 | my $num = '000' . $i;
211 | $num =~ s/\A.*?(\d\d\d)\Z/$1/;
212 | my $sym = "case_fold1_16_${num}";
213 | print(" { $sym, __PHYSFS_ARRAYLEN($sym) },\n");
214 | }
215 | }
216 | print("};\n\n");
217 |
218 |
219 | print("static const CaseFoldHashBucket1_32 case_fold_hash1_32[] = {\n");
220 |
221 | for (my $i = 0; $i < $HASHBUCKETS1_32; $i++) {
222 | my $str = $foldPairs1_32[$i];
223 | if ($str eq '') {
224 | print(" { NULL, 0 },\n");
225 | } else {
226 | my $num = '000' . $i;
227 | $num =~ s/\A.*?(\d\d\d)\Z/$1/;
228 | my $sym = "case_fold1_32_${num}";
229 | print(" { $sym, __PHYSFS_ARRAYLEN($sym) },\n");
230 | }
231 | }
232 | print("};\n\n");
233 |
234 |
235 | print("static const CaseFoldHashBucket2_16 case_fold_hash2_16[] = {\n");
236 |
237 | for (my $i = 0; $i < $HASHBUCKETS2_16; $i++) {
238 | my $str = $foldPairs2_16[$i];
239 | if ($str eq '') {
240 | print(" { NULL, 0 },\n");
241 | } else {
242 | my $num = '000' . $i;
243 | $num =~ s/\A.*?(\d\d\d)\Z/$1/;
244 | my $sym = "case_fold2_16_${num}";
245 | print(" { $sym, __PHYSFS_ARRAYLEN($sym) },\n");
246 | }
247 | }
248 | print("};\n\n");
249 |
250 | print("static const CaseFoldHashBucket3_16 case_fold_hash3_16[] = {\n");
251 |
252 | for (my $i = 0; $i < $HASHBUCKETS3_16; $i++) {
253 | my $str = $foldPairs3_16[$i];
254 | if ($str eq '') {
255 | print(" { NULL, 0 },\n");
256 | } else {
257 | my $num = '000' . $i;
258 | $num =~ s/\A.*?(\d\d\d)\Z/$1/;
259 | my $sym = "case_fold3_16_${num}";
260 | print(" { $sym, __PHYSFS_ARRAYLEN($sym) },\n");
261 | }
262 | }
263 | print("};\n\n");
264 |
265 | print <<__EOF__;
266 |
267 | #endif /* _INCLUDE_PHYSFS_CASEFOLDING_H_ */
268 |
269 | /* end of physfs_casefolding.h ... */
270 |
271 | __EOF__
272 |
273 | exit 0;
274 |
275 | # end of makecashfoldhashtable.pl ...
276 |
277 |
--------------------------------------------------------------------------------
/physfs/src/physfs_platform_unix.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Unix support routines for PhysicsFS.
3 | *
4 | * Please see the file LICENSE.txt in the source's root directory.
5 | *
6 | * This file written by Ryan C. Gordon.
7 | */
8 |
9 | #define __PHYSICSFS_INTERNAL__
10 | #include "physfs_platforms.h"
11 |
12 | #ifdef PHYSFS_PLATFORM_UNIX
13 |
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 |
26 | #if PHYSFS_NO_CDROM_SUPPORT
27 | #elif PHYSFS_PLATFORM_LINUX
28 | # define PHYSFS_HAVE_MNTENT_H 1
29 | #elif defined __CYGWIN__
30 | # define PHYSFS_HAVE_MNTENT_H 1
31 | #elif PHYSFS_PLATFORM_SOLARIS
32 | # define PHYSFS_HAVE_SYS_MNTTAB_H 1
33 | #elif PHYSFS_PLATFORM_BSD
34 | # define PHYSFS_HAVE_SYS_UCRED_H 1
35 | #else
36 | # warning No CD-ROM support included. Either define your platform here,
37 | # warning or define PHYSFS_NO_CDROM_SUPPORT=1 to confirm this is intentional.
38 | #endif
39 |
40 | #ifdef PHYSFS_HAVE_SYS_UCRED_H
41 | # ifdef PHYSFS_HAVE_MNTENT_H
42 | # undef PHYSFS_HAVE_MNTENT_H /* don't do both... */
43 | # endif
44 | # include
45 | # include
46 | #endif
47 |
48 | #ifdef PHYSFS_HAVE_MNTENT_H
49 | #include
50 | #endif
51 |
52 | #ifdef PHYSFS_HAVE_SYS_MNTTAB_H
53 | #include
54 | #endif
55 |
56 | #ifdef PHYSFS_PLATFORM_FREEBSD
57 | #include
58 | #endif
59 |
60 |
61 | #include "physfs_internal.h"
62 |
63 | int __PHYSFS_platformInit(void)
64 | {
65 | return 1; /* always succeed. */
66 | } /* __PHYSFS_platformInit */
67 |
68 |
69 | void __PHYSFS_platformDeinit(void)
70 | {
71 | /* no-op */
72 | } /* __PHYSFS_platformDeinit */
73 |
74 |
75 | void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
76 | {
77 | #if (defined PHYSFS_NO_CDROM_SUPPORT)
78 | /* no-op. */
79 |
80 | #elif (defined PHYSFS_HAVE_SYS_UCRED_H)
81 | int i;
82 | struct statfs *mntbufp = NULL;
83 | int mounts = getmntinfo(&mntbufp, MNT_NOWAIT);
84 |
85 | for (i = 0; i < mounts; i++)
86 | {
87 | int add_it = 0;
88 |
89 | if (strcmp(mntbufp[i].f_fstypename, "iso9660") == 0)
90 | add_it = 1;
91 | else if (strcmp( mntbufp[i].f_fstypename, "cd9660") == 0)
92 | add_it = 1;
93 |
94 | /* add other mount types here */
95 |
96 | if (add_it)
97 | cb(data, mntbufp[i].f_mntonname);
98 | } /* for */
99 |
100 | #elif (defined PHYSFS_HAVE_MNTENT_H)
101 | FILE *mounts = NULL;
102 | struct mntent *ent = NULL;
103 |
104 | mounts = setmntent("/etc/mtab", "r");
105 | BAIL_IF(mounts == NULL, PHYSFS_ERR_IO, /*return void*/);
106 |
107 | while ( (ent = getmntent(mounts)) != NULL )
108 | {
109 | int add_it = 0;
110 | if (strcmp(ent->mnt_type, "iso9660") == 0)
111 | add_it = 1;
112 | else if (strcmp(ent->mnt_type, "udf") == 0)
113 | add_it = 1;
114 |
115 | /* !!! FIXME: these might pick up floppy drives, right? */
116 | else if (strcmp(ent->mnt_type, "auto") == 0)
117 | add_it = 1;
118 | else if (strcmp(ent->mnt_type, "supermount") == 0)
119 | add_it = 1;
120 |
121 | /* add other mount types here */
122 |
123 | if (add_it)
124 | cb(data, ent->mnt_dir);
125 | } /* while */
126 |
127 | endmntent(mounts);
128 |
129 | #elif (defined PHYSFS_HAVE_SYS_MNTTAB_H)
130 | FILE *mounts = fopen(MNTTAB, "r");
131 | struct mnttab ent;
132 |
133 | BAIL_IF(mounts == NULL, PHYSFS_ERR_IO, /*return void*/);
134 | while (getmntent(mounts, &ent) == 0)
135 | {
136 | int add_it = 0;
137 | if (strcmp(ent.mnt_fstype, "hsfs") == 0)
138 | add_it = 1;
139 |
140 | /* add other mount types here */
141 |
142 | if (add_it)
143 | cb(data, ent.mnt_mountp);
144 | } /* while */
145 |
146 | fclose(mounts);
147 | #endif
148 | } /* __PHYSFS_platformDetectAvailableCDs */
149 |
150 |
151 | /*
152 | * See where program (bin) resides in the $PATH specified by (envr).
153 | * returns a copy of the first element in envr that contains it, or NULL
154 | * if it doesn't exist or there were other problems. PHYSFS_SetError() is
155 | * called if we have a problem.
156 | *
157 | * (envr) will be scribbled over, and you are expected to allocator.Free() the
158 | * return value when you're done with it.
159 | */
160 | static char *findBinaryInPath(const char *bin, char *envr)
161 | {
162 | size_t alloc_size = 0;
163 | char *exe = NULL;
164 | char *start = envr;
165 | char *ptr;
166 |
167 | assert(bin != NULL);
168 | assert(envr != NULL);
169 |
170 | do
171 | {
172 | size_t size;
173 | size_t binlen;
174 |
175 | ptr = strchr(start, ':'); /* find next $PATH separator. */
176 | if (ptr)
177 | *ptr = '\0';
178 |
179 | binlen = strlen(bin);
180 | size = strlen(start) + binlen + 2;
181 | if (size >= alloc_size)
182 | {
183 | char *x = (char *) allocator.Realloc(exe, size);
184 | if (!x)
185 | {
186 | if (exe != NULL)
187 | allocator.Free(exe);
188 | BAIL(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
189 | } /* if */
190 |
191 | alloc_size = size;
192 | exe = x;
193 | } /* if */
194 |
195 | /* build full binary path... */
196 | strcpy(exe, start);
197 | if ((exe[0] == '\0') || (exe[strlen(exe) - 1] != '/'))
198 | strcat(exe, "/");
199 | strcat(exe, bin);
200 |
201 | if (access(exe, X_OK) == 0) /* Exists as executable? We're done. */
202 | {
203 | exe[(size - binlen) - 1] = '\0'; /* chop off filename, leave '/' */
204 | return exe;
205 | } /* if */
206 |
207 | start = ptr + 1; /* start points to beginning of next element. */
208 | } while (ptr != NULL);
209 |
210 | if (exe != NULL)
211 | allocator.Free(exe);
212 |
213 | return NULL; /* doesn't exist in path. */
214 | } /* findBinaryInPath */
215 |
216 |
217 | static char *readSymLink(const char *path)
218 | {
219 | ssize_t len = 64;
220 | ssize_t rc = -1;
221 | char *retval = NULL;
222 |
223 | while (1)
224 | {
225 | char *ptr = (char *) allocator.Realloc(retval, (size_t) len);
226 | if (ptr == NULL)
227 | break; /* out of memory. */
228 | retval = ptr;
229 |
230 | rc = readlink(path, retval, len);
231 | if (rc == -1)
232 | break; /* not a symlink, i/o error, etc. */
233 |
234 | else if (rc < len)
235 | {
236 | retval[rc] = '\0'; /* readlink doesn't null-terminate. */
237 | return retval; /* we're good to go. */
238 | } /* else if */
239 |
240 | len *= 2; /* grow buffer, try again. */
241 | } /* while */
242 |
243 | if (retval != NULL)
244 | allocator.Free(retval);
245 | return NULL;
246 | } /* readSymLink */
247 |
248 |
249 | char *__PHYSFS_platformCalcBaseDir(const char *argv0)
250 | {
251 | char *retval = NULL;
252 | const char *envr = NULL;
253 |
254 | /* Try to avoid using argv0 unless forced to. Try system-specific stuff. */
255 |
256 | #if defined(PHYSFS_PLATFORM_FREEBSD)
257 | {
258 | char fullpath[PATH_MAX];
259 | size_t buflen = sizeof (fullpath);
260 | int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
261 | if (sysctl(mib, 4, fullpath, &buflen, NULL, 0) != -1)
262 | retval = __PHYSFS_strdup(fullpath);
263 | }
264 | #endif
265 |
266 | /* If there's a Linux-like /proc filesystem, you can get the full path to
267 | * the current process from a symlink in there.
268 | */
269 |
270 | if (!retval && (access("/proc", F_OK) == 0))
271 | {
272 | retval = readSymLink("/proc/self/exe");
273 | if (!retval) retval = readSymLink("/proc/curproc/file");
274 | if (!retval) retval = readSymLink("/proc/curproc/exe");
275 | if (!retval) retval = readSymLink("/proc/self/path/a.out");
276 | if (retval == NULL)
277 | {
278 | /* older kernels don't have /proc/self ... try PID version... */
279 | const unsigned long long pid = (unsigned long long) getpid();
280 | char path[64];
281 | const int rc = (int) snprintf(path,sizeof(path),"/proc/%llu/exe",pid);
282 | if ( (rc > 0) && (rc < sizeof(path)) )
283 | retval = readSymLink(path);
284 | } /* if */
285 | } /* if */
286 |
287 | #if defined(PHYSFS_PLATFORM_SOLARIS)
288 | if (!retval) /* try getexecname() if /proc didn't pan out. This may not be an absolute path! */
289 | {
290 | const char *path = getexecname();
291 | if ((path != NULL) && (path[0] == '/')) /* must be absolute path... */
292 | retval = __PHYSFS_strdup(path);
293 | } /* if */
294 | #endif
295 |
296 | if (retval != NULL) /* chop off filename. */
297 | {
298 | char *ptr = strrchr(retval, '/');
299 | if (ptr != NULL)
300 | *(ptr+1) = '\0';
301 | else /* shouldn't happen, but just in case... */
302 | {
303 | allocator.Free(retval);
304 | retval = NULL;
305 | } /* else */
306 | } /* if */
307 |
308 | /* No /proc/self/exe, etc, but we have an argv[0] we can parse? */
309 | if ((retval == NULL) && (argv0 != NULL))
310 | {
311 | /* fast path: default behaviour can handle this. */
312 | if (strchr(argv0, '/') != NULL)
313 | return NULL; /* higher level parses out real path from argv0. */
314 |
315 | /* If there's no dirsep on argv0, then look through $PATH for it. */
316 | envr = getenv("PATH");
317 | if (envr != NULL)
318 | {
319 | char *path = (char *) __PHYSFS_smallAlloc(strlen(envr) + 1);
320 | BAIL_IF(!path, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
321 | strcpy(path, envr);
322 | retval = findBinaryInPath(argv0, path);
323 | __PHYSFS_smallFree(path);
324 | } /* if */
325 | } /* if */
326 |
327 | if (retval != NULL)
328 | {
329 | /* try to shrink buffer... */
330 | char *ptr = (char *) allocator.Realloc(retval, strlen(retval) + 1);
331 | if (ptr != NULL)
332 | retval = ptr; /* oh well if it failed. */
333 | } /* if */
334 |
335 | return retval;
336 | } /* __PHYSFS_platformCalcBaseDir */
337 |
338 |
339 | char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
340 | {
341 | /*
342 | * We use XDG's base directory spec, even if you're not on Linux.
343 | * This isn't strictly correct, but the results are relatively sane
344 | * in any case.
345 | *
346 | * https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
347 | */
348 | const char *envr = getenv("XDG_DATA_HOME");
349 | const char *append = "/";
350 | char *retval = NULL;
351 | size_t len = 0;
352 |
353 | if (!envr)
354 | {
355 | /* You end up with "$HOME/.local/share/Game Name 2" */
356 | envr = __PHYSFS_getUserDir();
357 | BAIL_IF_ERRPASS(!envr, NULL); /* oh well. */
358 | append = ".local/share/";
359 | } /* if */
360 |
361 | len = strlen(envr) + strlen(append) + strlen(app) + 2;
362 | retval = (char *) allocator.Malloc(len);
363 | BAIL_IF(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
364 | snprintf(retval, len, "%s%s%s/", envr, append, app);
365 | return retval;
366 | } /* __PHYSFS_platformCalcPrefDir */
367 |
368 | #endif /* PHYSFS_PLATFORM_UNIX */
369 |
370 | /* end of physfs_platform_unix.c ... */
371 |
372 |
--------------------------------------------------------------------------------
/physfs/extras/physfshttpd.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This is a quick and dirty HTTP server that uses PhysicsFS to retrieve
3 | * files. It is not robust at all, probably buggy, and definitely poorly
4 | * designed. It's just meant to show that it can be done.
5 | *
6 | * Basically, you compile this code, and run it:
7 | * ./physfshttpd archive1.zip archive2.zip /path/to/a/real/dir etc...
8 | *
9 | * The files are appended in order to the PhysicsFS search path, and when
10 | * a client request comes in, it looks for the file in said search path.
11 | *
12 | * My goal was to make this work in less than 300 lines of C, so again, it's
13 | * not to be used for any serious purpose. Patches to make this application
14 | * suck less will be readily and gratefully accepted.
15 | *
16 | * Command line I used to build this on Linux:
17 | * gcc -Wall -Werror -g -o bin/physfshttpd extras/physfshttpd.c -lphysfs
18 | *
19 | * License: this code is public domain. I make no warranty that it is useful,
20 | * correct, harmless, or environmentally safe.
21 | *
22 | * This particular file may be used however you like, including copying it
23 | * verbatim into a closed-source project, exploiting it commercially, and
24 | * removing any trace of my name from the source (although I hope you won't
25 | * do that). I welcome enhancements and corrections to this file, but I do
26 | * not require you to send me patches if you make changes. This code has
27 | * NO WARRANTY.
28 | *
29 | * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
30 | * Please see LICENSE.txt in the root of the source tree.
31 | *
32 | * This file was written by Ryan C. Gordon. (icculus@icculus.org).
33 | */
34 |
35 | #include
36 | #include
37 | #include
38 | #include
39 | #include
40 | #include
41 | #include
42 | #include
43 | #include
44 | #include
45 | #include
46 |
47 | #ifndef LACKING_SIGNALS
48 | #include
49 | #endif
50 |
51 | #ifndef LACKING_PROTOENT
52 | #include
53 | #endif
54 |
55 | #include "physfs.h"
56 |
57 |
58 | #define DEFAULT_PORTNUM 8080
59 |
60 | typedef struct
61 | {
62 | int sock;
63 | struct sockaddr *addr;
64 | socklen_t addrlen;
65 | } http_args;
66 |
67 |
68 | #define txt404 \
69 | "HTTP/1.0 404 Not Found\n" \
70 | "Connection: close\n" \
71 | "Content-Type: text/html; charset=utf-8\n" \
72 | "\n" \
73 | "404 Not Found\n" \
74 | "Can't find '%s'.\n\n" \
75 |
76 | #define txt200 \
77 | "HTTP/1.0 200 OK\n" \
78 | "Connection: close\n" \
79 | "Content-Type: %s\n" \
80 | "\n"
81 |
82 | static const char *lastError(void)
83 | {
84 | return PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode());
85 | } /* lastError */
86 |
87 | static int writeAll(const char *ipstr, const int sock, void *buf, const size_t len)
88 | {
89 | if (write(sock, buf, len) != len)
90 | {
91 | printf("%s: Write error to socket.\n", ipstr);
92 | return 0;
93 | } /* if */
94 |
95 | return 1;
96 | } /* writeAll */
97 |
98 | static int writeString(const char *ipstr, const int sock, const char *fmt, ...)
99 | {
100 | /* none of this is robust against large strings or HTML escaping. */
101 | char buffer[1024];
102 | int len;
103 | va_list ap;
104 | va_start(ap, fmt);
105 | len = vsnprintf(buffer, sizeof (buffer), fmt, ap);
106 | va_end(ap);
107 | if (len < 0)
108 | {
109 | printf("uhoh, vsnprintf() failed!\n");
110 | return 0;
111 | } /* if */
112 |
113 | return writeAll(ipstr, sock, buffer, len);
114 | } /* writeString */
115 |
116 |
117 | static void feed_file_http(const char *ipstr, int sock, const char *fname)
118 | {
119 | PHYSFS_File *in = PHYSFS_openRead(fname);
120 |
121 | if (in == NULL)
122 | {
123 | printf("%s: Can't open [%s]: %s.\n", ipstr, fname, lastError());
124 | writeString(ipstr, sock, txt404, fname);
125 | return;
126 | } /* if */
127 |
128 | /* !!! FIXME: mimetype */
129 | if (writeString(ipstr, sock, txt200, "text/plain; charset=utf-8"))
130 | {
131 | do
132 | {
133 | char buffer[1024];
134 | PHYSFS_sint64 br = PHYSFS_readBytes(in, buffer, sizeof (buffer));
135 | if (br == -1)
136 | {
137 | printf("%s: Read error: %s.\n", ipstr, lastError());
138 | break;
139 | } /* if */
140 |
141 | else if (!writeAll(ipstr, sock, buffer, (size_t) br))
142 | {
143 | break;
144 | } /* else if */
145 | } while (!PHYSFS_eof(in));
146 | } /* if */
147 |
148 | PHYSFS_close(in);
149 | } /* feed_file_http */
150 |
151 |
152 | static void feed_dirlist_http(const char *ipstr, int sock,
153 | const char *dname, char **list)
154 | {
155 | int i;
156 |
157 | if (!writeString(ipstr, sock, txt200, "text/html; charset=utf-8"))
158 | return;
159 |
160 | else if (!writeString(ipstr, sock,
161 | "Directory %s"
162 | "Directory %s
\n",
163 | dname, dname))
164 | return;
165 |
166 | if (strcmp(dname, "/") == 0)
167 | dname = "";
168 |
169 | for (i = 0; list[i]; i++)
170 | {
171 | const char *fname = list[i];
172 | if (!writeString(ipstr, sock,
173 | "- %s
\n", dname, fname, fname))
174 | break;
175 | } /* for */
176 |
177 | writeString(ipstr, sock, "
\n");
178 | } /* feed_dirlist_http */
179 |
180 | static void feed_dir_http(const char *ipstr, int sock, const char *dname)
181 | {
182 | char **list = PHYSFS_enumerateFiles(dname);
183 | if (list == NULL)
184 | {
185 | printf("%s: Can't enumerate directory [%s]: %s.\n",
186 | ipstr, dname, lastError());
187 | writeString(ipstr, sock, txt404, dname);
188 | return;
189 | } /* if */
190 |
191 | feed_dirlist_http(ipstr, sock, dname, list);
192 | PHYSFS_freeList(list);
193 | } /* feed_dir_http */
194 |
195 | static void feed_http_request(const char *ipstr, int sock, const char *fname)
196 | {
197 | PHYSFS_Stat statbuf;
198 |
199 | printf("%s: requested [%s].\n", ipstr, fname);
200 |
201 | if (!PHYSFS_stat(fname, &statbuf))
202 | {
203 | printf("%s: Can't stat [%s]: %s.\n", ipstr, fname, lastError());
204 | writeString(ipstr, sock, txt404, fname);
205 | return;
206 | } /* if */
207 |
208 | if (statbuf.filetype == PHYSFS_FILETYPE_DIRECTORY)
209 | feed_dir_http(ipstr, sock, fname);
210 | else
211 | feed_file_http(ipstr, sock, fname);
212 | } /* feed_http_request */
213 |
214 |
215 | static void *do_http(void *_args)
216 | {
217 | http_args *args = (http_args *) _args;
218 | char ipstr[128];
219 | char buffer[512];
220 | char *ptr;
221 | strncpy(ipstr, inet_ntoa(((struct sockaddr_in *) args->addr)->sin_addr),
222 | sizeof (ipstr));
223 | ipstr[sizeof (ipstr) - 1] = '\0';
224 |
225 | printf("%s: connected.\n", ipstr);
226 | read(args->sock, buffer, sizeof (buffer));
227 | buffer[sizeof (buffer) - 1] = '\0';
228 | ptr = strchr(buffer, '\n');
229 | if (!ptr)
230 | printf("%s: potentially bogus request.\n", ipstr);
231 | else
232 | {
233 | *ptr = '\0';
234 | ptr = strchr(buffer, '\r');
235 | if (ptr != NULL)
236 | *ptr = '\0';
237 |
238 | if ((toupper(buffer[0]) == 'G') &&
239 | (toupper(buffer[1]) == 'E') &&
240 | (toupper(buffer[2]) == 'T') &&
241 | (toupper(buffer[3]) == ' ') &&
242 | (toupper(buffer[4]) == '/'))
243 | {
244 | ptr = strchr(buffer + 5, ' ');
245 | if (ptr != NULL)
246 | *ptr = '\0';
247 | feed_http_request(ipstr, args->sock, buffer + 4);
248 | } /* if */
249 | } /* else */
250 |
251 | /* !!! FIXME: Time the transfer. */
252 | printf("%s: closing connection.\n", ipstr);
253 | close(args->sock);
254 | free(args->addr);
255 | free(args);
256 | return NULL;
257 | } /* do_http */
258 |
259 |
260 | static void serve_http_request(int sock, struct sockaddr *addr,
261 | socklen_t addrlen)
262 | {
263 | http_args *args = (http_args *) malloc(sizeof (http_args));
264 | if (args == NULL)
265 | {
266 | printf("out of memory.\n");
267 | return;
268 | } /* if */
269 | args->addr = (struct sockaddr *) malloc(addrlen);
270 | if (args->addr == NULL)
271 | {
272 | free(args);
273 | printf("out of memory.\n");
274 | return;
275 | } /* if */
276 |
277 | args->sock = sock;
278 | args->addrlen = addrlen;
279 | memcpy(args->addr, addr, addrlen);
280 |
281 | /* !!! FIXME: optionally spin a thread... */
282 | do_http((void *) args);
283 | } /* server_http_request */
284 |
285 |
286 | static int create_listen_socket(short portnum)
287 | {
288 | int retval = -1;
289 | int protocol = 0; /* pray this is right. */
290 |
291 | #ifndef LACKING_PROTOENT
292 | struct protoent *prot;
293 | setprotoent(0);
294 | prot = getprotobyname("tcp");
295 | if (prot != NULL)
296 | protocol = prot->p_proto;
297 | #endif
298 |
299 | retval = socket(PF_INET, SOCK_STREAM, protocol);
300 | if (retval >= 0)
301 | {
302 | struct sockaddr_in addr;
303 | addr.sin_family = AF_INET;
304 | addr.sin_port = htons(portnum);
305 | addr.sin_addr.s_addr = INADDR_ANY;
306 | if ((bind(retval, (struct sockaddr *) &addr, (socklen_t) sizeof (addr)) == -1) ||
307 | (listen(retval, 5) == -1))
308 | {
309 | close(retval);
310 | retval = -1;
311 | } /* if */
312 | } /* if */
313 |
314 | return retval;
315 | } /* create_listen_socket */
316 |
317 |
318 | static int listensocket = -1;
319 |
320 | void at_exit_cleanup(void)
321 | {
322 | /*
323 | * !!! FIXME: If thread support, signal threads to terminate and
324 | * !!! FIXME: wait for them to clean up.
325 | */
326 |
327 | if (listensocket >= 0)
328 | close(listensocket);
329 |
330 | if (!PHYSFS_deinit())
331 | printf("PHYSFS_deinit() failed: %s\n", lastError());
332 | } /* at_exit_cleanup */
333 |
334 |
335 | int main(int argc, char **argv)
336 | {
337 | int i;
338 | int portnum = DEFAULT_PORTNUM;
339 |
340 | setbuf(stdout, NULL);
341 | setbuf(stderr, NULL);
342 |
343 | #ifndef LACKING_SIGNALS
344 | /* I'm not sure if this qualifies as a cheap trick... */
345 | signal(SIGTERM, exit);
346 | signal(SIGINT, exit);
347 | signal(SIGFPE, exit);
348 | signal(SIGSEGV, exit);
349 | signal(SIGPIPE, exit);
350 | signal(SIGILL, exit);
351 | #endif
352 |
353 | if (argc == 1)
354 | {
355 | printf("USAGE: %s [archive2 [... archiveN]]\n", argv[0]);
356 | return 42;
357 | } /* if */
358 |
359 | if (!PHYSFS_init(argv[0]))
360 | {
361 | printf("PHYSFS_init() failed: %s\n", lastError());
362 | return 42;
363 | } /* if */
364 |
365 | /* normally, this is bad practice, but oh well. */
366 | atexit(at_exit_cleanup);
367 |
368 | for (i = 1; i < argc; i++)
369 | {
370 | if (!PHYSFS_mount(argv[i], NULL, 1))
371 | printf(" WARNING: failed to add [%s] to search path.\n", argv[i]);
372 | } /* else */
373 |
374 | listensocket = create_listen_socket(portnum);
375 | if (listensocket < 0)
376 | {
377 | printf("listen socket failed to create.\n");
378 | return 42;
379 | } /* if */
380 |
381 | while (1) /* infinite loop for now. */
382 | {
383 | struct sockaddr addr;
384 | socklen_t len;
385 | int s = accept(listensocket, &addr, &len);
386 | if (s < 0)
387 | {
388 | printf("accept() failed: %s\n", strerror(errno));
389 | close(listensocket);
390 | return 42;
391 | } /* if */
392 |
393 | serve_http_request(s, &addr, len);
394 | } /* while */
395 |
396 | return 0;
397 | } /* main */
398 |
399 | /* end of physfshttpd.c ... */
400 |
401 |
--------------------------------------------------------------------------------
/physfs/src/physfs_platform_posix.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Posix-esque support routines for PhysicsFS.
3 | *
4 | * Please see the file LICENSE.txt in the source's root directory.
5 | *
6 | * This file written by Ryan C. Gordon.
7 | */
8 |
9 | #define __PHYSICSFS_INTERNAL__
10 | #include "physfs_platforms.h"
11 |
12 | #ifdef PHYSFS_PLATFORM_POSIX
13 |
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 |
24 | #include "physfs_internal.h"
25 |
26 |
27 | static PHYSFS_ErrorCode errcodeFromErrnoError(const int err)
28 | {
29 | switch (err)
30 | {
31 | case 0: return PHYSFS_ERR_OK;
32 | case EACCES: return PHYSFS_ERR_PERMISSION;
33 | case EPERM: return PHYSFS_ERR_PERMISSION;
34 | case EDQUOT: return PHYSFS_ERR_NO_SPACE;
35 | case EIO: return PHYSFS_ERR_IO;
36 | case ELOOP: return PHYSFS_ERR_SYMLINK_LOOP;
37 | case EMLINK: return PHYSFS_ERR_NO_SPACE;
38 | case ENAMETOOLONG: return PHYSFS_ERR_BAD_FILENAME;
39 | case ENOENT: return PHYSFS_ERR_NOT_FOUND;
40 | case ENOSPC: return PHYSFS_ERR_NO_SPACE;
41 | case ENOTDIR: return PHYSFS_ERR_NOT_FOUND;
42 | case EISDIR: return PHYSFS_ERR_NOT_A_FILE;
43 | case EROFS: return PHYSFS_ERR_READ_ONLY;
44 | case ETXTBSY: return PHYSFS_ERR_BUSY;
45 | case EBUSY: return PHYSFS_ERR_BUSY;
46 | case ENOMEM: return PHYSFS_ERR_OUT_OF_MEMORY;
47 | case ENOTEMPTY: return PHYSFS_ERR_DIR_NOT_EMPTY;
48 | default: return PHYSFS_ERR_OS_ERROR;
49 | } /* switch */
50 | } /* errcodeFromErrnoError */
51 |
52 |
53 | static inline PHYSFS_ErrorCode errcodeFromErrno(void)
54 | {
55 | return errcodeFromErrnoError(errno);
56 | } /* errcodeFromErrno */
57 |
58 |
59 | static char *getUserDirByUID(void)
60 | {
61 | uid_t uid = getuid();
62 | struct passwd *pw;
63 | char *retval = NULL;
64 |
65 | pw = getpwuid(uid);
66 | if ((pw != NULL) && (pw->pw_dir != NULL) && (*pw->pw_dir != '\0'))
67 | {
68 | const size_t dlen = strlen(pw->pw_dir);
69 | const size_t add_dirsep = (pw->pw_dir[dlen-1] != '/') ? 1 : 0;
70 | retval = (char *) allocator.Malloc(dlen + 1 + add_dirsep);
71 | if (retval != NULL)
72 | {
73 | strcpy(retval, pw->pw_dir);
74 | if (add_dirsep)
75 | {
76 | retval[dlen] = '/';
77 | retval[dlen+1] = '\0';
78 | } /* if */
79 | } /* if */
80 | } /* if */
81 |
82 | return retval;
83 | } /* getUserDirByUID */
84 |
85 |
86 | char *__PHYSFS_platformCalcUserDir(void)
87 | {
88 | char *retval = NULL;
89 | char *envr = getenv("HOME");
90 |
91 | /* if the environment variable was set, make sure it's really a dir. */
92 | if (envr != NULL)
93 | {
94 | struct stat statbuf;
95 | if ((stat(envr, &statbuf) != -1) && (S_ISDIR(statbuf.st_mode)))
96 | {
97 | const size_t envrlen = strlen(envr);
98 | const size_t add_dirsep = (envr[envrlen-1] != '/') ? 1 : 0;
99 | retval = allocator.Malloc(envrlen + 1 + add_dirsep);
100 | if (retval)
101 | {
102 | strcpy(retval, envr);
103 | if (add_dirsep)
104 | {
105 | retval[envrlen] = '/';
106 | retval[envrlen+1] = '\0';
107 | } /* if */
108 | } /* if */
109 | } /* if */
110 | } /* if */
111 |
112 | if (retval == NULL)
113 | retval = getUserDirByUID();
114 |
115 | return retval;
116 | } /* __PHYSFS_platformCalcUserDir */
117 |
118 |
119 | PHYSFS_EnumerateCallbackResult __PHYSFS_platformEnumerate(const char *dirname,
120 | PHYSFS_EnumerateCallback callback,
121 | const char *origdir, void *callbackdata)
122 | {
123 | DIR *dir;
124 | struct dirent *ent;
125 | PHYSFS_EnumerateCallbackResult retval = PHYSFS_ENUM_OK;
126 |
127 | dir = opendir(dirname);
128 | BAIL_IF(dir == NULL, errcodeFromErrno(), PHYSFS_ENUM_ERROR);
129 |
130 | while ((retval == PHYSFS_ENUM_OK) && ((ent = readdir(dir)) != NULL))
131 | {
132 | const char *name = ent->d_name;
133 | if (name[0] == '.') /* ignore "." and ".." */
134 | {
135 | if ((name[1] == '\0') || ((name[1] == '.') && (name[2] == '\0')))
136 | continue;
137 | } /* if */
138 |
139 | retval = callback(callbackdata, origdir, name);
140 | if (retval == PHYSFS_ENUM_ERROR)
141 | PHYSFS_setErrorCode(PHYSFS_ERR_APP_CALLBACK);
142 | } /* while */
143 |
144 | closedir(dir);
145 |
146 | return retval;
147 | } /* __PHYSFS_platformEnumerate */
148 |
149 |
150 | int __PHYSFS_platformMkDir(const char *path)
151 | {
152 | const int rc = mkdir(path, S_IRWXU);
153 | BAIL_IF(rc == -1, errcodeFromErrno(), 0);
154 | return 1;
155 | } /* __PHYSFS_platformMkDir */
156 |
157 |
158 | #if !defined(O_CLOEXEC) && defined(FD_CLOEXEC)
159 | static inline void set_CLOEXEC(int fildes)
160 | {
161 | int flags = fcntl(fildes, F_GETFD);
162 | if (flags != -1) {
163 | fcntl(fildes, F_SETFD, flags | FD_CLOEXEC);
164 | }
165 | }
166 | #endif
167 |
168 | static void *doOpen(const char *filename, int mode)
169 | {
170 | const int appending = (mode & O_APPEND);
171 | int fd;
172 | int *retval;
173 |
174 | errno = 0;
175 |
176 | /* O_APPEND doesn't actually behave as we'd like. */
177 | mode &= ~O_APPEND;
178 |
179 | #ifdef O_CLOEXEC
180 | /* Add O_CLOEXEC if defined */
181 | mode |= O_CLOEXEC;
182 | #endif
183 |
184 | do {
185 | fd = open(filename, mode, S_IRUSR | S_IWUSR);
186 | } while ((fd < 0) && (errno == EINTR));
187 | BAIL_IF(fd < 0, errcodeFromErrno(), NULL);
188 |
189 | #if !defined(O_CLOEXEC) && defined(FD_CLOEXEC)
190 | set_CLOEXEC(fd);
191 | #endif
192 |
193 | if (appending)
194 | {
195 | if (lseek(fd, 0, SEEK_END) < 0)
196 | {
197 | const int err = errno;
198 | close(fd);
199 | BAIL(errcodeFromErrnoError(err), NULL);
200 | } /* if */
201 | } /* if */
202 |
203 | retval = (int *) allocator.Malloc(sizeof (int));
204 | if (!retval)
205 | {
206 | close(fd);
207 | BAIL(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
208 | } /* if */
209 |
210 | *retval = fd;
211 | return ((void *) retval);
212 | } /* doOpen */
213 |
214 |
215 | void *__PHYSFS_platformOpenRead(const char *filename)
216 | {
217 | return doOpen(filename, O_RDONLY);
218 | } /* __PHYSFS_platformOpenRead */
219 |
220 |
221 | void *__PHYSFS_platformOpenWrite(const char *filename)
222 | {
223 | return doOpen(filename, O_WRONLY | O_CREAT | O_TRUNC);
224 | } /* __PHYSFS_platformOpenWrite */
225 |
226 |
227 | void *__PHYSFS_platformOpenAppend(const char *filename)
228 | {
229 | return doOpen(filename, O_WRONLY | O_CREAT | O_APPEND);
230 | } /* __PHYSFS_platformOpenAppend */
231 |
232 |
233 | PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
234 | PHYSFS_uint64 len)
235 | {
236 | const int fd = *((int *) opaque);
237 | ssize_t rc = 0;
238 |
239 | if (!__PHYSFS_ui64FitsAddressSpace(len))
240 | BAIL(PHYSFS_ERR_INVALID_ARGUMENT, -1);
241 |
242 | do {
243 | rc = read(fd, buffer, (size_t) len);
244 | } while ((rc == -1) && (errno == EINTR));
245 | BAIL_IF(rc == -1, errcodeFromErrno(), -1);
246 | assert(rc >= 0);
247 | assert(rc <= len);
248 | return (PHYSFS_sint64) rc;
249 | } /* __PHYSFS_platformRead */
250 |
251 |
252 | PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
253 | PHYSFS_uint64 len)
254 | {
255 | const int fd = *((int *) opaque);
256 | ssize_t rc = 0;
257 |
258 | if (!__PHYSFS_ui64FitsAddressSpace(len))
259 | BAIL(PHYSFS_ERR_INVALID_ARGUMENT, -1);
260 |
261 | do {
262 | rc = write(fd, (void *) buffer, (size_t) len);
263 | } while ((rc == -1) && (errno == EINTR));
264 | BAIL_IF(rc == -1, errcodeFromErrno(), rc);
265 | assert(rc >= 0);
266 | assert(rc <= len);
267 | return (PHYSFS_sint64) rc;
268 | } /* __PHYSFS_platformWrite */
269 |
270 |
271 | int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos)
272 | {
273 | const int fd = *((int *) opaque);
274 | const off_t rc = lseek(fd, (off_t) pos, SEEK_SET);
275 | BAIL_IF(rc == -1, errcodeFromErrno(), 0);
276 | return 1;
277 | } /* __PHYSFS_platformSeek */
278 |
279 |
280 | PHYSFS_sint64 __PHYSFS_platformTell(void *opaque)
281 | {
282 | const int fd = *((int *) opaque);
283 | PHYSFS_sint64 retval;
284 | retval = (PHYSFS_sint64) lseek(fd, 0, SEEK_CUR);
285 | BAIL_IF(retval == -1, errcodeFromErrno(), -1);
286 | return retval;
287 | } /* __PHYSFS_platformTell */
288 |
289 |
290 | PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
291 | {
292 | const int fd = *((int *) opaque);
293 | struct stat statbuf;
294 | BAIL_IF(fstat(fd, &statbuf) == -1, errcodeFromErrno(), -1);
295 | return ((PHYSFS_sint64) statbuf.st_size);
296 | } /* __PHYSFS_platformFileLength */
297 |
298 |
299 | int __PHYSFS_platformFlush(void *opaque)
300 | {
301 | const int fd = *((int *) opaque);
302 | int rc = -1;
303 | if ((fcntl(fd, F_GETFL) & O_ACCMODE) != O_RDONLY) {
304 | do {
305 | rc = fsync(fd);
306 | } while ((rc == -1) && (errno == EINTR));
307 | BAIL_IF(rc == -1, errcodeFromErrno(), 0);
308 | }
309 | return 1;
310 | } /* __PHYSFS_platformFlush */
311 |
312 |
313 | void __PHYSFS_platformClose(void *opaque)
314 | {
315 | const int fd = *((int *) opaque);
316 | int rc = -1;
317 | do {
318 | rc = close(fd); /* we don't check this. You should have used flush! */
319 | } while ((rc == -1) && (errno == EINTR));
320 | allocator.Free(opaque);
321 | } /* __PHYSFS_platformClose */
322 |
323 |
324 | int __PHYSFS_platformDelete(const char *path)
325 | {
326 | BAIL_IF(remove(path) == -1, errcodeFromErrno(), 0);
327 | return 1;
328 | } /* __PHYSFS_platformDelete */
329 |
330 |
331 | int __PHYSFS_platformStat(const char *fname, PHYSFS_Stat *st, const int follow)
332 | {
333 | struct stat statbuf;
334 | const int rc = follow ? stat(fname, &statbuf) : lstat(fname, &statbuf);
335 | BAIL_IF(rc == -1, errcodeFromErrno(), 0);
336 |
337 | if (S_ISREG(statbuf.st_mode))
338 | {
339 | st->filetype = PHYSFS_FILETYPE_REGULAR;
340 | st->filesize = statbuf.st_size;
341 | } /* if */
342 |
343 | else if(S_ISDIR(statbuf.st_mode))
344 | {
345 | st->filetype = PHYSFS_FILETYPE_DIRECTORY;
346 | st->filesize = 0;
347 | } /* else if */
348 |
349 | else if(S_ISLNK(statbuf.st_mode))
350 | {
351 | st->filetype = PHYSFS_FILETYPE_SYMLINK;
352 | st->filesize = 0;
353 | } /* else if */
354 |
355 | else
356 | {
357 | st->filetype = PHYSFS_FILETYPE_OTHER;
358 | st->filesize = statbuf.st_size;
359 | } /* else */
360 |
361 | st->modtime = statbuf.st_mtime;
362 | st->createtime = statbuf.st_ctime;
363 | st->accesstime = statbuf.st_atime;
364 |
365 | st->readonly = (access(fname, W_OK) == -1);
366 | return 1;
367 | } /* __PHYSFS_platformStat */
368 |
369 |
370 | typedef struct
371 | {
372 | pthread_mutex_t mutex;
373 | pthread_t owner;
374 | PHYSFS_uint32 count;
375 | } PthreadMutex;
376 |
377 |
378 | void *__PHYSFS_platformGetThreadID(void)
379 | {
380 | return ( (void *) ((size_t) pthread_self()) );
381 | } /* __PHYSFS_platformGetThreadID */
382 |
383 |
384 | void *__PHYSFS_platformCreateMutex(void)
385 | {
386 | int rc;
387 | PthreadMutex *m = (PthreadMutex *) allocator.Malloc(sizeof (PthreadMutex));
388 | BAIL_IF(!m, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
389 | rc = pthread_mutex_init(&m->mutex, NULL);
390 | if (rc != 0)
391 | {
392 | allocator.Free(m);
393 | BAIL(PHYSFS_ERR_OS_ERROR, NULL);
394 | } /* if */
395 |
396 | m->count = 0;
397 | m->owner = (pthread_t) 0xDEADBEEF;
398 | return ((void *) m);
399 | } /* __PHYSFS_platformCreateMutex */
400 |
401 |
402 | void __PHYSFS_platformDestroyMutex(void *mutex)
403 | {
404 | PthreadMutex *m = (PthreadMutex *) mutex;
405 |
406 | /* Destroying a locked mutex is a bug, but we'll try to be helpful. */
407 | if ((m->owner == pthread_self()) && (m->count > 0))
408 | pthread_mutex_unlock(&m->mutex);
409 |
410 | pthread_mutex_destroy(&m->mutex);
411 | allocator.Free(m);
412 | } /* __PHYSFS_platformDestroyMutex */
413 |
414 |
415 | int __PHYSFS_platformGrabMutex(void *mutex)
416 | {
417 | PthreadMutex *m = (PthreadMutex *) mutex;
418 | pthread_t tid = pthread_self();
419 | if (m->owner != tid)
420 | {
421 | if (pthread_mutex_lock(&m->mutex) != 0)
422 | return 0;
423 | m->owner = tid;
424 | } /* if */
425 |
426 | m->count++;
427 | return 1;
428 | } /* __PHYSFS_platformGrabMutex */
429 |
430 |
431 | void __PHYSFS_platformReleaseMutex(void *mutex)
432 | {
433 | PthreadMutex *m = (PthreadMutex *) mutex;
434 | assert(m->owner == pthread_self()); /* catch programming errors. */
435 | assert(m->count > 0); /* catch programming errors. */
436 | if (m->owner == pthread_self())
437 | {
438 | if (--m->count == 0)
439 | {
440 | m->owner = (pthread_t) 0xDEADBEEF;
441 | pthread_mutex_unlock(&m->mutex);
442 | } /* if */
443 | } /* if */
444 | } /* __PHYSFS_platformReleaseMutex */
445 |
446 | #endif /* PHYSFS_PLATFORM_POSIX */
447 |
448 | /* end of physfs_platform_posix.c ... */
449 |
450 |
--------------------------------------------------------------------------------