├── .github
├── FUNDING.yml
└── workflows
│ └── main.yml
├── .gitignore
├── CMakeLists.txt
├── LICENSE.txt
├── README.txt
├── docs
├── CHANGELOG.txt
├── CREDITS.txt
├── Doxyfile
├── INSTALL.txt
├── README-API-documentation.txt
└── TODO.txt
├── extras
├── README-CSharp.txt
├── abs-file.h
├── buildbot-checker.sh
├── buildbot-emscripten.sh
├── buildbot-os2.sh
├── buildbot-raspberrypi.sh
├── casefolding.txt
├── globbing.c
├── globbing.h
├── ignorecase.c
├── ignorecase.h
├── makecasefoldhashtable.pl
├── physfs.pc.in
├── physfshttpd.c
├── physfsrwops.c
├── physfsrwops.h
├── physfsunpack.c
├── selfextract.c
└── uninstall.sh
├── src
├── physfs.c
├── physfs.h
├── physfs_archiver_7z.c
├── physfs_archiver_dir.c
├── physfs_archiver_grp.c
├── physfs_archiver_hog.c
├── physfs_archiver_iso9660.c
├── physfs_archiver_mvl.c
├── physfs_archiver_qpak.c
├── physfs_archiver_slb.c
├── physfs_archiver_unpacked.c
├── physfs_archiver_vdf.c
├── physfs_archiver_wad.c
├── physfs_archiver_zip.c
├── physfs_byteorder.c
├── physfs_casefolding.h
├── physfs_internal.h
├── physfs_lzmasdk.h
├── physfs_miniz.h
├── physfs_platform_android.c
├── physfs_platform_apple.m
├── physfs_platform_haiku.cpp
├── physfs_platform_os2.c
├── physfs_platform_posix.c
├── physfs_platform_qnx.c
├── physfs_platform_unix.c
├── physfs_platform_windows.c
├── physfs_platform_winrt.cpp
├── physfs_platforms.h
└── physfs_unicode.c
└── test
└── test_physfs.c
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: [icculus]
2 | patreon: icculus
3 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | Build:
7 | name: ${{ matrix.platform.name }}
8 | runs-on: ${{ matrix.platform.os }}
9 | strategy:
10 | matrix:
11 | platform: # !!! FIXME: figure out an efficient way to get SDL2 on the Windows/Mac bots.
12 | - { name: Linux, os: ubuntu-20.04, flags: -GNinja }
13 | - { name: Windows, os: windows-latest }
14 | - { name: MacOS, os: macos-latest }
15 | steps:
16 | - name: Setup Linux dependencies
17 | if: runner.os == 'Linux'
18 | run: |
19 | sudo apt-get update
20 | sudo apt-get install cmake ninja-build
21 | - name: Get PhysicsFS sources
22 | uses: actions/checkout@v2
23 | - name: Configure CMake
24 | run: cmake -B build ${{ matrix.platform.flags }}
25 | - name: Build
26 | run: cmake --build build/
27 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | cmake-build
2 |
3 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # PhysicsFS; a portable, flexible file i/o abstraction.
2 | #
3 | # Please see the file LICENSE.txt in the source's root directory.
4 |
5 | # The CMake project file is meant to get this compiling on all sorts of
6 | # platforms quickly, and serve as the way Unix platforms and Linux distros
7 | # package up official builds, but you don't _need_ to use this; we have
8 | # built PhysicsFS to (hopefully) be able to drop into your project and
9 | # compile, using preprocessor checks for platform-specific bits instead of
10 | # testing in here.
11 |
12 | cmake_minimum_required(VERSION 2.8.12)
13 |
14 | project(PhysicsFS)
15 | set(PHYSFS_VERSION 3.1.0)
16 |
17 | # Increment this if/when we break backwards compatibility.
18 | set(PHYSFS_SOVERSION 1)
19 |
20 | # I hate that they define "WIN32" ... we're about to move to Win64...I hope!
21 | if(WIN32 AND NOT WINDOWS)
22 | set(WINDOWS TRUE)
23 | endif()
24 |
25 | include_directories(./src)
26 |
27 | if(APPLE)
28 | set(OTHER_LDFLAGS ${OTHER_LDFLAGS} "-framework IOKit -framework Foundation")
29 | set(PHYSFS_M_SRCS src/physfs_platform_apple.m)
30 | endif()
31 |
32 | if(CMAKE_COMPILER_IS_GNUCC)
33 | # Don't use -rpath.
34 | set(CMAKE_SKIP_RPATH ON CACHE BOOL "Skip RPATH" FORCE)
35 | endif()
36 |
37 | if(CMAKE_C_COMPILER_ID STREQUAL "SunPro")
38 | add_definitions(-erroff=E_EMPTY_TRANSLATION_UNIT)
39 | add_definitions(-xldscope=hidden)
40 | endif()
41 |
42 | if(HAIKU)
43 | # We add this explicitly, since we don't want CMake to think this
44 | # is a C++ project unless we're on Haiku.
45 | set(PHYSFS_CPP_SRCS src/physfs_platform_haiku.cpp)
46 | find_library(BE_LIBRARY be)
47 | find_library(ROOT_LIBRARY root)
48 | set(OPTIONAL_LIBRARY_LIBS ${OPTIONAL_LIBRARY_LIBS} ${BE_LIBRARY} ${ROOT_LIBRARY})
49 | endif()
50 |
51 | if(CMAKE_SYSTEM_NAME STREQUAL "WindowsPhone" OR CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
52 | set(WINRT TRUE)
53 | endif()
54 |
55 | if(WINRT)
56 | set(PHYSFS_CPP_SRCS src/physfs_platform_winrt.cpp)
57 | endif()
58 |
59 | if(UNIX AND NOT WINDOWS AND NOT APPLE) # (MingW and such might be UNIX _and_ WINDOWS!)
60 | find_library(PTHREAD_LIBRARY pthread)
61 | if(PTHREAD_LIBRARY)
62 | set(OPTIONAL_LIBRARY_LIBS ${OPTIONAL_LIBRARY_LIBS} ${PTHREAD_LIBRARY})
63 | endif()
64 | endif()
65 |
66 | # Almost everything is "compiled" here, but things that don't apply to the
67 | # build are #ifdef'd out. This is to make it easy to embed PhysicsFS into
68 | # another project or bring up a new build system: just compile all the source
69 | # code and #define the things you want.
70 | set(PHYSFS_SRCS
71 | src/physfs.c
72 | src/physfs_byteorder.c
73 | src/physfs_unicode.c
74 | src/physfs_platform_posix.c
75 | src/physfs_platform_unix.c
76 | src/physfs_platform_windows.c
77 | src/physfs_platform_os2.c
78 | src/physfs_platform_qnx.c
79 | src/physfs_platform_android.c
80 | src/physfs_archiver_dir.c
81 | src/physfs_archiver_unpacked.c
82 | src/physfs_archiver_grp.c
83 | src/physfs_archiver_hog.c
84 | src/physfs_archiver_7z.c
85 | src/physfs_archiver_mvl.c
86 | src/physfs_archiver_qpak.c
87 | src/physfs_archiver_wad.c
88 | src/physfs_archiver_zip.c
89 | src/physfs_archiver_slb.c
90 | src/physfs_archiver_iso9660.c
91 | src/physfs_archiver_vdf.c
92 | ${PHYSFS_CPP_SRCS}
93 | ${PHYSFS_M_SRCS}
94 | )
95 |
96 |
97 | # Archivers ...
98 | # These are (mostly) on by default now, so these options are only useful for
99 | # disabling them.
100 |
101 | option(PHYSFS_ARCHIVE_ZIP "Enable ZIP support" TRUE)
102 | if(NOT PHYSFS_ARCHIVE_ZIP)
103 | add_definitions(-DPHYSFS_SUPPORTS_ZIP=0)
104 | endif()
105 |
106 | option(PHYSFS_ARCHIVE_7Z "Enable 7zip support" TRUE)
107 | if(NOT PHYSFS_ARCHIVE_7Z)
108 | add_definitions(-DPHYSFS_SUPPORTS_7Z=0)
109 | endif()
110 |
111 | option(PHYSFS_ARCHIVE_GRP "Enable Build Engine GRP support" TRUE)
112 | if(NOT PHYSFS_ARCHIVE_GRP)
113 | add_definitions(-DPHYSFS_SUPPORTS_GRP=0)
114 | endif()
115 |
116 | option(PHYSFS_ARCHIVE_WAD "Enable Doom WAD support" TRUE)
117 | if(NOT PHYSFS_ARCHIVE_WAD)
118 | add_definitions(-DPHYSFS_SUPPORTS_WAD=0)
119 | endif()
120 |
121 | option(PHYSFS_ARCHIVE_HOG "Enable Descent I/II HOG support" TRUE)
122 | if(NOT PHYSFS_ARCHIVE_HOG)
123 | add_definitions(-DPHYSFS_SUPPORTS_HOG=0)
124 | endif()
125 |
126 | option(PHYSFS_ARCHIVE_MVL "Enable Descent I/II MVL support" TRUE)
127 | if(NOT PHYSFS_ARCHIVE_MVL)
128 | add_definitions(-DPHYSFS_SUPPORTS_MVL=0)
129 | endif()
130 |
131 | option(PHYSFS_ARCHIVE_QPAK "Enable Quake I/II QPAK support" TRUE)
132 | if(NOT PHYSFS_ARCHIVE_QPAK)
133 | add_definitions(-DPHYSFS_SUPPORTS_QPAK=0)
134 | endif()
135 |
136 | option(PHYSFS_ARCHIVE_SLB "Enable I-War / Independence War SLB support" TRUE)
137 | if(NOT PHYSFS_ARCHIVE_SLB)
138 | add_definitions(-DPHYSFS_SUPPORTS_SLB=0)
139 | endif()
140 |
141 | option(PHYSFS_ARCHIVE_ISO9660 "Enable ISO9660 support" TRUE)
142 | if(NOT PHYSFS_ARCHIVE_ISO9660)
143 | add_definitions(-DPHYSFS_SUPPORTS_ISO9660=0)
144 | endif()
145 |
146 | option(PHYSFS_ARCHIVE_VDF "Enable Gothic I/II VDF archive support" TRUE)
147 | if(NOT PHYSFS_ARCHIVE_VDF)
148 | add_definitions(-DPHYSFS_SUPPORTS_VDF=0)
149 | endif()
150 |
151 |
152 | option(PHYSFS_BUILD_STATIC "Build static library" TRUE)
153 | if(PHYSFS_BUILD_STATIC)
154 | add_library(physfs-static STATIC ${PHYSFS_SRCS})
155 | # Don't rename this on Windows, since DLLs will also produce an import
156 | # library named "physfs.lib" which would conflict; Unix tend to like the
157 | # same library name with a different extension for static libs, but
158 | # Windows can just have a separate name.
159 | if(NOT MSVC)
160 | set_target_properties(physfs-static PROPERTIES OUTPUT_NAME "physfs")
161 | endif()
162 | if(WINRT)
163 | # Ignore LNK4264 warnings; we don't author any WinRT components, just consume them, so we're okay in a static library.
164 | set_target_properties(physfs-static PROPERTIES VS_WINRT_COMPONENT True)
165 | set_target_properties(physfs-static PROPERTIES STATIC_LIBRARY_FLAGS "/ignore:4264")
166 | endif()
167 |
168 | set(PHYSFS_LIB_TARGET physfs-static)
169 | set(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";physfs-static")
170 | endif()
171 |
172 | option(PHYSFS_BUILD_SHARED "Build shared library" TRUE)
173 | if(PHYSFS_BUILD_SHARED)
174 | add_library(physfs SHARED ${PHYSFS_SRCS})
175 | set_target_properties(physfs PROPERTIES MACOSX_RPATH 1)
176 | set_target_properties(physfs PROPERTIES VERSION ${PHYSFS_VERSION})
177 | set_target_properties(physfs PROPERTIES SOVERSION ${PHYSFS_SOVERSION})
178 | if(WINRT)
179 | set_target_properties(physfs PROPERTIES VS_WINRT_COMPONENT True)
180 | endif()
181 | target_link_libraries(physfs ${OPTIONAL_LIBRARY_LIBS} ${OTHER_LDFLAGS})
182 | set(PHYSFS_LIB_TARGET physfs)
183 | set(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";physfs")
184 | endif()
185 |
186 | if(NOT PHYSFS_BUILD_SHARED AND NOT PHYSFS_BUILD_STATIC)
187 | message(FATAL "Both shared and static libraries are disabled!")
188 | endif()
189 |
190 | # CMake FAQ says I need this...
191 | if(PHYSFS_BUILD_SHARED AND PHYSFS_BUILD_STATIC AND NOT WINDOWS)
192 | set_target_properties(physfs PROPERTIES CLEAN_DIRECT_OUTPUT 1)
193 | set_target_properties(physfs-static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
194 | endif()
195 |
196 | option(PHYSFS_BUILD_TEST "Build stdio test program." TRUE)
197 | mark_as_advanced(PHYSFS_BUILD_TEST)
198 | if(PHYSFS_BUILD_TEST)
199 | find_path(READLINE_H readline/readline.h)
200 | find_path(HISTORY_H readline/history.h)
201 | if(READLINE_H AND HISTORY_H)
202 | find_library(CURSES_LIBRARY NAMES curses ncurses)
203 | set(CMAKE_REQUIRED_LIBRARIES ${CURSES_LIBRARY})
204 | find_library(READLINE_LIBRARY readline)
205 | if(READLINE_LIBRARY)
206 | set(HAVE_SYSTEM_READLINE TRUE)
207 | set(TEST_PHYSFS_LIBS ${TEST_PHYSFS_LIBS} ${READLINE_LIBRARY} ${CURSES_LIBRARY})
208 | include_directories(SYSTEM ${READLINE_H} ${HISTORY_H})
209 | add_definitions(-DPHYSFS_HAVE_READLINE=1)
210 | endif()
211 | endif()
212 | add_executable(test_physfs test/test_physfs.c)
213 | target_link_libraries(test_physfs ${PHYSFS_LIB_TARGET} ${TEST_PHYSFS_LIBS} ${OTHER_LDFLAGS})
214 | set(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";test_physfs")
215 | endif()
216 |
217 | install(TARGETS ${PHYSFS_INSTALL_TARGETS} EXPORT PhysFSExport
218 | RUNTIME DESTINATION bin
219 | LIBRARY DESTINATION lib${LIB_SUFFIX}
220 | ARCHIVE DESTINATION lib${LIB_SUFFIX}
221 | INCLUDES DESTINATION include)
222 | install(FILES src/physfs.h DESTINATION include)
223 |
224 | install(EXPORT PhysFSExport
225 | DESTINATION "lib${LIB_SUFFIX}/cmake/PhysFS"
226 | FILE PhysFSConfig.cmake
227 | )
228 |
229 |
230 | find_package(Doxygen)
231 | if(DOXYGEN_FOUND)
232 | set(PHYSFS_OUTPUT_DOXYFILE "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile")
233 | configure_file(
234 | "${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile"
235 | "${PHYSFS_OUTPUT_DOXYFILE}"
236 | COPYONLY
237 | )
238 | file(APPEND "${PHYSFS_OUTPUT_DOXYFILE}" "\n\n# Below auto-generated by cmake...\n\n")
239 | file(APPEND "${PHYSFS_OUTPUT_DOXYFILE}" "PROJECT_NUMBER = \"${PHYSFS_VERSION}\"\n")
240 | file(APPEND "${PHYSFS_OUTPUT_DOXYFILE}" "OUTPUT_DIRECTORY = \"${CMAKE_CURRENT_BINARY_DIR}/docs\"\n")
241 | file(APPEND "${PHYSFS_OUTPUT_DOXYFILE}" "\n# End auto-generated section.\n\n")
242 |
243 | set(PHYSFS_TARGETNAME_DOCS "docs" CACHE STRING "Name of 'docs' build target")
244 | add_custom_target(
245 | ${PHYSFS_TARGETNAME_DOCS}
246 | ${DOXYGEN_EXECUTABLE} "${PHYSFS_OUTPUT_DOXYFILE}"
247 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
248 | COMMENT "Building documentation in 'docs' directory..."
249 | )
250 | else()
251 | message(STATUS "Doxygen not found. You won't be able to build documentation.")
252 | endif()
253 |
254 | if(UNIX)
255 | set(PHYSFS_TARBALL "${CMAKE_CURRENT_SOURCE_DIR}/../physfs-${PHYSFS_VERSION}.tar.gz")
256 |
257 | set(PHYSFS_TARGETNAME_DIST "dist" CACHE STRING "Name of 'dist' build target")
258 | add_custom_target(
259 | ${PHYSFS_TARGETNAME_DIST}
260 | git archive --prefix="physfs-${PHYSFS_VERSION}/" --output="${PHYSFS_TARBALL}" HEAD
261 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
262 | COMMENT "Building source tarball '${PHYSFS_TARBALL}'..."
263 | )
264 |
265 | set(PHYSFS_TARGETNAME_UNINSTALL "uninstall" CACHE STRING "Name of 'uninstall' build target")
266 | add_custom_target(
267 | ${PHYSFS_TARGETNAME_UNINSTALL}
268 | "${CMAKE_CURRENT_SOURCE_DIR}/extras/uninstall.sh"
269 | WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
270 | COMMENT "Uninstall the project..."
271 | )
272 | endif()
273 |
274 | if(NOT MSVC)
275 | configure_file(
276 | "extras/physfs.pc.in"
277 | "extras/physfs.pc"
278 | @ONLY
279 | )
280 | install(
281 | FILES "${CMAKE_CURRENT_BINARY_DIR}/extras/physfs.pc"
282 | DESTINATION "lib${LIB_SUFFIX}/pkgconfig"
283 | )
284 | endif()
285 |
286 | macro(message_bool_option _NAME _VALUE)
287 | if(${_VALUE})
288 | message(STATUS " ${_NAME}: enabled")
289 | else()
290 | message(STATUS " ${_NAME}: disabled")
291 | endif()
292 | endmacro()
293 |
294 | message(STATUS "PhysicsFS will build with the following options:")
295 | message_bool_option("ZIP support" PHYSFS_ARCHIVE_ZIP)
296 | message_bool_option("7zip support" PHYSFS_ARCHIVE_7Z)
297 | message_bool_option("GRP support" PHYSFS_ARCHIVE_GRP)
298 | message_bool_option("WAD support" PHYSFS_ARCHIVE_WAD)
299 | message_bool_option("HOG support" PHYSFS_ARCHIVE_HOG)
300 | message_bool_option("MVL support" PHYSFS_ARCHIVE_MVL)
301 | message_bool_option("QPAK support" PHYSFS_ARCHIVE_QPAK)
302 | message_bool_option("SLB support" PHYSFS_ARCHIVE_SLB)
303 | message_bool_option("VDF support" PHYSFS_ARCHIVE_VDF)
304 | message_bool_option("ISO9660 support" PHYSFS_ARCHIVE_ISO9660)
305 | message_bool_option("Build static library" PHYSFS_BUILD_STATIC)
306 | message_bool_option("Build shared library" PHYSFS_BUILD_SHARED)
307 | message_bool_option("Build stdio test program" PHYSFS_BUILD_TEST)
308 | if(PHYSFS_BUILD_TEST)
309 | message_bool_option(" Use readline in test program" HAVE_SYSTEM_READLINE)
310 | endif()
311 |
312 | # end of CMakeLists.txt ...
313 |
314 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2001-2021 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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/extras/physfs.pc.in:
--------------------------------------------------------------------------------
1 | prefix=@CMAKE_INSTALL_PREFIX@
2 | exec_prefix=${prefix}
3 | libdir=${exec_prefix}/lib
4 | includedir=${prefix}/include
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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/src/physfs_archiver_7z.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 7zip support routines for PhysicsFS.
3 | *
4 | * Please see the file LICENSE.txt in the source's root directory.
5 | *
6 | * This file was written by Ryan C. Gordon.
7 | */
8 |
9 | #define __PHYSICSFS_INTERNAL__
10 | #include "physfs_internal.h"
11 |
12 | #if PHYSFS_SUPPORTS_7Z
13 |
14 | #include "physfs_lzmasdk.h"
15 |
16 | typedef struct
17 | {
18 | ISeekInStream seekStream; /* lzma sdk i/o interface (lower level). */
19 | PHYSFS_Io *io; /* physfs i/o interface for this archive. */
20 | CLookToRead lookStream; /* lzma sdk i/o interface (higher level). */
21 | } SZIPLookToRead;
22 |
23 | /* One SZIPentry is kept for each file in an open 7zip archive. */
24 | typedef struct
25 | {
26 | __PHYSFS_DirTreeEntry tree; /* manages directory tree */
27 | PHYSFS_uint32 dbidx; /* index into lzma sdk database */
28 | } SZIPentry;
29 |
30 | /* One SZIPinfo is kept for each open 7zip archive. */
31 | typedef struct
32 | {
33 | __PHYSFS_DirTree tree; /* manages directory tree. */
34 | PHYSFS_Io *io; /* physfs i/o interface for this archive. */
35 | CSzArEx db; /* lzma sdk archive database object. */
36 | } SZIPinfo;
37 |
38 |
39 | static PHYSFS_ErrorCode szipErrorCode(const SRes rc)
40 | {
41 | switch (rc)
42 | {
43 | case SZ_OK: return PHYSFS_ERR_OK;
44 | case SZ_ERROR_DATA: return PHYSFS_ERR_CORRUPT;
45 | case SZ_ERROR_MEM: return PHYSFS_ERR_OUT_OF_MEMORY;
46 | case SZ_ERROR_CRC: return PHYSFS_ERR_CORRUPT;
47 | case SZ_ERROR_UNSUPPORTED: return PHYSFS_ERR_UNSUPPORTED;
48 | case SZ_ERROR_INPUT_EOF: return PHYSFS_ERR_CORRUPT;
49 | case SZ_ERROR_OUTPUT_EOF: return PHYSFS_ERR_IO;
50 | case SZ_ERROR_READ: return PHYSFS_ERR_IO;
51 | case SZ_ERROR_WRITE: return PHYSFS_ERR_IO;
52 | case SZ_ERROR_ARCHIVE: return PHYSFS_ERR_CORRUPT;
53 | case SZ_ERROR_NO_ARCHIVE: return PHYSFS_ERR_UNSUPPORTED;
54 | default: break;
55 | } /* switch */
56 |
57 | return PHYSFS_ERR_OTHER_ERROR;
58 | } /* szipErrorCode */
59 |
60 |
61 | /* LZMA SDK's ISzAlloc interface ... */
62 |
63 | static void *SZIP_ISzAlloc_Alloc(void *p, size_t size)
64 | {
65 | return allocator.Malloc(size ? size : 1);
66 | } /* SZIP_ISzAlloc_Alloc */
67 |
68 | static void SZIP_ISzAlloc_Free(void *p, void *address)
69 | {
70 | if (address)
71 | allocator.Free(address);
72 | } /* SZIP_ISzAlloc_Free */
73 |
74 | static ISzAlloc SZIP_SzAlloc = {
75 | SZIP_ISzAlloc_Alloc, SZIP_ISzAlloc_Free
76 | };
77 |
78 |
79 | /* we implement ISeekInStream, and then wrap that in LZMA SDK's CLookToRead,
80 | which implements the higher-level ILookInStream on top of that, handling
81 | buffering and such for us. */
82 |
83 | /* LZMA SDK's ISeekInStream interface ... */
84 |
85 | static SRes SZIP_ISeekInStream_Read(void *p, void *buf, size_t *size)
86 | {
87 | SZIPLookToRead *stream = (SZIPLookToRead *) p;
88 | PHYSFS_Io *io = stream->io;
89 | const PHYSFS_uint64 len = (PHYSFS_uint64) *size;
90 | const PHYSFS_sint64 rc = (len == 0) ? 0 : io->read(io, buf, len);
91 |
92 | if (rc < 0)
93 | {
94 | *size = 0;
95 | return SZ_ERROR_READ;
96 | } /* if */
97 |
98 | *size = (size_t) rc;
99 | return SZ_OK;
100 | } /* SZIP_ISeekInStream_Read */
101 |
102 | static SRes SZIP_ISeekInStream_Seek(void *p, Int64 *pos, ESzSeek origin)
103 | {
104 | SZIPLookToRead *stream = (SZIPLookToRead *) p;
105 | PHYSFS_Io *io = stream->io;
106 | PHYSFS_sint64 base;
107 | PHYSFS_uint64 newpos;
108 |
109 | switch (origin)
110 | {
111 | case SZ_SEEK_SET:
112 | base = 0;
113 | break;
114 |
115 | case SZ_SEEK_CUR:
116 | base = io->tell(io);
117 | break;
118 |
119 | case SZ_SEEK_END:
120 | base = io->length(io);
121 | break;
122 |
123 | default:
124 | return SZ_ERROR_FAIL;
125 | } /* switch */
126 |
127 | if (base < 0)
128 | return SZ_ERROR_FAIL;
129 | else if ((*pos < 0) && (((Int64) base) < -*pos))
130 | return SZ_ERROR_FAIL;
131 |
132 | newpos = (PHYSFS_uint64) (((Int64) base) + *pos);
133 | if (!io->seek(io, newpos))
134 | return SZ_ERROR_FAIL;
135 |
136 | *pos = (Int64) newpos;
137 | return SZ_OK;
138 | } /* SZIP_ISeekInStream_Seek */
139 |
140 |
141 | static void szipInitStream(SZIPLookToRead *stream, PHYSFS_Io *io)
142 | {
143 | stream->seekStream.Read = SZIP_ISeekInStream_Read;
144 | stream->seekStream.Seek = SZIP_ISeekInStream_Seek;
145 |
146 | stream->io = io;
147 |
148 | /* !!! FIXME: can we use lookahead? Is there value to it? */
149 | LookToRead_Init(&stream->lookStream);
150 | LookToRead_CreateVTable(&stream->lookStream, False);
151 | stream->lookStream.realStream = &stream->seekStream;
152 | } /* szipInitStream */
153 |
154 |
155 | /* Do this in a separate function so we can smallAlloc without looping. */
156 | static int szipLoadEntry(SZIPinfo *info, const PHYSFS_uint32 idx)
157 | {
158 | const size_t utf16len = SzArEx_GetFileNameUtf16(&info->db, idx, NULL);
159 | const size_t utf16buflen = utf16len * 2;
160 | PHYSFS_uint16 *utf16 = (PHYSFS_uint16 *) __PHYSFS_smallAlloc(utf16buflen);
161 | const size_t utf8buflen = utf16len * 4;
162 | char *utf8 = (char *) __PHYSFS_smallAlloc(utf8buflen);
163 | int retval = 0;
164 |
165 | if (utf16 && utf8)
166 | {
167 | const int isdir = SzArEx_IsDir(&info->db, idx) != 0;
168 | SZIPentry *entry;
169 | SzArEx_GetFileNameUtf16(&info->db, idx, (UInt16 *) utf16);
170 | PHYSFS_utf8FromUtf16(utf16, utf8, utf8buflen);
171 | entry = (SZIPentry*) __PHYSFS_DirTreeAdd(&info->tree, utf8, isdir);
172 | retval = (entry != NULL);
173 | if (retval)
174 | entry->dbidx = idx;
175 | } /* if */
176 |
177 | __PHYSFS_smallFree(utf8);
178 | __PHYSFS_smallFree(utf16);
179 |
180 | return retval;
181 | } /* szipLoadEntry */
182 |
183 |
184 | static int szipLoadEntries(SZIPinfo *info)
185 | {
186 | int retval = 0;
187 |
188 | if (__PHYSFS_DirTreeInit(&info->tree, sizeof (SZIPentry)))
189 | {
190 | const PHYSFS_uint32 count = info->db.NumFiles;
191 | PHYSFS_uint32 i;
192 | for (i = 0; i < count; i++)
193 | BAIL_IF_ERRPASS(!szipLoadEntry(info, i), 0);
194 | retval = 1;
195 | } /* if */
196 |
197 | return retval;
198 | } /* szipLoadEntries */
199 |
200 |
201 | static void SZIP_closeArchive(void *opaque)
202 | {
203 | SZIPinfo *info = (SZIPinfo *) opaque;
204 | if (info)
205 | {
206 | if (info->io)
207 | info->io->destroy(info->io);
208 | SzArEx_Free(&info->db, &SZIP_SzAlloc);
209 | __PHYSFS_DirTreeDeinit(&info->tree);
210 | allocator.Free(info);
211 | } /* if */
212 | } /* SZIP_closeArchive */
213 |
214 |
215 | static void *SZIP_openArchive(PHYSFS_Io *io, const char *name,
216 | int forWriting, int *claimed)
217 | {
218 | static const PHYSFS_uint8 wantedsig[] = { '7','z',0xBC,0xAF,0x27,0x1C };
219 | SZIPLookToRead stream;
220 | ISzAlloc *alloc = &SZIP_SzAlloc;
221 | SZIPinfo *info = NULL;
222 | SRes rc;
223 | PHYSFS_uint8 sig[6];
224 | PHYSFS_sint64 pos;
225 |
226 | BAIL_IF(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
227 | pos = io->tell(io);
228 | BAIL_IF_ERRPASS(pos == -1, NULL);
229 | BAIL_IF_ERRPASS(io->read(io, sig, 6) != 6, NULL);
230 | *claimed = (memcmp(sig, wantedsig, 6) == 0);
231 | BAIL_IF_ERRPASS(!io->seek(io, pos), NULL);
232 |
233 | info = (SZIPinfo *) allocator.Malloc(sizeof (SZIPinfo));
234 | BAIL_IF(!info, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
235 | memset(info, '\0', sizeof (*info));
236 |
237 | SzArEx_Init(&info->db);
238 |
239 | info->io = io;
240 |
241 | szipInitStream(&stream, io);
242 | rc = SzArEx_Open(&info->db, &stream.lookStream.s, alloc, alloc);
243 | GOTO_IF(rc != SZ_OK, szipErrorCode(rc), failed);
244 |
245 | GOTO_IF_ERRPASS(!szipLoadEntries(info), failed);
246 |
247 | return info;
248 |
249 | failed:
250 | info->io = NULL; /* don't let cleanup destroy the PHYSFS_Io. */
251 | SZIP_closeArchive(info);
252 | return NULL;
253 | } /* SZIP_openArchive */
254 |
255 |
256 | static PHYSFS_Io *SZIP_openRead(void *opaque, const char *path)
257 | {
258 | /* !!! FIXME: the current lzma sdk C API only allows you to decompress
259 | !!! FIXME: the entire file at once, which isn't ideal. Fix this in the
260 | !!! FIXME: SDK and then convert this all to a streaming interface. */
261 |
262 | SZIPinfo *info = (SZIPinfo *) opaque;
263 | SZIPentry *entry = (SZIPentry *) __PHYSFS_DirTreeFind(&info->tree, path);
264 | ISzAlloc *alloc = &SZIP_SzAlloc;
265 | SZIPLookToRead stream;
266 | PHYSFS_Io *retval = NULL;
267 | PHYSFS_Io *io = NULL;
268 | UInt32 blockIndex = 0xFFFFFFFF;
269 | Byte *outBuffer = NULL;
270 | size_t outBufferSize = 0;
271 | size_t offset = 0;
272 | size_t outSizeProcessed = 0;
273 | void *buf = NULL;
274 | SRes rc;
275 |
276 | BAIL_IF_ERRPASS(!entry, NULL);
277 | BAIL_IF(entry->tree.isdir, PHYSFS_ERR_NOT_A_FILE, NULL);
278 |
279 | io = info->io->duplicate(info->io);
280 | GOTO_IF_ERRPASS(!io, SZIP_openRead_failed);
281 |
282 | szipInitStream(&stream, io);
283 |
284 | rc = SzArEx_Extract(&info->db, &stream.lookStream.s, entry->dbidx,
285 | &blockIndex, &outBuffer, &outBufferSize, &offset,
286 | &outSizeProcessed, alloc, alloc);
287 | GOTO_IF(rc != SZ_OK, szipErrorCode(rc), SZIP_openRead_failed);
288 | GOTO_IF(outBuffer == NULL, PHYSFS_ERR_OUT_OF_MEMORY, SZIP_openRead_failed);
289 |
290 | io->destroy(io);
291 | io = NULL;
292 |
293 | buf = allocator.Malloc(outSizeProcessed ? outSizeProcessed : 1);
294 | GOTO_IF(buf == NULL, PHYSFS_ERR_OUT_OF_MEMORY, SZIP_openRead_failed);
295 |
296 | if (outSizeProcessed > 0)
297 | memcpy(buf, outBuffer + offset, outSizeProcessed);
298 |
299 | alloc->Free(alloc, outBuffer);
300 | outBuffer = NULL;
301 |
302 | retval = __PHYSFS_createMemoryIo(buf, outSizeProcessed, allocator.Free);
303 | GOTO_IF_ERRPASS(!retval, SZIP_openRead_failed);
304 |
305 | return retval;
306 |
307 | SZIP_openRead_failed:
308 | if (io != NULL)
309 | io->destroy(io);
310 |
311 | if (buf)
312 | allocator.Free(buf);
313 |
314 | if (outBuffer)
315 | alloc->Free(alloc, outBuffer);
316 |
317 | return NULL;
318 | } /* SZIP_openRead */
319 |
320 |
321 | static PHYSFS_Io *SZIP_openWrite(void *opaque, const char *filename)
322 | {
323 | BAIL(PHYSFS_ERR_READ_ONLY, NULL);
324 | } /* SZIP_openWrite */
325 |
326 |
327 | static PHYSFS_Io *SZIP_openAppend(void *opaque, const char *filename)
328 | {
329 | BAIL(PHYSFS_ERR_READ_ONLY, NULL);
330 | } /* SZIP_openAppend */
331 |
332 |
333 | static int SZIP_remove(void *opaque, const char *name)
334 | {
335 | BAIL(PHYSFS_ERR_READ_ONLY, 0);
336 | } /* SZIP_remove */
337 |
338 |
339 | static int SZIP_mkdir(void *opaque, const char *name)
340 | {
341 | BAIL(PHYSFS_ERR_READ_ONLY, 0);
342 | } /* SZIP_mkdir */
343 |
344 |
345 | static inline PHYSFS_uint64 lzmasdkTimeToPhysfsTime(const CNtfsFileTime *t)
346 | {
347 | const PHYSFS_uint64 winEpochToUnixEpoch = __PHYSFS_UI64(0x019DB1DED53E8000);
348 | const PHYSFS_uint64 nanosecToMillisec = __PHYSFS_UI64(10000000);
349 | const PHYSFS_uint64 quad = (((PHYSFS_uint64) t->High) << 32) | t->Low;
350 | return (quad - winEpochToUnixEpoch) / nanosecToMillisec;
351 | } /* lzmasdkTimeToPhysfsTime */
352 |
353 |
354 | static int SZIP_stat(void *opaque, const char *path, PHYSFS_Stat *stat)
355 | {
356 | SZIPinfo *info = (SZIPinfo *) opaque;
357 | SZIPentry *entry;
358 | PHYSFS_uint32 idx;
359 |
360 | entry = (SZIPentry *) __PHYSFS_DirTreeFind(&info->tree, path);
361 | BAIL_IF_ERRPASS(!entry, 0);
362 | idx = entry->dbidx;
363 |
364 | if (entry->tree.isdir)
365 | {
366 | stat->filesize = -1;
367 | stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
368 | } /* if */
369 | else
370 | {
371 | stat->filesize = (PHYSFS_sint64) SzArEx_GetFileSize(&info->db, idx);
372 | stat->filetype = PHYSFS_FILETYPE_REGULAR;
373 | } /* else */
374 |
375 | if (info->db.MTime.Vals != NULL)
376 | stat->modtime = lzmasdkTimeToPhysfsTime(&info->db.MTime.Vals[idx]);
377 | else if (info->db.CTime.Vals != NULL)
378 | stat->modtime = lzmasdkTimeToPhysfsTime(&info->db.CTime.Vals[idx]);
379 | else
380 | stat->modtime = -1;
381 |
382 | if (info->db.CTime.Vals != NULL)
383 | stat->createtime = lzmasdkTimeToPhysfsTime(&info->db.CTime.Vals[idx]);
384 | else if (info->db.MTime.Vals != NULL)
385 | stat->createtime = lzmasdkTimeToPhysfsTime(&info->db.MTime.Vals[idx]);
386 | else
387 | stat->createtime = -1;
388 |
389 | stat->accesstime = -1;
390 | stat->readonly = 1;
391 |
392 | return 1;
393 | } /* SZIP_stat */
394 |
395 |
396 | void SZIP_global_init(void)
397 | {
398 | /* this just needs to calculate some things, so it only ever
399 | has to run once, even after a deinit. */
400 | static int generatedTable = 0;
401 | if (!generatedTable)
402 | {
403 | generatedTable = 1;
404 | CrcGenerateTable();
405 | } /* if */
406 | } /* SZIP_global_init */
407 |
408 |
409 | const PHYSFS_Archiver __PHYSFS_Archiver_7Z =
410 | {
411 | CURRENT_PHYSFS_ARCHIVER_API_VERSION,
412 | {
413 | "7Z",
414 | "7zip archives",
415 | "Ryan C. Gordon ",
416 | "https://icculus.org/physfs/",
417 | 0, /* supportsSymlinks */
418 | },
419 | SZIP_openArchive,
420 | __PHYSFS_DirTreeEnumerate,
421 | SZIP_openRead,
422 | SZIP_openWrite,
423 | SZIP_openAppend,
424 | SZIP_remove,
425 | SZIP_mkdir,
426 | SZIP_stat,
427 | SZIP_closeArchive
428 | };
429 |
430 | #endif /* defined PHYSFS_SUPPORTS_7Z */
431 |
432 | /* end of physfs_archiver_7z.c ... */
433 |
434 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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);
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 |
--------------------------------------------------------------------------------
/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);
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 |
--------------------------------------------------------------------------------
/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);
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 |
--------------------------------------------------------------------------------
/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 | unpkarc = UNPK_openArchive(io);
90 | BAIL_IF_ERRPASS(!unpkarc, NULL);
91 |
92 | if (!qpakLoadEntries(io, count, unpkarc))
93 | {
94 | UNPK_abandonArchive(unpkarc);
95 | return NULL;
96 | } /* if */
97 |
98 | return unpkarc;
99 | } /* QPAK_openArchive */
100 |
101 |
102 | const PHYSFS_Archiver __PHYSFS_Archiver_QPAK =
103 | {
104 | CURRENT_PHYSFS_ARCHIVER_API_VERSION,
105 | {
106 | "PAK",
107 | "Quake I/II format",
108 | "Ryan C. Gordon ",
109 | "https://icculus.org/physfs/",
110 | 0, /* supportsSymlinks */
111 | },
112 | QPAK_openArchive,
113 | UNPK_enumerate,
114 | UNPK_openRead,
115 | UNPK_openWrite,
116 | UNPK_openAppend,
117 | UNPK_remove,
118 | UNPK_mkdir,
119 | UNPK_stat,
120 | UNPK_closeArchive
121 | };
122 |
123 | #endif /* defined PHYSFS_SUPPORTS_QPAK */
124 |
125 | /* end of physfs_archiver_qpak.c ... */
126 |
127 |
--------------------------------------------------------------------------------
/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 | unpkarc = UNPK_openArchive(io);
98 | BAIL_IF_ERRPASS(!unpkarc, NULL);
99 |
100 | if (!slbLoadEntries(io, count, unpkarc))
101 | {
102 | UNPK_abandonArchive(unpkarc);
103 | return NULL;
104 | } /* if */
105 |
106 | *claimed = 1; /* oh well. */
107 |
108 | return unpkarc;
109 | } /* SLB_openArchive */
110 |
111 |
112 | const PHYSFS_Archiver __PHYSFS_Archiver_SLB =
113 | {
114 | CURRENT_PHYSFS_ARCHIVER_API_VERSION,
115 | {
116 | "SLB",
117 | "I-War / Independence War Slab file",
118 | "Aleksi Nurmi ",
119 | "https://bitbucket.org/ahnurmi/",
120 | 0, /* supportsSymlinks */
121 | },
122 | SLB_openArchive,
123 | UNPK_enumerate,
124 | UNPK_openRead,
125 | UNPK_openWrite,
126 | UNPK_openAppend,
127 | UNPK_remove,
128 | UNPK_mkdir,
129 | UNPK_stat,
130 | UNPK_closeArchive
131 | };
132 |
133 | #endif /* defined PHYSFS_SUPPORTS_SLB */
134 |
135 | /* end of physfs_archiver_slb.c ... */
136 |
--------------------------------------------------------------------------------
/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)
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)))
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 |
--------------------------------------------------------------------------------
/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 | unpkarc = UNPK_openArchive(io);
133 | BAIL_IF_ERRPASS(!unpkarc, NULL);
134 |
135 | if (!vdfLoadEntries(io, count, vdfDosTimeToEpoch(timestamp), unpkarc))
136 | {
137 | UNPK_abandonArchive(unpkarc);
138 | return NULL;
139 | } /* if */
140 |
141 | return unpkarc;
142 | } /* VDF_openArchive */
143 |
144 |
145 | const PHYSFS_Archiver __PHYSFS_Archiver_VDF =
146 | {
147 | CURRENT_PHYSFS_ARCHIVER_API_VERSION,
148 | {
149 | "VDF",
150 | "Gothic I/II engine format",
151 | "Francesco Bertolaccini ",
152 | "https://github.com/frabert",
153 | 0, /* supportsSymlinks */
154 | },
155 | VDF_openArchive,
156 | UNPK_enumerate,
157 | UNPK_openRead,
158 | UNPK_openWrite,
159 | UNPK_openAppend,
160 | UNPK_remove,
161 | UNPK_mkdir,
162 | UNPK_stat,
163 | UNPK_closeArchive
164 | };
165 |
166 | #endif /* defined PHYSFS_SUPPORTS_VDF */
167 |
168 | /* end of physfs_archiver_vdf.c ... */
169 |
--------------------------------------------------------------------------------
/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);
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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
16 | #include "physfs_internal.h"
17 |
18 | int __PHYSFS_platformInit(void)
19 | {
20 | return 1; /* success. */
21 | } /* __PHYSFS_platformInit */
22 |
23 |
24 | void __PHYSFS_platformDeinit(void)
25 | {
26 | /* no-op */
27 | } /* __PHYSFS_platformDeinit */
28 |
29 |
30 | char *__PHYSFS_platformCalcBaseDir(const char *argv0)
31 | {
32 | @autoreleasepool
33 | {
34 | NSString *path = [[NSBundle mainBundle] bundlePath];
35 | BAIL_IF(!path, PHYSFS_ERR_OS_ERROR, NULL);
36 | size_t len = [path lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
37 | char *retval = (char *) allocator.Malloc(len + 2);
38 | BAIL_IF(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
39 | [path getCString:retval maxLength:len+1 encoding:NSUTF8StringEncoding];
40 | retval[len] = '/';
41 | retval[len+1] = '\0';
42 | return retval; /* whew. */
43 | } /* @autoreleasepool */
44 | } /* __PHYSFS_platformCalcBaseDir */
45 |
46 |
47 | char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
48 | {
49 | @autoreleasepool
50 | {
51 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, TRUE);
52 | BAIL_IF(!paths, PHYSFS_ERR_OS_ERROR, NULL);
53 | NSString *path = (NSString *) [paths objectAtIndex:0];
54 | BAIL_IF(!path, PHYSFS_ERR_OS_ERROR, NULL);
55 | size_t len = [path lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
56 | const size_t applen = strlen(app);
57 | char *retval = (char *) allocator.Malloc(len + applen + 3);
58 | BAIL_IF(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
59 | [path getCString:retval maxLength:len+1 encoding:NSUTF8StringEncoding];
60 | snprintf(retval + len, applen + 3, "/%s/", app);
61 | return retval; /* whew. */
62 | } /* @autoreleasepool */
63 | } /* __PHYSFS_platformCalcPrefDir */
64 |
65 |
66 | /* CD-ROM detection code... */
67 |
68 | /*
69 | * Code based on sample from Apple Developer Connection:
70 | * https://developer.apple.com/samplecode/Sample_Code/Devices_and_Hardware/Disks/VolumeToBSDNode/VolumeToBSDNode.c.htm
71 | */
72 |
73 | #if !defined(PHYSFS_NO_CDROM_SUPPORT)
74 |
75 | #include
76 | #include
77 | #include
78 | #include
79 | #include
80 |
81 | static int darwinIsWholeMedia(io_service_t service)
82 | {
83 | int retval = 0;
84 | CFTypeRef wholeMedia;
85 |
86 | if (!IOObjectConformsTo(service, kIOMediaClass))
87 | return 0;
88 |
89 | wholeMedia = IORegistryEntryCreateCFProperty(service,
90 | CFSTR(kIOMediaWholeKey),
91 | NULL, 0);
92 | if (wholeMedia == NULL)
93 | return 0;
94 |
95 | retval = CFBooleanGetValue(wholeMedia);
96 | CFRelease(wholeMedia);
97 |
98 | return retval;
99 | } /* darwinIsWholeMedia */
100 |
101 |
102 | static int darwinIsMountedDisc(char *bsdName, mach_port_t masterPort)
103 | {
104 | int retval = 0;
105 | CFMutableDictionaryRef matchingDict;
106 | kern_return_t rc;
107 | io_iterator_t iter;
108 | io_service_t service;
109 |
110 | if ((matchingDict = IOBSDNameMatching(masterPort, 0, bsdName)) == NULL)
111 | return 0;
112 |
113 | rc = IOServiceGetMatchingServices(masterPort, matchingDict, &iter);
114 | if ((rc != KERN_SUCCESS) || (!iter))
115 | return 0;
116 |
117 | service = IOIteratorNext(iter);
118 | IOObjectRelease(iter);
119 | if (!service)
120 | return 0;
121 |
122 | rc = IORegistryEntryCreateIterator(service, kIOServicePlane,
123 | kIORegistryIterateRecursively | kIORegistryIterateParents, &iter);
124 |
125 | if (!iter)
126 | return 0;
127 |
128 | if (rc != KERN_SUCCESS)
129 | {
130 | IOObjectRelease(iter);
131 | return 0;
132 | } /* if */
133 |
134 | IOObjectRetain(service); /* add an extra object reference... */
135 |
136 | do
137 | {
138 | if (darwinIsWholeMedia(service))
139 | {
140 | if ( (IOObjectConformsTo(service, kIOCDMediaClass)) ||
141 | (IOObjectConformsTo(service, kIODVDMediaClass)) )
142 | {
143 | retval = 1;
144 | } /* if */
145 | } /* if */
146 | IOObjectRelease(service);
147 | } while ((service = IOIteratorNext(iter)) && (!retval));
148 |
149 | IOObjectRelease(iter);
150 | IOObjectRelease(service);
151 |
152 | return retval;
153 | } /* darwinIsMountedDisc */
154 |
155 | #endif /* !defined(PHYSFS_NO_CDROM_SUPPORT) */
156 |
157 |
158 | void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
159 | {
160 | #if !defined(PHYSFS_NO_CDROM_SUPPORT)
161 | const char *devPrefix = "/dev/";
162 | const int prefixLen = strlen(devPrefix);
163 | mach_port_t masterPort = 0;
164 | struct statfs *mntbufp;
165 | int i, mounts;
166 |
167 | if (IOMasterPort(MACH_PORT_NULL, &masterPort) != KERN_SUCCESS)
168 | BAIL(PHYSFS_ERR_OS_ERROR, ) /*return void*/;
169 |
170 | mounts = getmntinfo(&mntbufp, MNT_WAIT); /* NOT THREAD SAFE! */
171 | for (i = 0; i < mounts; i++)
172 | {
173 | char *dev = mntbufp[i].f_mntfromname;
174 | char *mnt = mntbufp[i].f_mntonname;
175 | if (strncmp(dev, devPrefix, prefixLen) != 0) /* a virtual device? */
176 | continue;
177 |
178 | dev += prefixLen;
179 | if (darwinIsMountedDisc(dev, masterPort))
180 | cb(data, mnt);
181 | } /* for */
182 | #endif /* !defined(PHYSFS_NO_CDROM_SUPPORT) */
183 | } /* __PHYSFS_platformDetectAvailableCDs */
184 |
185 | #endif /* PHYSFS_PLATFORM_APPLE */
186 |
187 | /* end of physfs_platform_apple.m ... */
188 |
189 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | /* !!! FIXME: check for EINTR? */
10 |
11 | #define __PHYSICSFS_INTERNAL__
12 | #include "physfs_platforms.h"
13 |
14 | #ifdef PHYSFS_PLATFORM_POSIX
15 |
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 |
26 | #include "physfs_internal.h"
27 |
28 |
29 | static PHYSFS_ErrorCode errcodeFromErrnoError(const int err)
30 | {
31 | switch (err)
32 | {
33 | case 0: return PHYSFS_ERR_OK;
34 | case EACCES: return PHYSFS_ERR_PERMISSION;
35 | case EPERM: return PHYSFS_ERR_PERMISSION;
36 | case EDQUOT: return PHYSFS_ERR_NO_SPACE;
37 | case EIO: return PHYSFS_ERR_IO;
38 | case ELOOP: return PHYSFS_ERR_SYMLINK_LOOP;
39 | case EMLINK: return PHYSFS_ERR_NO_SPACE;
40 | case ENAMETOOLONG: return PHYSFS_ERR_BAD_FILENAME;
41 | case ENOENT: return PHYSFS_ERR_NOT_FOUND;
42 | case ENOSPC: return PHYSFS_ERR_NO_SPACE;
43 | case ENOTDIR: return PHYSFS_ERR_NOT_FOUND;
44 | case EISDIR: return PHYSFS_ERR_NOT_A_FILE;
45 | case EROFS: return PHYSFS_ERR_READ_ONLY;
46 | case ETXTBSY: return PHYSFS_ERR_BUSY;
47 | case EBUSY: return PHYSFS_ERR_BUSY;
48 | case ENOMEM: return PHYSFS_ERR_OUT_OF_MEMORY;
49 | case ENOTEMPTY: return PHYSFS_ERR_DIR_NOT_EMPTY;
50 | default: return PHYSFS_ERR_OS_ERROR;
51 | } /* switch */
52 | } /* errcodeFromErrnoError */
53 |
54 |
55 | static inline PHYSFS_ErrorCode errcodeFromErrno(void)
56 | {
57 | return errcodeFromErrnoError(errno);
58 | } /* errcodeFromErrno */
59 |
60 |
61 | static char *getUserDirByUID(void)
62 | {
63 | uid_t uid = getuid();
64 | struct passwd *pw;
65 | char *retval = NULL;
66 |
67 | pw = getpwuid(uid);
68 | if ((pw != NULL) && (pw->pw_dir != NULL) && (*pw->pw_dir != '\0'))
69 | {
70 | const size_t dlen = strlen(pw->pw_dir);
71 | const size_t add_dirsep = (pw->pw_dir[dlen-1] != '/') ? 1 : 0;
72 | retval = (char *) allocator.Malloc(dlen + 1 + add_dirsep);
73 | if (retval != NULL)
74 | {
75 | strcpy(retval, pw->pw_dir);
76 | if (add_dirsep)
77 | {
78 | retval[dlen] = '/';
79 | retval[dlen+1] = '\0';
80 | } /* if */
81 | } /* if */
82 | } /* if */
83 |
84 | return retval;
85 | } /* getUserDirByUID */
86 |
87 |
88 | char *__PHYSFS_platformCalcUserDir(void)
89 | {
90 | char *retval = NULL;
91 | char *envr = getenv("HOME");
92 |
93 | /* if the environment variable was set, make sure it's really a dir. */
94 | if (envr != NULL)
95 | {
96 | struct stat statbuf;
97 | if ((stat(envr, &statbuf) != -1) && (S_ISDIR(statbuf.st_mode)))
98 | {
99 | const size_t envrlen = strlen(envr);
100 | const size_t add_dirsep = (envr[envrlen-1] != '/') ? 1 : 0;
101 | retval = allocator.Malloc(envrlen + 1 + add_dirsep);
102 | if (retval)
103 | {
104 | strcpy(retval, envr);
105 | if (add_dirsep)
106 | {
107 | retval[envrlen] = '/';
108 | retval[envrlen+1] = '\0';
109 | } /* if */
110 | } /* if */
111 | } /* if */
112 | } /* if */
113 |
114 | if (retval == NULL)
115 | retval = getUserDirByUID();
116 |
117 | return retval;
118 | } /* __PHYSFS_platformCalcUserDir */
119 |
120 |
121 | PHYSFS_EnumerateCallbackResult __PHYSFS_platformEnumerate(const char *dirname,
122 | PHYSFS_EnumerateCallback callback,
123 | const char *origdir, void *callbackdata)
124 | {
125 | DIR *dir;
126 | struct dirent *ent;
127 | PHYSFS_EnumerateCallbackResult retval = PHYSFS_ENUM_OK;
128 |
129 | dir = opendir(dirname);
130 | BAIL_IF(dir == NULL, errcodeFromErrno(), PHYSFS_ENUM_ERROR);
131 |
132 | while ((retval == PHYSFS_ENUM_OK) && ((ent = readdir(dir)) != NULL))
133 | {
134 | const char *name = ent->d_name;
135 | if (name[0] == '.') /* ignore "." and ".." */
136 | {
137 | if ((name[1] == '\0') || ((name[1] == '.') && (name[2] == '\0')))
138 | continue;
139 | } /* if */
140 |
141 | retval = callback(callbackdata, origdir, name);
142 | if (retval == PHYSFS_ENUM_ERROR)
143 | PHYSFS_setErrorCode(PHYSFS_ERR_APP_CALLBACK);
144 | } /* while */
145 |
146 | closedir(dir);
147 |
148 | return retval;
149 | } /* __PHYSFS_platformEnumerate */
150 |
151 |
152 | int __PHYSFS_platformMkDir(const char *path)
153 | {
154 | const int rc = mkdir(path, S_IRWXU);
155 | BAIL_IF(rc == -1, errcodeFromErrno(), 0);
156 | return 1;
157 | } /* __PHYSFS_platformMkDir */
158 |
159 |
160 | static void *doOpen(const char *filename, int mode)
161 | {
162 | const int appending = (mode & O_APPEND);
163 | int fd;
164 | int *retval;
165 | errno = 0;
166 |
167 | /* O_APPEND doesn't actually behave as we'd like. */
168 | mode &= ~O_APPEND;
169 |
170 | fd = open(filename, mode, S_IRUSR | S_IWUSR);
171 | BAIL_IF(fd < 0, errcodeFromErrno(), NULL);
172 |
173 | if (appending)
174 | {
175 | if (lseek(fd, 0, SEEK_END) < 0)
176 | {
177 | const int err = errno;
178 | close(fd);
179 | BAIL(errcodeFromErrnoError(err), NULL);
180 | } /* if */
181 | } /* if */
182 |
183 | retval = (int *) allocator.Malloc(sizeof (int));
184 | if (!retval)
185 | {
186 | close(fd);
187 | BAIL(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
188 | } /* if */
189 |
190 | *retval = fd;
191 | return ((void *) retval);
192 | } /* doOpen */
193 |
194 |
195 | void *__PHYSFS_platformOpenRead(const char *filename)
196 | {
197 | return doOpen(filename, O_RDONLY);
198 | } /* __PHYSFS_platformOpenRead */
199 |
200 |
201 | void *__PHYSFS_platformOpenWrite(const char *filename)
202 | {
203 | return doOpen(filename, O_WRONLY | O_CREAT | O_TRUNC);
204 | } /* __PHYSFS_platformOpenWrite */
205 |
206 |
207 | void *__PHYSFS_platformOpenAppend(const char *filename)
208 | {
209 | return doOpen(filename, O_WRONLY | O_CREAT | O_APPEND);
210 | } /* __PHYSFS_platformOpenAppend */
211 |
212 |
213 | PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
214 | PHYSFS_uint64 len)
215 | {
216 | const int fd = *((int *) opaque);
217 | ssize_t rc = 0;
218 |
219 | if (!__PHYSFS_ui64FitsAddressSpace(len))
220 | BAIL(PHYSFS_ERR_INVALID_ARGUMENT, -1);
221 |
222 | rc = read(fd, buffer, (size_t) len);
223 | BAIL_IF(rc == -1, errcodeFromErrno(), -1);
224 | assert(rc >= 0);
225 | assert(rc <= len);
226 | return (PHYSFS_sint64) rc;
227 | } /* __PHYSFS_platformRead */
228 |
229 |
230 | PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
231 | PHYSFS_uint64 len)
232 | {
233 | const int fd = *((int *) opaque);
234 | ssize_t rc = 0;
235 |
236 | if (!__PHYSFS_ui64FitsAddressSpace(len))
237 | BAIL(PHYSFS_ERR_INVALID_ARGUMENT, -1);
238 |
239 | rc = write(fd, (void *) buffer, (size_t) len);
240 | BAIL_IF(rc == -1, errcodeFromErrno(), rc);
241 | assert(rc >= 0);
242 | assert(rc <= len);
243 | return (PHYSFS_sint64) rc;
244 | } /* __PHYSFS_platformWrite */
245 |
246 |
247 | int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos)
248 | {
249 | const int fd = *((int *) opaque);
250 | const off_t rc = lseek(fd, (off_t) pos, SEEK_SET);
251 | BAIL_IF(rc == -1, errcodeFromErrno(), 0);
252 | return 1;
253 | } /* __PHYSFS_platformSeek */
254 |
255 |
256 | PHYSFS_sint64 __PHYSFS_platformTell(void *opaque)
257 | {
258 | const int fd = *((int *) opaque);
259 | PHYSFS_sint64 retval;
260 | retval = (PHYSFS_sint64) lseek(fd, 0, SEEK_CUR);
261 | BAIL_IF(retval == -1, errcodeFromErrno(), -1);
262 | return retval;
263 | } /* __PHYSFS_platformTell */
264 |
265 |
266 | PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
267 | {
268 | const int fd = *((int *) opaque);
269 | struct stat statbuf;
270 | BAIL_IF(fstat(fd, &statbuf) == -1, errcodeFromErrno(), -1);
271 | return ((PHYSFS_sint64) statbuf.st_size);
272 | } /* __PHYSFS_platformFileLength */
273 |
274 |
275 | int __PHYSFS_platformFlush(void *opaque)
276 | {
277 | const int fd = *((int *) opaque);
278 | if ((fcntl(fd, F_GETFL) & O_ACCMODE) != O_RDONLY)
279 | BAIL_IF(fsync(fd) == -1, errcodeFromErrno(), 0);
280 | return 1;
281 | } /* __PHYSFS_platformFlush */
282 |
283 |
284 | void __PHYSFS_platformClose(void *opaque)
285 | {
286 | const int fd = *((int *) opaque);
287 | (void) close(fd); /* we don't check this. You should have used flush! */
288 | allocator.Free(opaque);
289 | } /* __PHYSFS_platformClose */
290 |
291 |
292 | int __PHYSFS_platformDelete(const char *path)
293 | {
294 | BAIL_IF(remove(path) == -1, errcodeFromErrno(), 0);
295 | return 1;
296 | } /* __PHYSFS_platformDelete */
297 |
298 |
299 | int __PHYSFS_platformStat(const char *fname, PHYSFS_Stat *st, const int follow)
300 | {
301 | struct stat statbuf;
302 | const int rc = follow ? stat(fname, &statbuf) : lstat(fname, &statbuf);
303 | BAIL_IF(rc == -1, errcodeFromErrno(), 0);
304 |
305 | if (S_ISREG(statbuf.st_mode))
306 | {
307 | st->filetype = PHYSFS_FILETYPE_REGULAR;
308 | st->filesize = statbuf.st_size;
309 | } /* if */
310 |
311 | else if(S_ISDIR(statbuf.st_mode))
312 | {
313 | st->filetype = PHYSFS_FILETYPE_DIRECTORY;
314 | st->filesize = 0;
315 | } /* else if */
316 |
317 | else if(S_ISLNK(statbuf.st_mode))
318 | {
319 | st->filetype = PHYSFS_FILETYPE_SYMLINK;
320 | st->filesize = 0;
321 | } /* else if */
322 |
323 | else
324 | {
325 | st->filetype = PHYSFS_FILETYPE_OTHER;
326 | st->filesize = statbuf.st_size;
327 | } /* else */
328 |
329 | st->modtime = statbuf.st_mtime;
330 | st->createtime = statbuf.st_ctime;
331 | st->accesstime = statbuf.st_atime;
332 |
333 | st->readonly = (access(fname, W_OK) == -1);
334 | return 1;
335 | } /* __PHYSFS_platformStat */
336 |
337 |
338 | typedef struct
339 | {
340 | pthread_mutex_t mutex;
341 | pthread_t owner;
342 | PHYSFS_uint32 count;
343 | } PthreadMutex;
344 |
345 |
346 | void *__PHYSFS_platformGetThreadID(void)
347 | {
348 | return ( (void *) ((size_t) pthread_self()) );
349 | } /* __PHYSFS_platformGetThreadID */
350 |
351 |
352 | void *__PHYSFS_platformCreateMutex(void)
353 | {
354 | int rc;
355 | PthreadMutex *m = (PthreadMutex *) allocator.Malloc(sizeof (PthreadMutex));
356 | BAIL_IF(!m, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
357 | rc = pthread_mutex_init(&m->mutex, NULL);
358 | if (rc != 0)
359 | {
360 | allocator.Free(m);
361 | BAIL(PHYSFS_ERR_OS_ERROR, NULL);
362 | } /* if */
363 |
364 | m->count = 0;
365 | m->owner = (pthread_t) 0xDEADBEEF;
366 | return ((void *) m);
367 | } /* __PHYSFS_platformCreateMutex */
368 |
369 |
370 | void __PHYSFS_platformDestroyMutex(void *mutex)
371 | {
372 | PthreadMutex *m = (PthreadMutex *) mutex;
373 |
374 | /* Destroying a locked mutex is a bug, but we'll try to be helpful. */
375 | if ((m->owner == pthread_self()) && (m->count > 0))
376 | pthread_mutex_unlock(&m->mutex);
377 |
378 | pthread_mutex_destroy(&m->mutex);
379 | allocator.Free(m);
380 | } /* __PHYSFS_platformDestroyMutex */
381 |
382 |
383 | int __PHYSFS_platformGrabMutex(void *mutex)
384 | {
385 | PthreadMutex *m = (PthreadMutex *) mutex;
386 | pthread_t tid = pthread_self();
387 | if (m->owner != tid)
388 | {
389 | if (pthread_mutex_lock(&m->mutex) != 0)
390 | return 0;
391 | m->owner = tid;
392 | } /* if */
393 |
394 | m->count++;
395 | return 1;
396 | } /* __PHYSFS_platformGrabMutex */
397 |
398 |
399 | void __PHYSFS_platformReleaseMutex(void *mutex)
400 | {
401 | PthreadMutex *m = (PthreadMutex *) mutex;
402 | assert(m->owner == pthread_self()); /* catch programming errors. */
403 | assert(m->count > 0); /* catch programming errors. */
404 | if (m->owner == pthread_self())
405 | {
406 | if (--m->count == 0)
407 | {
408 | m->owner = (pthread_t) 0xDEADBEEF;
409 | pthread_mutex_unlock(&m->mutex);
410 | } /* if */
411 | } /* if */
412 | } /* __PHYSFS_platformReleaseMutex */
413 |
414 | #endif /* PHYSFS_PLATFORM_POSIX */
415 |
416 | /* end of physfs_platform_posix.c ... */
417 |
418 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | #elif defined(PHYSFS_PLATFORM_SOLARIS)
265 | {
266 | const char *path = getexecname();
267 | if ((path != NULL) && (path[0] == '/')) /* must be absolute path... */
268 | retval = __PHYSFS_strdup(path);
269 | }
270 | #endif
271 |
272 | /* If there's a Linux-like /proc filesystem, you can get the full path to
273 | * the current process from a symlink in there.
274 | */
275 |
276 | if (!retval && (access("/proc", F_OK) == 0))
277 | {
278 | retval = readSymLink("/proc/self/exe");
279 | if (!retval) retval = readSymLink("/proc/curproc/file");
280 | if (!retval) retval = readSymLink("/proc/curproc/exe");
281 | if (retval == NULL)
282 | {
283 | /* older kernels don't have /proc/self ... try PID version... */
284 | const unsigned long long pid = (unsigned long long) getpid();
285 | char path[64];
286 | const int rc = (int) snprintf(path,sizeof(path),"/proc/%llu/exe",pid);
287 | if ( (rc > 0) && (rc < sizeof(path)) )
288 | retval = readSymLink(path);
289 | } /* if */
290 | } /* if */
291 |
292 | if (retval != NULL) /* chop off filename. */
293 | {
294 | char *ptr = strrchr(retval, '/');
295 | if (ptr != NULL)
296 | *(ptr+1) = '\0';
297 | else /* shouldn't happen, but just in case... */
298 | {
299 | allocator.Free(retval);
300 | retval = NULL;
301 | } /* else */
302 | } /* if */
303 |
304 | /* No /proc/self/exe, etc, but we have an argv[0] we can parse? */
305 | if ((retval == NULL) && (argv0 != NULL))
306 | {
307 | /* fast path: default behaviour can handle this. */
308 | if (strchr(argv0, '/') != NULL)
309 | return NULL; /* higher level parses out real path from argv0. */
310 |
311 | /* If there's no dirsep on argv0, then look through $PATH for it. */
312 | envr = getenv("PATH");
313 | if (envr != NULL)
314 | {
315 | char *path = (char *) __PHYSFS_smallAlloc(strlen(envr) + 1);
316 | BAIL_IF(!path, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
317 | strcpy(path, envr);
318 | retval = findBinaryInPath(argv0, path);
319 | __PHYSFS_smallFree(path);
320 | } /* if */
321 | } /* if */
322 |
323 | if (retval != NULL)
324 | {
325 | /* try to shrink buffer... */
326 | char *ptr = (char *) allocator.Realloc(retval, strlen(retval) + 1);
327 | if (ptr != NULL)
328 | retval = ptr; /* oh well if it failed. */
329 | } /* if */
330 |
331 | return retval;
332 | } /* __PHYSFS_platformCalcBaseDir */
333 |
334 |
335 | char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
336 | {
337 | /*
338 | * We use XDG's base directory spec, even if you're not on Linux.
339 | * This isn't strictly correct, but the results are relatively sane
340 | * in any case.
341 | *
342 | * https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
343 | */
344 | const char *envr = getenv("XDG_DATA_HOME");
345 | const char *append = "/";
346 | char *retval = NULL;
347 | size_t len = 0;
348 |
349 | if (!envr)
350 | {
351 | /* You end up with "$HOME/.local/share/Game Name 2" */
352 | envr = __PHYSFS_getUserDir();
353 | BAIL_IF_ERRPASS(!envr, NULL); /* oh well. */
354 | append = ".local/share/";
355 | } /* if */
356 |
357 | len = strlen(envr) + strlen(append) + strlen(app) + 2;
358 | retval = (char *) allocator.Malloc(len);
359 | BAIL_IF(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
360 | snprintf(retval, len, "%s%s%s/", envr, append, app);
361 | return retval;
362 | } /* __PHYSFS_platformCalcPrefDir */
363 |
364 | #endif /* PHYSFS_PLATFORM_UNIX */
365 |
366 | /* end of physfs_platform_unix.c ... */
367 |
368 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------