# HG changeset patch
# User koda
# Date 1364929257 -7200
# Node ID c13ebed437cb4313a5dc14971833bdee050b2d14
# Parent 404ddce27b230641703a408a7d75099e0ee597dd# Parent 343d3f0d6a8630bd2b7310b2970abb10b49e0fcc
update webgl branch
diff -r 404ddce27b23 -r c13ebed437cb .hgignore
--- a/.hgignore Wed Feb 20 02:21:58 2013 +0100
+++ b/.hgignore Tue Apr 02 21:00:57 2013 +0200
@@ -31,7 +31,8 @@
glob:misc/liblua/Xcode/build/
glob:misc/libfreetype/Xcode/build/
glob:misc/libfreetype/Xcode-iOS/build/
-glob:misc/physfs/Xcode/build/
+glob:misc/libphysfs/Xcode/build/
+glob:misc/libphyslayer/Xcode/build/
glob:moc_*.cxx_parameters
relre:^release\/
glob:*.log
@@ -60,4 +61,7 @@
glob:*.depends
glob:tools/build_windows_koda.bat
glob:share/hedgewars/Data/misc/hwengine.desktop
-
+glob:*.exe
+glob:_CPack_Packages/
+glob:version_info.txt
+glob:*.tar.*
diff -r 404ddce27b23 -r c13ebed437cb CMakeLists.txt
--- a/CMakeLists.txt Wed Feb 20 02:21:58 2013 +0100
+++ b/CMakeLists.txt Tue Apr 02 21:00:57 2013 +0200
@@ -2,77 +2,97 @@
#initialise cmake environment
cmake_minimum_required(VERSION 2.6.0)
+if(CMAKE_VERSION VERSION_LESS "2.8")
+ set(WARNING "WARNING: ")
+ set(allow_parse_args FALSE)
+else()
+ set(WARNING WARNING)
+ set(allow_parse_args TRUE)
+endif()
foreach(hwpolicy CMP0003 CMP0012 CMP0017)
if(POLICY ${hwpolicy})
cmake_policy(SET ${hwpolicy} NEW)
endif()
endforeach()
-#use available modules, fallback to ours if not present (CMP0017 helps)
-set(CMAKE_MODULE_PATH "${CMAKE_ROOT}/Modules" "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules")
+
+set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake_modules")
-#usually this is set at release time
-option(NOREVISION "Build Hedgewars without revision information [default: off]" OFF)
+#possible cmake configuration
+option(NOSERVER "Disable gameServer build (off)]" OFF)
+option(NOPNG "Disable screenshoot compression (off)" OFF)
+option(NOVIDEOREC "Disable video recording (off)" OFF)
+
+#set this to ON when 2.1.0 becomes more widespread (and only for linux)
+option(SYSTEM_PHYSFS "Use system physfs (off)" OFF)
-#set other default values
-option(NOSERVER "Disable gameServer build [default: auto]" OFF)
-option(NOPNG "Disable screenshoot compression [default: auto]" OFF)
-option(NOVIDEOREC "Disable video recording [default: auto]" OFF)
+option(LIBENGINE "Enable hwengine library (off)" OFF)
+option(ANDROID "Enable Android build (off)" OFF)
+if(UNIX AND NOT APPLE)
+ option(MINIMAL_FLAGS "Respect system flags as much as possible (off)" OFF)
+else()
+ option(NOAUTOUPDATE "Disable OS X Sparkle update checking" OFF)
+endif()
option(WEBGL "Enable WebGL build (implies NOPASCAL) [default: off]" OFF)
option(NOPASCAL "Compile hwengine as native C [default: off]" ${WEBGL})
-option(LIBENGINE "Enable hwengine library [default: off]" OFF)
+option(GL2 "Enable OpenGL 2 rendering [default: off]" OFF)
-option(ANDROID "Enable Android build [default: off]" OFF)
-option(NOAUTOUPDATE "Disable OS X Sparkle update checking" OFF)
-option(MINIMAL_FLAGS "Respect system flags as much as possible [default: off]" OFF)
-option(GL2 "Enable OpenGL 2 rendering [default: off]" OFF)
set(FPFLAGS "" CACHE STRING "Additional Freepascal flags")
set(GHFLAGS "" CACHE STRING "Additional Haskell flags")
if(UNIX AND NOT APPLE)
set(DATA_INSTALL_DIR "share/hedgewars" CACHE STRING "Resource folder path")
endif()
-#detect Mercurial revision (if present)
-if(NOT ${NOREVISION})
- set(default_build_type "DEBUG")
- set(version_suffix "-development_version")
- set(HW_DEV true)
- find_program(HGCOMMAND hg)
- if(HGCOMMAND AND (EXISTS ${CMAKE_SOURCE_DIR}/.hg))
- execute_process(COMMAND ${HGCOMMAND} identify -in
- WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
- OUTPUT_VARIABLE internal_version
- ERROR_QUIET
- )
- #check local repo status
- string(REGEX REPLACE "[^+]" "" HGCHANGED ${internal_version})
+
+#detect Mercurial revision and init rev/hash information
+find_program(HGCOMMAND hg)
+if(HGCOMMAND AND (EXISTS ${CMAKE_SOURCE_DIR}/.hg))
+ execute_process(COMMAND ${HGCOMMAND} identify -in
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ OUTPUT_VARIABLE internal_version
+ ERROR_QUIET
+ )
+ #check local repo status
+ string(REGEX REPLACE "[^+]" "" HGCHANGED ${internal_version})
+ string(REGEX REPLACE "[0-9a-zA-Z]+(.*) ([0-9]+)(.*)" "\\2" HEDGEWARS_REVISION ${internal_version})
+ string(REGEX REPLACE "([0-9a-zA-Z]+)(.*) [0-9]+(.*)" "\\1" HEDGEWARS_HASH ${internal_version})
- string(REGEX REPLACE "[0-9a-zA-Z]+(.*) ([0-9]+)(.*)" "\\2" revision_number ${internal_version})
- string(REGEX REPLACE "([0-9a-zA-Z]+)(.*) [0-9]+(.*)" "\\1" revision_hash ${internal_version})
-
- message(STATUS "Building revision ${revision_number} from hash ${revision_hash} ${HGCHANGED}")
- if(HGCHANGED)
- MESSAGE(WARNING "Notice: you have uncommitted changes in your repository")
- endif()
- set(version_suffix "-${revision_number}${HGCHANGED}")
+ if(HGCHANGED)
+ message(${WARNING} "You have uncommitted changes in your repository!")
endif()
-else(NOT ${NOREVISION})
+ #let's assume that if you have hg you might be interested in debugging
+ set(default_build_type "DEBUG")
+ #write down hash and rev for easy picking should hg be missing
+ file(WRITE "${CMAKE_SOURCE_DIR}/share/version_info.txt" "Hedgewars versioning information, do not modify\nrev ${HEDGEWARS_REVISION}\nhash ${HEDGEWARS_HASH}\n")
+else()
set(default_build_type "RELEASE")
- set(HWDEV false)
- message(STATUS "Building distributable version")
-endif(NOT ${NOREVISION})
+ # when compiling outside rev control, fetch revision and hash information from version_info.txt
+ find_file(version_info version_info.txt PATH ${CMAKE_SOURCE_DIR}/share)
+ if(version_info)
+ file(STRINGS ${version_info} internal_version REGEX "rev")
+ string(REGEX REPLACE "rev ([0-9]*)" "\\1" HEDGEWARS_REVISION ${internal_version})
+ file(STRINGS ${version_info} internal_version REGEX "hash")
+ string(REGEX REPLACE "hash ([a-zA-Z0-9]*)" "\\1" HEDGEWARS_HASH ${internal_version})
+ else()
+ message(${WARNING} "${CMAKE_SOURCE_DIR}/share/version_info.txt not found, revision information "
+ "will be incorrect!!! Contact your source provider to fix this!")
+ set(HEDGEWARS_REVISION "0000")
+ set(HEDGEWARS_HASH "unknown")
+ endif()
+endif()
#versioning
set(CPACK_PACKAGE_VERSION_MAJOR 0)
set(CPACK_PACKAGE_VERSION_MINOR 9)
-set(CPACK_PACKAGE_VERSION_PATCH 19${version_suffix})
+set(CPACK_PACKAGE_VERSION_PATCH 19)
set(HEDGEWARS_PROTO_VER 44)
set(HEDGEWARS_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
set(required_clang_version 3.0)
+message(STATUS "Building ${HEDGEWARS_VERSION}-r${HEDGEWARS_REVISION} (${HEDGEWARS_HASH})")
if (${NOPASCAL})
find_package(Clang)
@@ -85,27 +105,36 @@
endif(${NOPASCAL})
+
+#where to build libs and bins
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
+#resource paths
if(UNIX AND NOT APPLE)
set(target_binary_install_dir "bin")
set(target_library_install_dir "lib")
- set(SHAREPATH "${DATA_INSTALL_DIR}/")
+
+ string(SUBSTRING "${DATA_INSTALL_DIR}" 0 1 sharepath_start)
+ if (NOT (${sharepath_start} MATCHES "/"))
+ set(HEDGEWARS_DATADIR "${CMAKE_INSTALL_PREFIX}/${DATA_INSTALL_DIR}/")
+ else()
+ set(HEDGEWARS_DATADIR "${DATA_INSTALL_DIR}/")
+ endif()
+ set(HEDGEWARS_FULL_DATADIR "${HEDGEWARS_DATADIR}")
else()
set(target_binary_install_dir "./")
if(APPLE)
+ set(target_library_install_dir "../Frameworks/")
set(CMAKE_INSTALL_PREFIX "Hedgewars.app/Contents/MacOS/")
- set(SHAREPATH "../Resources/")
- set(target_library_install_dir "../Frameworks/")
- else()
- if(WIN32)
- set(target_library_install_dir "./")
- set(SHAREPATH "./")
- set(CMAKE_PREFIX_PATH "${CMAKE_SOURCE_DIR}/misc/winutils/")
- link_directories("${EXECUTABLE_OUTPUT_PATH}" "${CMAKE_SOURCE_DIR}/misc/winutils/bin")
- endif(WIN32)
+ set(HEDGEWARS_DATADIR "../Resources/")
+ set(HEDGEWARS_FULL_DATADIR "/Applications/${CMAKE_INSTALL_PREFIX}/${HEDGEWARS_DATADIR}")
+ elseif(WIN32)
+ set(target_library_install_dir "./")
+ set(HEDGEWARS_DATADIR "./")
+ set(HEDGEWARS_FULL_DATADIR "${CMAKE_INSTALL_PREFIX}/")
+ link_directories("${EXECUTABLE_OUTPUT_PATH}" "${CMAKE_SOURCE_DIR}/misc/winutils/bin")
endif()
endif()
@@ -127,7 +156,7 @@
if(NOT minimum_macosx_version)
message(FATAL_ERROR "sw_vers not found! Need explicit MACOSX_DEPLOYMENT_TARGET variable set")
else()
- message(WARNING "sw_vers not found! Fallback to MACOSX_DEPLOYMENT_TARGET variable")
+ message(${WARNING} "sw_vers not found! Fallback to MACOSX_DEPLOYMENT_TARGET variable")
set(current_macosx_version ${minimum_macosx_version})
endif()
endif()
@@ -181,11 +210,6 @@
list(APPEND pascal_flags "-Ff~/Library/Frameworks")
#set deployment target
list(APPEND pascal_flags "-k-macosx_version_min" "-k${minimum_macosx_version}" "-XR${CMAKE_OSX_SYSROOT}")
-
- #silly libav that always brings in VideoDecoderAcceleration, avaible only from 10.6.3
- if(NOT NOVIDEOREC AND ${minimum_macosx_version} VERSION_LESS "10.6")
- set(WARNING "Video recording support before OS X 10.6 is experimental")
- endif()
endif(APPLE)
@@ -193,13 +217,14 @@
if (CMAKE_BUILD_TYPE)
string (TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE)
if ( NOT( (CMAKE_BUILD_TYPE MATCHES "RELEASE") OR (CMAKE_BUILD_TYPE MATCHES "DEBUG") ) )
- set (CMAKE_BUILD_TYPE ${default_build_type} CACHE STRING "Choose the build type, options are: Debug Release." FORCE)
+ set (CMAKE_BUILD_TYPE ${default_build_type} CACHE STRING "Build type (Debug/Release)" FORCE)
message (STATUS "Unknown build type, using default (${default_build_type})")
endif ()
else (CMAKE_BUILD_TYPE)
- set (CMAKE_BUILD_TYPE ${default_build_type} CACHE STRING "Choose the build type, options are: Debug Release." FORCE)
+ set (CMAKE_BUILD_TYPE ${default_build_type} CACHE STRING "Build type (Debug/Release)" FORCE)
endif (CMAKE_BUILD_TYPE)
+
#set default flags values for all projects (unless MINIMAL_FLAGS is true)
if(NOT ${MINIMAL_FLAGS})
set(CMAKE_C_FLAGS "-pipe ${CMAKE_C_FLAGS}")
@@ -216,39 +241,67 @@
set(CMAKE_CXX_FLAGS_DEBUG "-Wall -DDEBUG")
endif()
+#TODO: find out why we need this...
+include(CheckCCompilerFlag)
+set(CMAKE_REQUIRED_FLAGS "-Wl,-z -Wl,noexecstack")
+check_c_compiler_flag("" HAVE_NOEXECSTACK) #empty because we are testing a linker flag
+if(HAVE_NOEXECSTACK)
+ list(APPEND pascal_flags "-k-z" "-knoexecstack")
+ if(NOT ${MINIMAL_FLAGS})
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_REQUIRED_FLAGS}")
+ endif()
+endif()
+unset(CMAKE_REQUIRED_FLAGS)
+
#parse additional parameters
if(FPFLAGS OR GHFLAGS)
- set(cmake_version "${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}")
- if(cmake_version VERSION_LESS "2.8")
- message(WARNING "FPFLAGS and GHFLAGS are available only when using CMake >= 2.8")
+ if(${allow_parse_args})
+ message(${WARNING} "FPFLAGS and GHFLAGS are available only when using CMake >= 2.8")
else()
separate_arguments(fpflags_parsed UNIX_COMMAND ${FPFLAGS})
separate_arguments(ghflags_parsed UNIX_COMMAND ${GHFLAGS})
endif()
endif()
-list(APPEND pascal_flags ${fpflags_parsed} # user flags
- "-vm4079,4080,4081" # fpc output format
- "-B" # compile all units
- "-FE${PROJECT_BINARY_DIR}/bin" # fpc output directory
- "-Fl${PROJECT_BINARY_DIR}/bin" # fpc linking directory
- "-Cs2000000" # stack size
- "-vewnq" # fpc output verbosity
- "-dDEBUGFILE" # macro for engine output
+list(APPEND pascal_flags ${fpflags_parsed} # user flags
+ "-B" # compile all units
+ "-vm4079,4080,4081" # fpc verbosity output format
+ "-FE${PROJECT_BINARY_DIR}/bin" # fpc binaries output directory
+ "-FU${PROJECT_BINARY_DIR}/hedgewars" # fpc units output directory
+ "-Fl${PROJECT_BINARY_DIR}/bin" # fpc linking directory (win/unix)
+ "-Fi${PROJECT_BINARY_DIR}/hedgewars" # fpc .inc path (for out of source builds)
+ "-k-L${PROJECT_BINARY_DIR}/bin" # ld linking directory (unix/osx)
+ "-Cs2000000" # stack size
+ "-vewnq" # fpc output verbosity
+ "-dDEBUGFILE" # macro for engine output
)
-list(APPEND haskell_flags "-O2" ${ghflags_parsed})
+list(APPEND haskell_flags ${ghflags_parsed} # user flags
+ "-O2" # optimise for faster code
+ )
+
#get BUILD_TYPE and enable/disable optimisation
message(STATUS "Using ${CMAKE_BUILD_TYPE} configuration")
if(CMAKE_BUILD_TYPE MATCHES "DEBUG")
- list(APPEND pascal_flags "-O-" "-g" "-gl" "-gv")
- list(APPEND haskell_flags "-Wall" "-debug" "-dcore-lint" "-fno-warn-unused-do-bind")
+ list(APPEND pascal_flags "-O-" # disable all optimisations
+ "-g" # enable debug symbols
+ "-gl" # add line info to bt
+ "-gv" # allow valgrind
+ )
+ list(APPEND haskell_flags "-Wall" # all warnings
+ "-debug" # debug mode
+ "-dcore-lint" # internal sanity check
+ )
else()
-# set(pascal_flags "-O3" "-OpPENTIUM4" "-CfSSE3" "-Xs" "-Si" ${pascal_flags})
- list(APPEND pascal_flags "-Os" "-Xs" "-Si")
- list(APPEND haskell_flags "-w" "-fno-warn-unused-do-bind")
+ list(APPEND pascal_flags "-Os" # optimise for size
+ "-Xs" # strip binary
+ "-Si" # turn on inlining
+ )
+ list(APPEND haskell_flags "-w" # no warnings
+ )
endif()
+include(${CMAKE_MODULE_PATH}/utils.cmake)
#Haskell compiler discovery (for server and engine in c)
if((NOT NOSERVER) OR NOPASCAL)
@@ -290,16 +343,45 @@
endif()
-#physfs library (static on unix, dll on win32)
-add_subdirectory(misc/physfs)
-if(NOT WIN32)
- list(APPEND pascal_flags "-k${LIBRARY_OUTPUT_PATH}/libphysfs.a")
+#physfs discovery
+if (${SYSTEM_PHYSFS})
+ if (NOT PHYSFS_LIBRARY OR NOT PHYSFS_INCLUDE_DIR)
+ find_package(PhysFS)
+ endif()
+
+ find_file(physfs_h physfs.h ${PHYSFS_INCLUDE_DIR})
+ if(physfs_h)
+ file(STRINGS ${physfs_h} physfs_majorversion REGEX "PHYSFS_VER_MAJOR[\t' ']+[0-9]+")
+ file(STRINGS ${physfs_h} physfs_minorversion REGEX "PHYSFS_VER_MINOR[\t' ']+[0-9]+")
+ file(STRINGS ${physfs_h} physfs_patchversion REGEX "PHYSFS_VER_PATCH[\t' ']+[0-9]+")
+ string(REGEX MATCH "([0-9]+)" physfs_majorversion "${physfs_majorversion}")
+ string(REGEX MATCH "([0-9]+)" physfs_minorversion "${physfs_minorversion}")
+ string(REGEX MATCH "([0-9]+)" physfs_patchversion "${physfs_patchversion}")
+ set(physfs_detected_ver "${physfs_majorversion}.${physfs_minorversion}.${physfs_patchversion}")
+
+ if (physfs_detected_ver VERSION_LESS "2.1.0")
+ message(FATAL_ERROR "PhysFS version is too old (dected ${physfs_detected_ver}, required 2.1.0)")
+ set(physfs_too_old true)
+ endif()
+ endif()
+
+ if (NOT PHYSFS_LIBRARY OR NOT PHYSFS_INCLUDE_DIR)
+ message(FATAL_ERROR "Missing PhysFS! Rerun cmake with -DPHYSFS_SYSTEM=off to build the internal version")
+ endif()
+else()
+ message(STATUS "PhysFS will be provided by the bundled sources")
+ set(physfs_output_name "hw_physfs")
+ add_subdirectory(misc/libphysfs)
+ #-XLA is a beta fpc flag that renames libraries before passing them to the linker
+ #we also have to pass PHYSFS_INTERNAL to satisfy windows runtime requirements
+ #(should be harmless on other platforms)
+ list(APPEND pascal_flags "-XLAphysfs=${physfs_output_name}" "-dPHYSFS_INTERNAL")
endif()
+find_package_or_disable_msg(FFMPEG NOVIDEOREC "Video recording will not be built")
-#frontend library
-add_subdirectory(project_files/frontlib)
-
+#physfs helper library
+add_subdirectory(misc/libphyslayer)
if(NOPASCAL)
if (NOT ghc_executable)
@@ -317,102 +399,16 @@
#WEBGL deps
else(WEBGL)
#Android related build scripts
+ #TODO: when ANDROID, LIBENGINE should be set
if(ANDROID)
add_subdirectory(project_files/Android-build)
- endif()
-
- #TODO: when ANDROID, LIBENGINE should be set
- if(NOT ANDROID)
+ else(ANDROID)
add_subdirectory(bin)
add_subdirectory(QTfrontend)
add_subdirectory(share)
add_subdirectory(tools)
- endif()
+ endif(ANDROID)
endif(WEBGL)
-
-
-# CPack variables
-set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Hedgewars, a free turn-based strategy")
-set(CPACK_PACKAGE_VENDOR "Hedgewars Project")
-set(CPACK_PACKAGE_FILE_NAME "hedgewars-${HEDGEWARS_VERSION}")
-set(CPACK_SOURCE_PACKAGE_FILE_NAME "hedgewars-src-${HEDGEWARS_VERSION}")
-set(CPACK_SOURCE_GENERATOR "TBZ2")
-set(CPACK_PACKAGE_EXECUTABLES "hedgewars" "hedgewars")
-set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING")
-set(CPACK_PACKAGE_INSTALL_DIRECTORY "Hedgewars ${HEDGEWARS_VERSION}")
-
-if(WIN32 AND NOT UNIX)
- set(CPACK_NSIS_DISPLAY_NAME "Hedgewars")
- set(CPACK_NSIS_HELP_LINK "http://www.hedgewars.org/")
- set(CPACK_NSIS_URL_INFO_ABOUT "http://www.hedgewars.org/")
- set(CPACK_NSIS_CONTACT "unC0Rr@gmail.com")
- set(CPACK_NSIS_MODIFY_PATH OFF)
- set(CPACK_NSIS_EXECUTABLES_DIRECTORY "${target_binary_install_dir}")
- set(CPACK_GENERATOR "ZIP;NSIS")
- set(CPACK_PACKAGE_INSTALL_REGISTRY_KEY "hedgewars")
-else(WIN32 AND NOT UNIX)
- set(CPACK_STRIP_FILES "bin/hedgewars;bin/hwengine")
-endif(WIN32 AND NOT UNIX)
+include(${CMAKE_MODULE_PATH}/CPackConfig.cmake)
-set(CPACK_SOURCE_IGNORE_FILES
- "~"
- "\\\\.hg"
- "\\\\.svn"
- "\\\\.exe$"
- "\\\\.a$"
- "\\\\.dll$"
- "\\\\.xcf$"
- "\\\\.cxx$"
- "\\\\.db$"
- "\\\\.dof$"
- "\\\\.layout$"
- "\\\\.zip$"
- "\\\\.gz$"
- "\\\\.bz2$"
- "\\\\.tmp$"
- "\\\\.core$"
- "\\\\.sh$"
- "\\\\.sifz$"
- "\\\\.svg$"
- "\\\\.svgz$"
- "\\\\.ppu$"
- "\\\\.psd$"
- "\\\\.o$"
- "Makefile"
- "Doxyfile"
- "CMakeFiles"
- "debug"
- "release$"
- "Debug$"
- "Release$"
- "proto\\\\.inc$"
- "hwconsts\\\\.cpp$"
- "playlist\\\\.inc$"
- "CPack"
- "cmake_install\\\\.cmake$"
- "config\\\\.inc$"
- "hwengine\\\\.desktop$"
- "CMakeCache\\\\.txt$"
-# "^${CMAKE_CURRENT_SOURCE_DIR}/misc/libopenalbridge"
-# "^${CMAKE_CURRENT_SOURCE_DIR}/misc/libfreetype"
- "^${CMAKE_CURRENT_SOURCE_DIR}/misc/liblua"
-# "^${CMAKE_CURRENT_SOURCE_DIR}/misc/libtremor"
- "^${CMAKE_CURRENT_SOURCE_DIR}/project_files/HedgewarsMobile/"
- "^${CMAKE_CURRENT_SOURCE_DIR}/bin/[a-z]"
- "^${CMAKE_CURRENT_SOURCE_DIR}/tools/templates"
- "^${CMAKE_CURRENT_SOURCE_DIR}/doc"
- "^${CMAKE_CURRENT_SOURCE_DIR}/templates"
- "^${CMAKE_CURRENT_SOURCE_DIR}/Graphics"
- "^${CMAKE_CURRENT_SOURCE_DIR}/realtest"
- "^${CMAKE_CURRENT_SOURCE_DIR}/tmp"
- "^${CMAKE_CURRENT_SOURCE_DIR}/utils"
- "^${CMAKE_CURRENT_SOURCE_DIR}/share/hedgewars/Data/Maps/test"
- "^${CMAKE_CURRENT_SOURCE_DIR}/share/hedgewars/Data/Themes/ethereal"
- "^${CMAKE_CURRENT_SOURCE_DIR}/install_manifest.txt"
- "^${CMAKE_CURRENT_SOURCE_DIR}/CMakeCache.txt"
- "^${CMAKE_CURRENT_SOURCE_DIR}/hedgewars\\\\."
-)
-
-include(CPack)
-
diff -r 404ddce27b23 -r c13ebed437cb CREDITS
--- a/CREDITS Wed Feb 20 02:21:58 2013 +0100
+++ b/CREDITS Tue Apr 02 21:00:57 2013 +0200
@@ -6,6 +6,13 @@
- see Fonts_LICENSE.txt
==========
+= FORTS
+==========
+- Carlos Vives -> Tank (2010)
+- Dragonfly -> EvilChicken (2010)
+- Randy Broda -> SteelTower (2013)
+
+==========
= HATS
==========
- Robinator -> Terminator (2010)
@@ -66,4 +73,4 @@
http://www.freesound.org/people/Jovica/sounds/38317/
-ALL OTHER CONTENT IS PROPERTY OF Andrey Korotaev UNLESS OTHERWISE SPECIFIED
\ No newline at end of file
+ALL OTHER CONTENT IS PROPERTY OF Andrey Korotaev UNLESS OTHERWISE SPECIFIED
diff -r 404ddce27b23 -r c13ebed437cb INSTALL
--- a/INSTALL Wed Feb 20 02:21:58 2013 +0100
+++ b/INSTALL Tue Apr 02 21:00:57 2013 +0200
@@ -8,7 +8,7 @@
- SDL_image >= 1.2
- SDL_ttf >= 2.0
- Lua >= 5.1.0
- - Physfs >= 2.1
+ - Physfs >= 2.1.0
For server:
- Glasgow Haskell Compiler >= 6.10
- bytestring-show package
@@ -22,6 +22,8 @@
Lua will be automatically built if not found.
+PhysFS will internally built unless -DPHYSFS_SYSTEM=on is passed to cmake
+(also allows to set PHYSFS_LIBRARY and PHYSFS_INCLUDE_DIR if needed).
1. Configure:
$ cmake .
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/CMakeLists.txt
--- a/QTfrontend/CMakeLists.txt Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/CMakeLists.txt Tue Apr 02 21:00:57 2013 +0200
@@ -15,12 +15,11 @@
find_package(SDL REQUIRED) #video in SDLInteraction
find_package(SDL_mixer REQUIRED) #audio in SDLInteraction
-find_package(SDL_net REQUIRED) #network frontlib
-if(NOT NOVIDEOREC)
- find_package(FFMPEG)
- if(${FFMPEG_FOUND})
- add_definitions(-DVIDEOREC -D__STDC_CONSTANT_MACROS)
- endif()
+
+if(${FFMPEG_FOUND})
+ add_definitions(-DVIDEOREC -D__STDC_CONSTANT_MACROS)
+ include_directories(${FFMPEG_INCLUDE_DIR})
+ list(APPEND HW_LINK_LIBS ${FFMPEG_LIBRARIES})
endif()
# server messages localization
@@ -56,22 +55,15 @@
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/util/platform)
include_directories(${SDL_INCLUDE_DIR})
include_directories(${SDLMIXER_INCLUDE_DIR})
-include_directories(${FFMPEG_INCLUDE_DIR})
-include_directories(${CMAKE_SOURCE_DIR}/misc/physfs/src)
-include_directories(${CMAKE_SOURCE_DIR}/misc/physfs/extras)
+include_directories(${PHYSFS_INCLUDE_DIR})
+include_directories(${PHYSLAYER_INCLUDE_DIR})
+
+
if(UNIX)
# HACK: in freebsd cannot find iconv.h included via SDL.h
include_directories("/usr/local/include")
endif(UNIX)
-#directory for resources, relative to bindir (on linux an absolute path is always used)
-string(SUBSTRING "${SHAREPATH}" 0 1 sharepath_start)
-if(APPLE OR WIN32 OR ${sharepath_start} MATCHES "/")
- set(HEDGEWARS_DATADIR ${SHAREPATH})
-else()
- set(HEDGEWARS_DATADIR ${CMAKE_INSTALL_PREFIX}/${SHAREPATH})
-endif()
-
#only the cocoa version of qt supports building 64 bit apps
if(APPLE AND (CMAKE_OSX_ARCHITECTURES MATCHES "x86_64*") AND (NOT QT_MAC_USE_COCOA))
message(FATAL_ERROR "Building the 64 bit version of Hedgewars *requires* the Cocoa variant of QT on Mac OS X")
@@ -138,7 +130,6 @@
team.h
util/DataManager.h
util/LibavInteraction.h
- util/MessageDialog.h
)
set(hwfr_hdrs
@@ -175,14 +166,13 @@
util/platform/M3InstallController.m
util/platform/NSWorkspace_RBAdditions.m
)
- if(NOT NOAUTOUPDATE)
- find_package(Sparkle)
- if(SPARKLE_FOUND)
- add_definitions(-DSPARKLE_ENABLED)
- list(APPEND hwfr_src util/platform/AutoUpdater.cpp
- util/platform/SparkleAutoUpdater.mm)
- list(APPEND HW_LINK_LIBS ${SPARKLE_LIBRARY})
- endif()
+ include(${CMAKE_MODULE_PATH}/utils.cmake)
+ find_package_or_disable_msg(Sparkle NOAUTOUPDATE "Autoupdater will not be built.")
+ if(SPARKLE_FOUND)
+ add_definitions(-DSPARKLE_ENABLED)
+ list(APPEND hwfr_src util/platform/AutoUpdater.cpp
+ util/platform/SparkleAutoUpdater.mm)
+ list(APPEND HW_LINK_LIBS ${SPARKLE_LIBRARY})
endif()
endif()
@@ -209,11 +199,11 @@
endif()
list(APPEND HW_LINK_LIBS
- physfs
+ ${PHYSFS_LIBRARY}
+ ${PHYSLAYER_LIBRARY}
${QT_LIBRARIES}
${SDL_LIBRARY}
${SDLMIXER_LIBRARY}
- ${FFMPEG_LIBRARIES}
)
if(WIN32 AND NOT UNIX)
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/HWApplication.cpp
--- a/QTfrontend/HWApplication.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/HWApplication.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -1,6 +1,6 @@
/*
* Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2012 Andrey Korotaev
+ * Copyright (c) 2012 Vittorio Giovara
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,30 +18,84 @@
#include "HWApplication.h"
#include
+#include
#include "hwform.h"
+#include "MessageDialog.h"
-HWApplication::HWApplication(int &argc, char **argv):
+#if !defined(Q_WS_WIN)
+#include "signal.h"
+#endif
+
+#if !defined(Q_WS_WIN)
+void terminateFrontend(int signal)
+{
+ Q_UNUSED(signal);
+ QCoreApplication::exit(0);
+}
+#endif
+
+HWApplication::HWApplication(int &argc, char **argv) :
QApplication(argc, argv)
{
+#if !defined(Q_WS_WIN)
+ signal(SIGINT, &terminateFrontend);
+#endif
+#if 0
+ qDebug("%s called with", argv[0]);
+ for (int i = 1; i < argc; i++)
+ qDebug("%d: %s", i, argv[i]);
+#endif
+ // on Windows, sending an event right away leads to a segfault
+ // so we use urlString to save the data and send the event just before the app.exec()
+ urlString = NULL;
+ if (argc > 1) {
+ urlString = new QString(argv[1]);
+ if (urlString->contains("//", Qt::CaseInsensitive) == false) {
+ delete urlString;
+ urlString = NULL;
+ }
+ }
+}
+void HWApplication::fakeEvent()
+{
+ QUrl parsedUrl(*urlString);
+ delete urlString;
+ urlString = NULL;
+ QFileOpenEvent *openEvent = new QFileOpenEvent(parsedUrl);
+ QCoreApplication::sendEvent(QCoreApplication::instance(), openEvent);
}
bool HWApplication::event(QEvent *event)
{
QFileOpenEvent *openEvent;
+ QString scheme, path, address;
- switch (event->type())
- {
- case QEvent::FileOpen:
- openEvent = (QFileOpenEvent *)event;
- if (form) form->PlayDemoQuick(openEvent->file());
+ if (event->type() == QEvent::FileOpen) {
+ openEvent = (QFileOpenEvent *)event;
+ scheme = openEvent->url().scheme();
+ path = openEvent->url().path();
+ address = openEvent->url().host();
+
+ QFile file(path);
+ if (scheme == "file" && file.exists()) {
+ form->PlayDemoQuick(path);
return true;
- break;
- default:
- return QApplication::event(event);
- break;
+ } else if (scheme == "hwplay") {
+ int port = openEvent->url().port(NETGAME_DEFAULT_PORT);
+ if (address == "")
+ address = NETGAME_DEFAULT_SERVER;
+ form->NetConnectQuick(address, (quint16) port);
+ return true;
+ } else {
+ const QString errmsg = tr("Scheme '%1' not supported").arg(scheme);
+ MessageDialog::ShowErrorMessage(errmsg, form);
+ return false;
+ }
}
+
+ return QApplication::event(event);
}
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/HWApplication.h
--- a/QTfrontend/HWApplication.h Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/HWApplication.h Tue Apr 02 21:00:57 2013 +0200
@@ -1,6 +1,6 @@
/*
* Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2012 Andrey Korotaev
+ * Copyright (c) 2012 Vittorio Giovara
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,10 +20,9 @@
#define HWAPP_H
#include
-#include
-#include
class HWForm;
+class QEvent;
/**
* @brief Main class of the Qt application.
@@ -41,6 +40,8 @@
~HWApplication() {};
HWForm *form;
+ QString *urlString;
+ void fakeEvent();
protected:
bool event(QEvent *);
};
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/game.cpp
--- a/QTfrontend/game.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/game.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -313,9 +313,8 @@
default:
{
if (gameType == gtNet && !netSuspend)
- {
- emit SendNet(msg);
- }
+ m_netSendBuffer.append(msg);
+
demo.append(msg);
}
}
@@ -344,6 +343,18 @@
readbuffer.remove(0, msglen + 1);
ParseMessage(msg);
}
+
+ flushNetBuffer();
+}
+
+void HWGame::flushNetBuffer()
+{
+ if(m_netSendBuffer.size())
+ {
+ emit SendNet(m_netSendBuffer);
+
+ m_netSendBuffer.clear();
+ }
}
QStringList HWGame::getArguments()
@@ -478,7 +489,7 @@
void HWGame::sendCampaignVar(const QByteArray &varToSend)
{
QString varToFind(varToSend);
- QSettings teamfile(cfgdir->absolutePath() + "/Teams/" + campaignTeam + ".hwt", QSettings::IniFormat, 0);
+ QSettings teamfile(QString("physfs://Teams/%1.hwt").arg(campaignTeam), QSettings::IniFormat, 0);
teamfile.setIniCodec("UTF-8");
QString varValue = teamfile.value("Campaign " + campaign + "/" + varToFind, "").toString();
QByteArray command;
@@ -495,7 +506,7 @@
QString varToWrite = QString::fromUtf8(varVal.left(i));
QString varValue = QString::fromUtf8(varVal.mid(i + 1));
- QSettings teamfile(cfgdir->absolutePath() + "/Teams/" + campaignTeam + ".hwt", QSettings::IniFormat, 0);
+ QSettings teamfile(QString("physfs://Teams/%1.hwt").arg(campaignTeam), QSettings::IniFormat, 0);
teamfile.setIniCodec("UTF-8");
teamfile.setValue("Campaign " + campaign + "/" + varToWrite, varValue);
}
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/game.h
--- a/QTfrontend/game.h Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/game.h Tue Apr 02 21:00:57 2013 +0200
@@ -102,6 +102,7 @@
GameCFGWidget * gamecfg;
TeamSelWidget* m_pTeamSelWidget;
GameType gameType;
+ QByteArray m_netSendBuffer;
void addKeyBindings(QByteArray * buf);
void commonConfig();
@@ -114,6 +115,7 @@
void SetGameState(GameState state);
void sendCampaignVar(const QByteArray & varToSend);
void writeCampaignVar(const QByteArray &varVal);
+ void flushNetBuffer();
};
#endif
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/gameuiconfig.cpp
--- a/QTfrontend/gameuiconfig.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/gameuiconfig.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -130,10 +130,10 @@
delete netHost;
netHost = new QString(value("net/ip", "").toString());
- netPort = value("net/port", 46631).toUInt();
+ netPort = value("net/port", NETGAME_DEFAULT_PORT).toUInt();
Form->ui.pageNetServer->leServerDescr->setText(value("net/servername", "hedgewars server").toString());
- Form->ui.pageNetServer->sbPort->setValue(value("net/serverport", 46631).toUInt());
+ Form->ui.pageNetServer->sbPort->setValue(value("net/serverport", NETGAME_DEFAULT_PORT).toUInt());
Form->ui.pageOptions->CBShowFPS->setChecked(value("fps/show", false).toBool());
Form->ui.pageOptions->fpsedit->setValue(value("fps/limit", 27).toUInt());
@@ -217,12 +217,12 @@
void GameUIConfig::resizeToConfigValues()
{
// fill 2/3 of the screen desktop
- const QRect deskSize = QApplication::desktop()->screenGeometry(-1);
+ const QRect deskSize = HWApplication::desktop()->screenGeometry(-1);
Form->resize(value("frontend/width", qMin(qMax(deskSize.width()*2/3,800),deskSize.width())).toUInt(),
value("frontend/height", qMin(qMax(deskSize.height()*2/3,600),deskSize.height())).toUInt());
// move the window to the center of the screen
- QPoint center = QApplication::desktop()->availableGeometry(-1).center();
+ QPoint center = HWApplication::desktop()->availableGeometry(-1).center();
center.setX(center.x() - (Form->width()/2));
center.setY(center.y() - (Form->height()/2));
Form->move(center);
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/hwconsts.cpp.in
--- a/QTfrontend/hwconsts.cpp.in Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/hwconsts.cpp.in Tue Apr 02 21:00:57 2013 +0200
@@ -19,10 +19,15 @@
#include
#include "hwconsts.h"
+#include "weapons.h"
+// cDataDir gets 'Data' appended later (in main.cpp)
+QString * cDataDir = new QString("${HEDGEWARS_DATADIR}");
QString * cProtoVer = new QString("${HEDGEWARS_PROTO_VER}");
-QString * cDataDir = new QString("${HEDGEWARS_DATADIR}");
QString * cVersionString = new QString("${HEDGEWARS_VERSION}");
+QString * cRevisionString = new QString("${HEDGEWARS_REVISION}");
+QString * cHashString = new QString("${HEDGEWARS_HASH}");
+
QDir * bindir = new QDir();
QDir * cfgdir = new QDir();
@@ -59,6 +64,9 @@
<< qMakePair(QString("Thinking with Portals"), QString(
AMMOLINE_PORTALS_QT AMMOLINE_PORTALS_PROB
AMMOLINE_PORTALS_DELAY AMMOLINE_PORTALS_CRATE ))
+ << qMakePair(QString("One of Everything"), QString(
+ AMMOLINE_ONEEVERY_QT AMMOLINE_ONEEVERY_PROB
+ AMMOLINE_ONEEVERY_DELAY AMMOLINE_ONEEVERY_CRATE ))
;
unsigned int colors[] = HW_TEAMCOLOR_ARRAY;
@@ -66,8 +74,5 @@
QString * netHost = new QString();
quint16 netPort = NETGAME_DEFAULT_PORT;
-bool haveServer = ${HAVE_NETSERVER};
-bool isDevBuild = ${HW_DEV};
-
int season = SEASON_NONE;
int years_since_foundation = 0;
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/hwconsts.h
--- a/QTfrontend/hwconsts.h Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/hwconsts.h Tue Apr 02 21:00:57 2013 +0200
@@ -25,6 +25,8 @@
extern QString * cProtoVer;
extern QString * cVersionString;
+extern QString * cRevisionString;
+extern QString * cHashString;
extern QString * cDataDir;
extern QDir * bindir;
@@ -48,8 +50,6 @@
extern QString * netHost;
extern quint16 netPort;
-extern bool haveServer;
-extern bool isDevBuild;
//Current season, SEASON_NONE by default
extern int season;
@@ -60,42 +60,6 @@
#endif
-#define HEDGEHOGS_PER_TEAM 8
-
-#define AMMOLINE_DEFAULT_QT "9391929422199121032235111001201000000211110101011111101"
-#define AMMOLINE_DEFAULT_PROB "0405040541600655546554464776576666666155510101115411101"
-#define AMMOLINE_DEFAULT_DELAY "0000000000000205500000040007004000000000220000000600000"
-#define AMMOLINE_DEFAULT_CRATE "1311110312111111123114111111111111111211111101111111101"
-
-#define AMMOLINE_CRAZY_QT "9999999999999999992999999999999999299999999909999992909"
-#define AMMOLINE_CRAZY_PROB "1111110111111111111111111111111111111111111101111111101"
-#define AMMOLINE_CRAZY_DELAY "0000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_CRAZY_CRATE "1311110312111111123114111111111111111211110101111111101"
-
-#define AMMOLINE_PROMODE_QT "9090009000000000000009000000000000000000000000000000000"
-#define AMMOLINE_PROMODE_PROB "0000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_PROMODE_DELAY "0000000000000205500000040007004000000000200000000000002"
-#define AMMOLINE_PROMODE_CRATE "1111111111111111111111111111111111111111100101111111101"
-
-#define AMMOLINE_SHOPPA_QT "0000009900000000000000000000000000000000000000000000000"
-#define AMMOLINE_SHOPPA_PROB "4444410044244402210112121222422000000002000400010011001"
-#define AMMOLINE_SHOPPA_DELAY "0000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_SHOPPA_CRATE "1111111111111111111111111111111111111111101101111111001"
-
-#define AMMOLINE_CLEAN_QT "1010009000010000011000000000000000000000000000001000000"
-#define AMMOLINE_CLEAN_PROB "0405040541600655546554464776576666666155510101115411101"
-#define AMMOLINE_CLEAN_DELAY "0000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_CLEAN_CRATE "1311110312111111123114111111111111111211111101111111101"
-
-#define AMMOLINE_MINES_QT "0000009900090000000300000000000000000000000000000000000"
-#define AMMOLINE_MINES_PROB "0000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_MINES_DELAY "0000000000000205500000040007004000000000200000000600000"
-#define AMMOLINE_MINES_CRATE "1111111111111111111111111111111111111111111101111111101"
-
-#define AMMOLINE_PORTALS_QT "9000009002000000002100000000000000110000090000000000000"
-#define AMMOLINE_PORTALS_PROB "0405040541600655546554464776576666666155510101115411101"
-#define AMMOLINE_PORTALS_DELAY "0000000000000205500000040007004000000000200000000600000"
-#define AMMOLINE_PORTALS_CRATE "1311110312111111123114111111111111111211111101111111101"
//Different seasons; assigned to season (int)
#define SEASON_NONE 0
@@ -103,7 +67,9 @@
#define SEASON_HWBDAY 4
#define SEASON_EASTER 8
+#define NETGAME_DEFAULT_SERVER "netserver.hedgewars.org"
#define NETGAME_DEFAULT_PORT 46631
+#define HEDGEHOGS_PER_TEAM 8
// see http://en.wikipedia.org/wiki/List_of_colors
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/hwform.cpp
--- a/QTfrontend/hwform.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/hwform.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -155,6 +155,7 @@
playerHash = QString(QCryptographicHash::hash(config->value("net/nick","").toString().toUtf8(), QCryptographicHash::Md5).toHex());
ui.pageRoomsList->setSettings(config);
+ ui.pageNetGame->setSettings(config);
ui.pageNetGame->chatWidget->setSettings(config);
ui.pageRoomsList->chatWidget->setSettings(config);
ui.pageOptions->setConfig(config);
@@ -349,6 +350,7 @@
}
}
+ ui.Pages->setCurrentIndex(ID_PAGE_INFO);
PagesStack.push(ID_PAGE_MAIN);
((AbstractPage*)ui.Pages->widget(ID_PAGE_MAIN))->triggerPageEnter();
GoBack();
@@ -359,7 +361,7 @@
{
if(hwnet && (hwnet->clientState() != HWNewNet::Disconnected))
{
- xfire_setvalue(XFIRE_SERVER, !hwnet->getHost().compare("netserver.hedgewars.org:46631") ? "Official server" : hwnet->getHost().toAscii());
+ xfire_setvalue(XFIRE_SERVER, !hwnet->getHost().compare(QString("%1:%2").arg(NETGAME_DEFAULT_SERVER).arg(NETGAME_DEFAULT_PORT)) ? "Official server" : hwnet->getHost().toAscii());
switch(hwnet->clientState())
{
case HWNewNet::Connecting: // Connecting
@@ -992,21 +994,27 @@
void HWForm::PlayDemoQuick(const QString & demofilename)
{
- if (game && game->gameState == gsStarted) return;
- GoBack(); //needed to cleanly disconnect from netgame
GoToPage(ID_PAGE_MAIN);
+ //GoBack() <- don't or you'll close the socket
CreateGame(0, 0, 0);
game->PlayDemo(demofilename, false);
}
+void HWForm::NetConnectQuick(const QString & host, quint16 port)
+{
+ GoToPage(ID_PAGE_MAIN);
+ NetConnectServer(host, port);
+}
+
void HWForm::NetConnectServer(const QString & host, quint16 port)
{
+ qDebug("connecting to %s:%d", qPrintable(host), port);
_NetConnect(host, port, ui.pageOptions->editNetNick->text().trimmed());
}
void HWForm::NetConnectOfficialServer()
{
- NetConnectServer("netserver.hedgewars.org", 46631);
+ NetConnectServer(NETGAME_DEFAULT_SERVER, NETGAME_DEFAULT_PORT);
}
void HWForm::NetPassword(const QString & nick)
@@ -1096,10 +1104,14 @@
if (!ok || newNick.isEmpty())
{
//ForcedDisconnect(tr("No nickname supplied."));
- bool retry = RetryDialog(tr("Hedgewars - Empty nickname"), tr("No nickname supplied."));
- GoBack();
+ bool retry = RetryDialog(tr("Hedgewars - Empty nickname"), tr("No nickname supplied."));
+ GoBack();
if (retry) {
- NetConnectOfficialServer();
+ if (hwnet->m_private_game) {
+ QStringList list = hwnet->getHost().split(":");
+ NetConnectServer(list.at(0), list.at(1).toShort());
+ } else
+ NetConnectOfficialServer();
}
return;
}
@@ -1182,18 +1194,18 @@
{
Q_UNUSED(nick);
- if(hwnet)
- {
+ if (hwnet) {
+ // destroy old connection
hwnet->Disconnect();
delete hwnet;
- hwnet=0;
+ hwnet = NULL;
}
hwnet = new HWNewNet();
GoToPage(ID_PAGE_CONNECTING);
- connect(hwnet, SIGNAL(AskForRunGame()), this, SLOT(CreateNetGame()));
+ connect(hwnet, SIGNAL(AskForRunGame()), this, SLOT(CreateNetGame()), Qt::QueuedConnection);
connect(hwnet, SIGNAL(connected()), this, SLOT(NetConnected()), Qt::QueuedConnection);
connect(hwnet, SIGNAL(Error(const QString&)), this, SLOT(NetError(const QString&)), Qt::QueuedConnection);
connect(hwnet, SIGNAL(Warning(const QString&)), this, SLOT(NetWarning(const QString&)), Qt::QueuedConnection);
@@ -1237,6 +1249,8 @@
this, SLOT(NetGameChangeStatus(bool)), Qt::QueuedConnection);
// net page stuff
+ connect(hwnet, SIGNAL(roomNameUpdated(const QString &)),
+ ui.pageNetGame, SLOT(setRoomName(const QString &)), Qt::QueuedConnection);
connect(hwnet, SIGNAL(chatStringFromNet(const QString&)),
ui.pageNetGame->chatWidget, SLOT(onChatString(const QString&)), Qt::QueuedConnection);
@@ -1278,7 +1292,7 @@
connect(hwnet, SIGNAL(chatStringLobby(const QString&)),
ui.pageRoomsList->chatWidget, SLOT(onChatString(const QString&)), Qt::QueuedConnection);
connect(hwnet, SIGNAL(chatStringLobby(const QString&, const QString&)),
- ui.pageRoomsList->chatWidget, SLOT(onChatString(const QString&, const QString&)));
+ ui.pageRoomsList->chatWidget, SLOT(onChatString(const QString&, const QString&)), Qt::QueuedConnection);
connect(hwnet, SIGNAL(chatStringFromMeLobby(const QString&)),
ui.pageRoomsList->chatWidget, SLOT(onChatString(const QString&)), Qt::QueuedConnection);
@@ -1328,8 +1342,22 @@
connect(ui.pageNetGame->pGameCFG, SIGNAL(paramChanged(const QString &, const QStringList &)), hwnet, SLOT(onParamChanged(const QString &, const QStringList &)));
connect(hwnet, SIGNAL(configAsked()), ui.pageNetGame->pGameCFG, SLOT(fullNetConfig()));
-//nick and pass stuff
+ //nick and pass stuff
+ QString nickname = config->value("net/nick", "").toString();
+
+ hwnet->m_private_game = !(hostName == NETGAME_DEFAULT_SERVER && port == NETGAME_DEFAULT_PORT);
+ if (hwnet->m_private_game == false)
+ if (AskForNickAndPwd() != 0)
+ return;
+ ui.pageRoomsList->setUser(nickname);
+ ui.pageNetGame->setUser(nickname);
+
+ hwnet->Connect(hostName, port, nickname);
+}
+
+int HWForm::AskForNickAndPwd(void)
+{
//remove temppasswordhash just in case
config->clearTempHash();
@@ -1360,7 +1388,7 @@
if (pwDialog->exec() != QDialog::Accepted) {
delete pwDialog;
GoBack();
- return;
+ return -1;
}
//set nick and pass from the dialog
@@ -1373,9 +1401,13 @@
GoBack();
delete pwDialog;
if (retry) {
- NetConnectOfficialServer();
- }
- return;
+ if (hwnet->m_private_game) {
+ QStringList list = hwnet->getHost().split(":");
+ NetConnectServer(list.at(0), list.at(1).toShort());
+ } else
+ NetConnectOfficialServer();
+ }
+ return -1;
}
if (!password.isEmpty()) {
@@ -1412,15 +1444,9 @@
nickname = config->value("net/nick", "").toString();
}
}
-
- ui.pageRoomsList->setUser(nickname);
- ui.pageNetGame->setUser(nickname);
-
- hwnet->Connect(hostName, port, nickname);
+ return 0;
}
-
-
void HWForm::NetConnect()
{
HWHostPortDialog * hpd = new HWHostPortDialog(this);
@@ -1488,7 +1514,11 @@
if (reason == "Reconnected too fast") { //TODO: this is a hack, which should be remade
bool retry = RetryDialog(tr("Hedgewars - Connection error"), tr("You reconnected too fast.\nPlease wait a few seconds and try again."));
if (retry) {
- NetConnectOfficialServer();
+ if (hwnet->m_private_game) {
+ QStringList list = hwnet->getHost().split(":");
+ NetConnectServer(list.at(0), list.at(1).toShort());
+ } else
+ NetConnectOfficialServer();
}
else {
while (ui.Pages->currentIndex() != ID_PAGE_NET
@@ -1501,8 +1531,7 @@
}
if (pnetserver)
return; // we have server - let it care of all things
- if (hwnet)
- {
+ if (hwnet) {
QString errorStr = QMessageBox::tr("Connection to server is lost") + (reason.isEmpty()?"":("\n\n" + HWNewNet::tr("Quit reason: ") + '"' + reason +'"'));
MessageDialog::ShowErrorMessage(errorStr, this);
}
@@ -1621,9 +1650,7 @@
QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm") :
"LastRound";
- QStringList versionParts = cVersionString->split('-');
- if ( (versionParts.size() == 2) && (!versionParts[1].isEmpty()) && (versionParts[1].contains(':')) )
- recordFileName = recordFileName + "_" + versionParts[1].replace(':','-');
+ recordFileName += "_" + *cRevisionString + "-" + *cHashString;
if (type == rtDemo)
{
@@ -1727,6 +1754,7 @@
ui.pageNetGame->setMasterMode(true);
ui.pageNetGame->restrictJoins->setChecked(false);
ui.pageNetGame->restrictTeamAdds->setChecked(false);
+ ui.pageNetGame->restrictUnregistered->setChecked(false);
ui.pageNetGame->pGameCFG->GameSchemes->setModel(ammoSchemeModel);
ui.pageNetGame->pGameCFG->setMaster(true);
ui.pageNetGame->pNetTeamsWidget->setInteractivity(true);
@@ -1739,6 +1767,7 @@
ui.pageNetGame->leRoomName->disconnect(hwnet);
ui.pageNetGame->restrictJoins->disconnect(hwnet);
ui.pageNetGame->restrictTeamAdds->disconnect(hwnet);
+ ui.pageNetGame->restrictUnregistered->disconnect(hwnet);
ui.pageNetGame->disconnect(hwnet, SLOT(updateRoomName(const QString&)));
ui.pageNetGame->setRoomName(hwnet->getRoom());
@@ -1747,6 +1776,7 @@
connect(ui.pageNetGame, SIGNAL(askForUpdateRoomName(const QString &)), hwnet, SLOT(updateRoomName(const QString &)));
connect(ui.pageNetGame->restrictJoins, SIGNAL(triggered()), hwnet, SLOT(toggleRestrictJoins()));
connect(ui.pageNetGame->restrictTeamAdds, SIGNAL(triggered()), hwnet, SLOT(toggleRestrictTeamAdds()));
+ connect(ui.pageNetGame->restrictUnregistered, SIGNAL(triggered()), hwnet, SLOT(toggleRegisteredOnly()));
connect(ui.pageNetGame->pGameCFG->GameSchemes->model(),
SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
ui.pageNetGame->pGameCFG,
@@ -1855,8 +1885,8 @@
QString HWForm::getDemoArguments()
{
- QString prefix = datadir->absolutePath();
- QString userPrefix = cfgdir->absolutePath();
+ QString prefix = "\"" + datadir->absolutePath() + "\"";
+ QString userPrefix = "\"" + cfgdir->absolutePath() + "\"";
#ifdef Q_WS_WIN
prefix = prefix.replace("/","\\");
userPrefix = userPrefix.replace("/","\\");
@@ -1886,14 +1916,22 @@
QString arguments = getDemoArguments();
#ifdef _WIN32
QSettings registry_hkcr("HKEY_CLASSES_ROOT", QSettings::NativeFormat);
+
+ // file extension(s)
registry_hkcr.setValue(".hwd/Default", "Hedgewars.Demo");
registry_hkcr.setValue(".hws/Default", "Hedgewars.Save");
registry_hkcr.setValue("Hedgewars.Demo/Default", tr("Hedgewars Demo File", "File Types"));
registry_hkcr.setValue("Hedgewars.Save/Default", tr("Hedgewars Save File", "File Types"));
registry_hkcr.setValue("Hedgewars.Demo/DefaultIcon/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hwdfile.ico\",0");
registry_hkcr.setValue("Hedgewars.Save/DefaultIcon/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hwsfile.ico\",0");
- registry_hkcr.setValue("Hedgewars.Demo/Shell/Open/Command/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hwengine.exe\" \"%1\" "+arguments);
- registry_hkcr.setValue("Hedgewars.Save/Shell/Open/Command/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hwengine.exe\" \"%1\" "+arguments);
+ registry_hkcr.setValue("Hedgewars.Demo/Shell/Open/Command/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hwengine.exe\" " + arguments + " %1");
+ registry_hkcr.setValue("Hedgewars.Save/Shell/Open/Command/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hwengine.exe\" " + arguments + " %1");
+
+ // custom url scheme(s)
+ registry_hkcr.setValue("hwplay/Default", "\"URL:Hedgewars ServerAccess Scheme\"");
+ registry_hkcr.setValue("hwplay/URL Protocol", "");
+ registry_hkcr.setValue("hwplay/DefaultIcon/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hedgewars.exe\",0");
+ registry_hkcr.setValue("hwplay/Shell/Open/Command/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hedgewars.exe\" %1");
#elif defined __APPLE__
// only useful when other apps have taken precedence over our file extensions and you want to reset it
system("defaults write com.apple.LaunchServices LSHandlers -array-add 'LSHandlerContentTaghwdLSHandlerContentTagClasspublic.filename-extensionLSHandlerRoleAllorg.hedgewars.desktop'");
@@ -1909,12 +1947,14 @@
if (success) success = checkForDir(QDir::home().absolutePath() + "/.local/share");
if (success) success = checkForDir(QDir::home().absolutePath() + "/.local/share/applications");
if (success) success = system(("cp "+datadir->absolutePath()+"/misc/hedgewars-mimeinfo.xml "+QDir::home().absolutePath()+"/.local/share/mime/packages").toLocal8Bit().constData())==0;
+ if (success) success = system(("cp "+datadir->absolutePath()+"/misc/hedgewars.desktop "+QDir::home().absolutePath()+"/.local/share/applications").toLocal8Bit().constData())==0;
if (success) success = system(("cp "+datadir->absolutePath()+"/misc/hwengine.desktop "+QDir::home().absolutePath()+"/.local/share/applications").toLocal8Bit().constData())==0;
if (success) success = system(("update-mime-database "+QDir::home().absolutePath()+"/.local/share/mime").toLocal8Bit().constData())==0;
+ if (success) success = system("xdg-mime default hedgewars.desktop x-scheme-handler/hwplay")==0;
if (success) success = system("xdg-mime default hwengine.desktop application/x-hedgewars-demo")==0;
if (success) success = system("xdg-mime default hwengine.desktop application/x-hedgewars-save")==0;
// hack to add user's settings to hwengine. might be better at this point to read in the file, append it, and write it out to its new home. This assumes no spaces in the data dir path
- if (success) success = system(("sed -i 's/^\\(Exec=.*\\) \\([^ ]* %f\\)/\\1 \\2 "+arguments+"/' "+QDir::home().absolutePath()+"/.local/share/applications/hwengine.desktop").toLocal8Bit().constData())==0;
+ if (success) success = system(("sed -i 's|^\\(Exec=.*\\) \\(%f\\)|\\1 \\2 "+arguments+"|' "+QDir::home().absolutePath()+"/.local/share/applications/hwengine.desktop").toLocal8Bit().constData())==0;
#endif
if (success)
{
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/hwform.h
--- a/QTfrontend/hwform.h Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/hwform.h Tue Apr 02 21:00:57 2013 +0200
@@ -62,12 +62,14 @@
Ui_HWForm ui;
static GameUIConfig * config;
void updateXfire();
- void PlayDemoQuick(const QString & demofilename);
void exit();
void setButtonDescription(QString desc);
void backDescription();
void GoToVideos();
+ void NetConnectQuick(const QString & host, quint16 port);
+ void PlayDemoQuick(const QString & demofilename);
+
private slots:
void GoToSaves();
void GoToDemos();
@@ -143,6 +145,7 @@
private:
void _NetConnect(const QString & hostName, quint16 port, QString nick);
+ int AskForNickAndPwd(void);
void UpdateTeamsLists();
void CreateGame(GameCFGWidget * gamecfg, TeamSelWidget* pTeamSelWidget, QString ammo);
void closeEvent(QCloseEvent *event);
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/main.cpp
--- a/QTfrontend/main.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/main.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -20,7 +20,6 @@
#include
#include
-#include
#include
#include
#include
@@ -36,15 +35,13 @@
#include "DataManager.h"
#include "FileEngine.h"
+#include "MessageDialog.h"
#ifdef _WIN32
#include
#elif defined __APPLE__
#include "CocoaInitializer.h"
#endif
-#ifndef _WIN32
-#include
-#endif
// Program resources
#ifdef __APPLE__
@@ -94,14 +91,7 @@
else
season = SEASON_NONE;
}
-#ifndef _WIN32
-void terminateFrontend(int signal)
-{
- Q_UNUSED(signal);
- QCoreApplication::exit(0);
-}
-#endif
bool checkForDir(const QString & dir)
{
@@ -109,26 +99,12 @@
if (!tmpdir.exists())
if (!tmpdir.mkpath(dir))
{
- QMessageBox directoryMsg(QApplication::activeWindow());
- directoryMsg.setIcon(QMessageBox::Warning);
- directoryMsg.setWindowTitle(QMessageBox::tr("Main - Error"));
- directoryMsg.setText(QMessageBox::tr("Cannot create directory %1").arg(dir));
- directoryMsg.setWindowModality(Qt::WindowModal);
- directoryMsg.exec();
+ MessageDialog::ShowErrorMessage(HWApplication::tr("Cannot create directory %1").arg(dir));
return false;
}
return true;
}
-bool checkForFile(const QString & file)
-{
- QFile tmpfile(file);
- if (!tmpfile.exists())
- return tmpfile.open(QFile::WriteOnly);
- else
- return true;
-}
-
// Guaranteed to be the last thing ran in the application's life time.
// Closes resources that need to exist as long as possible.
void closeResources(void)
@@ -156,10 +132,6 @@
cocoaInit = new CocoaInitializer(); // Creates the autoreleasepool preventing cocoa object leaks on OS X.
#endif
-#ifndef _WIN32
- signal(SIGINT, &terminateFrontend);
-#endif
-
HWApplication app(argc, argv);
QLabel *splash = NULL;
@@ -167,7 +139,7 @@
QPixmap pixmap(":res/splash.png");
splash = new QLabel(0, Qt::FramelessWindowHint|Qt::WindowStaysOnTopHint);
splash->setAttribute(Qt::WA_TranslucentBackground);
- const QRect deskSize = QApplication::desktop()->screenGeometry(-1);
+ const QRect deskSize = HWApplication::desktop()->screenGeometry(-1);
QPoint splashCenter = QPoint( (deskSize.width() - pixmap.width())/2,
(deskSize.height() - pixmap.height())/2 );
splash->move(splashCenter);
@@ -276,16 +248,9 @@
datadir->cd(bindir->absolutePath());
datadir->cd(*cDataDir);
- if(!datadir->cd("Data"))
+ if (!datadir->cd("Data"))
{
- QMessageBox missingMsg(QApplication::activeWindow());
- missingMsg.setIcon(QMessageBox::Critical);
- missingMsg.setWindowTitle(QMessageBox::tr("Main - Error"));
- missingMsg.setText(QMessageBox::tr("Failed to open data directory:\n%1\n\n"
- "Please check your installation!").
- arg(datadir->absolutePath()+"/Data"));
- missingMsg.setWindowModality(Qt::WindowModal);
- missingMsg.exec();
+ MessageDialog::ShowFatalMessage(HWApplication::tr("Failed to open data directory:\n%1\n\nPlease check your installation!").arg(datadir->absolutePath()+"/Data"));
return 1;
}
@@ -296,7 +261,7 @@
engine->setWriteDir(cfgdir->absolutePath());
engine->mountPacks();
- checkForFile("physfs://hedgewars.ini");
+ DataManager::ensureFileExists("physfs://hedgewars.ini");
QTranslator Translator;
{
@@ -355,9 +320,13 @@
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
style.append(file.readAll());
+ qWarning("Starting Hedgewars %s-r%d (%s)", qPrintable(*cVersionString), cRevisionString->toInt(), qPrintable(*cHashString));
+
app.form = new HWForm(NULL, style);
app.form->show();
if(splash)
splash->close();
+ if (app.urlString)
+ app.fakeEvent();
return app.exec();
}
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/model/GameStyleModel.cpp
--- a/QTfrontend/model/GameStyleModel.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/model/GameStyleModel.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -25,12 +25,11 @@
#include "physfs.h"
#include "GameStyleModel.h"
+#include "hwconsts.h"
void GameStyleModel::loadGameStyles()
{
- const QString appDir = QString(PHYSFS_getBaseDir());
-
beginResetModel();
// empty list, so that we can (re)fill it
@@ -81,7 +80,7 @@
// detect if script is dlc
QString scriptPath = PHYSFS_getRealDir(QString("Scripts/Multiplayer/%1.lua").arg(script).toLocal8Bit().data());
- bool isDLC = !scriptPath.startsWith(appDir);
+ bool isDLC = !scriptPath.startsWith(datadir->absolutePath());
QStandardItem * item = new QStandardItem((isDLC ? "*" : "") + name);
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/model/MapModel.cpp
--- a/QTfrontend/model/MapModel.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/model/MapModel.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -26,6 +26,7 @@
#include "physfs.h"
#include "MapModel.h"
#include "HWApplication.h"
+#include "hwconsts.h"
MapModel::MapInfo MapModel::MapInfoRandom = {MapModel::GeneratedMap, "+rnd+", "", 0, "", "", ""};
MapModel::MapInfo MapModel::MapInfoMaze = {MapModel::GeneratedMaze, "+maze+", "", 0, "", "", ""};
@@ -33,8 +34,6 @@
void MapModel::loadMaps(MapType maptype)
{
- const QString appDir = QString(PHYSFS_getBaseDir());
-
// this method resets the contents of this model (important to know for views).
beginResetModel();
@@ -99,7 +98,7 @@
// detect if map is dlc
QString mapDir = PHYSFS_getRealDir(QString("Maps/%1/map.cfg").arg(map).toLocal8Bit().data());
- dlc = !mapDir.startsWith(appDir);
+ dlc = !mapDir.startsWith(datadir->absolutePath());
// let's use some semi-sane hedgehog limit, rather than none
if (limit == 0)
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/model/ThemeModel.cpp
--- a/QTfrontend/model/ThemeModel.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/model/ThemeModel.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -23,6 +23,7 @@
#include "physfs.h"
#include "ThemeModel.h"
+#include "hwconsts.h"
ThemeModel::ThemeModel(QObject *parent) :
QAbstractListModel(parent)
@@ -50,8 +51,6 @@
void ThemeModel::loadThemes()
{
- const QString appDir = QString(PHYSFS_getBaseDir());
-
beginResetModel();
DataManager & datamgr = DataManager::instance();
@@ -77,24 +76,21 @@
// detect if theme is dlc
QString themeDir = PHYSFS_getRealDir(QString("Themes/%1/icon.png").arg(theme).toLocal8Bit().data());
- dataset.insert(Qt::UserRole + 2, !themeDir.startsWith(appDir));
+ bool isDLC = !themeDir.startsWith(datadir->absolutePath());
+ dataset.insert(IsDlcRole, isDLC);
// set icon path
- dataset.insert(Qt::UserRole + 1, iconpath);
+ dataset.insert(IconPathRole, iconpath);
// set name
- dataset.insert(Qt::DisplayRole, theme);
+ dataset.insert(ActualNameRole, theme);
- // load and set icon
- QIcon icon;
- icon.addPixmap(QPixmap(iconpath), QIcon::Normal);
- icon.addPixmap(QPixmap(iconpath), QIcon::Disabled);
-
- dataset.insert(Qt::DecorationRole, icon);
+ // set displayed name
+ dataset.insert(Qt::DisplayRole, (isDLC ? "*" : "") + theme);
// load and set preview icon
QIcon preview(QString("physfs://Themes/%1/icon@2x.png").arg(theme));
- dataset.insert(Qt::UserRole, preview);
+ dataset.insert(Qt::DecorationRole, preview);
m_data.append(dataset);
}
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/model/ThemeModel.h
--- a/QTfrontend/model/ThemeModel.h Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/model/ThemeModel.h Tue Apr 02 21:00:57 2013 +0200
@@ -39,6 +39,7 @@
Q_OBJECT
public:
+ enum Roles { ActualNameRole = Qt::UserRole, IsDlcRole, IconPathRole };
explicit ThemeModel(QObject *parent = 0);
int rowCount(const QModelIndex &parent = QModelIndex()) const;
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/net/netudpserver.cpp
--- a/QTfrontend/net/netudpserver.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/net/netudpserver.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -20,13 +20,14 @@
#include
#include "netudpserver.h"
+#include "hwconsts.h"
HWNetUdpServer::HWNetUdpServer(QObject *parent, const QString & descr, quint16 port) :
HWNetRegisterServer(parent, descr, port),
m_descr(descr)
{
pUdpSocket = new QUdpSocket(this);
- pUdpSocket->bind(46631);
+ pUdpSocket->bind(NETGAME_DEFAULT_PORT);
connect(pUdpSocket, SIGNAL(readyRead()), this, SLOT(onClientRead()));
}
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/net/netudpwidget.cpp
--- a/QTfrontend/net/netudpwidget.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/net/netudpwidget.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -20,6 +20,7 @@
#include
#include "netudpwidget.h"
+#include "hwconsts.h"
HWNetUdpModel::HWNetUdpModel(QObject* parent) :
HWNetServersModel(parent)
@@ -36,7 +37,7 @@
reset();
- pUdpSocket->writeDatagram("hedgewars client", QHostAddress::Broadcast, 46631);
+ pUdpSocket->writeDatagram("hedgewars client", QHostAddress::Broadcast, NETGAME_DEFAULT_PORT);
}
void HWNetUdpModel::onClientRead()
@@ -54,7 +55,7 @@
if(packet.startsWith("hedgewars server"))
{
QStringList sl;
- sl << packet.remove(0, 17) << clientAddr.toString() << "46631";
+ sl << packet.remove(0, 17) << clientAddr.toString() << QString::number(NETGAME_DEFAULT_PORT);
games.append(sl);
}
}
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/net/newnetclient.cpp
--- a/QTfrontend/net/newnetclient.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/net/newnetclient.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -63,6 +63,8 @@
connect(&NetSocket, SIGNAL(disconnected()), this, SLOT(OnDisconnect()));
connect(&NetSocket, SIGNAL(error(QAbstractSocket::SocketError)), this,
SLOT(displayError(QAbstractSocket::SocketError)));
+
+ connect(this, SIGNAL(messageProcessed()), this, SLOT(ClientRead()), Qt::QueuedConnection);
}
HWNewNet::~HWNewNet()
@@ -186,6 +188,8 @@
{
ParseCmd(cmdbuf);
cmdbuf.clear();
+ emit messageProcessed();
+ return ;
}
else
cmdbuf << s;
@@ -307,7 +311,7 @@
QStringList tmp = lst;
tmp.removeFirst();
m_roomsListModel->setRoomsList(tmp);
- if (m_nick_registered == false)
+ if (m_private_game == false && m_nick_registered == false)
{
emit NickNotRegistered(mynick);
}
@@ -486,9 +490,9 @@
emit connected();
}
+ m_playersModel->addPlayer(lst[i]);
emit nickAddedLobby(lst[i], false);
emit chatStringLobby(lst[i], tr("%1 *** %2 has joined").arg('\x03').arg("|nick|"));
- m_playersModel->addPlayer(lst[i]);
}
return;
}
@@ -512,9 +516,12 @@
QString roomName = tmp.takeFirst();
m_roomsListModel->updateRoom(roomName, tmp);
- // keep track of room name so correct name is displayed when you become room admin
+ // keep track of room name so correct name is displayed
if(myroom == roomName)
+ {
myroom = tmp[1];
+ emit roomNameUpdated(myroom);
+ }
return;
}
@@ -598,6 +605,18 @@
return;
}
+ if(lst[0] == "JOINING")
+ {
+ if(lst.size() < 2)
+ {
+ qWarning("Net: Bad JOINING message");
+ return;
+ }
+
+ myroom = lst[1];
+ emit roomNameUpdated(myroom);
+ }
+
if(netClientState == InLobby && lst[0] == "JOINED")
{
if(lst.size() < 2 || lst[1] != mynick)
@@ -617,9 +636,9 @@
emit configAsked();
}
+ m_playersModel->playerJoinedRoom(lst[i]);
emit nickAdded(lst[i], isChief && (lst[i] != mynick));
emit chatStringFromNet(tr("%1 *** %2 has joined the room").arg('\x03').arg(lst[i]));
- m_playersModel->playerJoinedRoom(lst[i]);
}
return;
}
@@ -963,6 +982,11 @@
RawSendNet(QString("TOGGLE_RESTRICT_TEAMS"));
}
+void HWNewNet::toggleRegisteredOnly()
+{
+ RawSendNet(QString("TOGGLE_REGISTERED_ONLY"));
+}
+
void HWNewNet::clearAccountsCache()
{
RawSendNet(QString("CLEAR_ACCOUNTS_CACHE"));
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/net/newnetclient.h
--- a/QTfrontend/net/newnetclient.h Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/net/newnetclient.h Tue Apr 02 21:00:57 2013 +0200
@@ -61,6 +61,7 @@
QAbstractItemModel * lobbyPlayersModel();
QAbstractItemModel * roomPlayersModel();
bool allPlayersReady();
+ bool m_private_game;
private:
bool isChief;
@@ -105,6 +106,7 @@
void FromNet(const QByteArray & buf);
void adminAccess(bool);
void roomMaster(bool);
+ void roomNameUpdated(const QString & name);
void netSchemeConfig(QStringList &);
void paramChanged(const QString & param, const QStringList & value);
@@ -130,6 +132,8 @@
void setMyReadyStatus(bool isReady);
+ void messageProcessed();
+
public slots:
void ToggleReady();
void chatLineToNet(const QString& str);
@@ -160,6 +164,7 @@
void startGame();
void toggleRestrictJoins();
void toggleRestrictTeamAdds();
+ void toggleRegisteredOnly();
void partRoom();
void clearAccountsCache();
void getBanList();
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/net/tcpBase.cpp
--- a/QTfrontend/net/tcpBase.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/net/tcpBase.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -19,13 +19,12 @@
#include "tcpBase.h"
-#include
#include
-#include
#include
#include
#include "hwconsts.h"
+#include "MessageDialog.h"
#ifdef HWLIBRARY
extern "C" void Game(char**arguments);
@@ -89,13 +88,7 @@
IPCServer->setMaxPendingConnections(1);
if (!IPCServer->listen(QHostAddress::LocalHost))
{
- QMessageBox deniedMsg(QApplication::activeWindow());
- deniedMsg.setIcon(QMessageBox::Critical);
- deniedMsg.setWindowTitle(QMessageBox::tr("TCP - Error"));
- deniedMsg.setText(QMessageBox::tr("Unable to start the server: %1.").arg(IPCServer->errorString()));
- deniedMsg.setWindowModality(Qt::WindowModal);
- deniedMsg.exec();
-
+ MessageDialog::ShowFatalMessage(tr("Unable to start server at %1.").arg(IPCServer->errorString()));
exit(0); // FIXME - should be graceful exit here (lower Critical -> Warning above when implemented)
}
}
@@ -141,9 +134,10 @@
connect(process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(StartProcessError(QProcess::ProcessError)));
QStringList arguments=getArguments();
+#ifdef DEBUG
// redirect everything written on stdout/stderr
- if(isDevBuild)
- process->setProcessChannelMode(QProcess::ForwardedChannels);
+ process->setProcessChannelMode(QProcess::ForwardedChannels);
+#endif
process->start(bindir->absolutePath() + "/hwengine", arguments);
#endif
@@ -171,14 +165,7 @@
void TCPBase::StartProcessError(QProcess::ProcessError error)
{
- QMessageBox deniedMsg(QApplication::activeWindow());
- deniedMsg.setIcon(QMessageBox::Critical);
- deniedMsg.setWindowTitle(QMessageBox::tr("TCP - Error"));
- deniedMsg.setText(QMessageBox::tr("Unable to run engine at ") + bindir->absolutePath() + "/hwengine\n" +
- QMessageBox::tr("Error code: %1").arg(error));
- deniedMsg.setWindowModality(Qt::WindowModal);
- deniedMsg.exec();
-
+ MessageDialog::ShowFatalMessage(tr("Unable to run engine at %1\nError code: %2").arg(bindir->absolutePath() + "/hwengine").arg(error));
ClientDisconnect();
}
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/res/css/qt.css
--- a/QTfrontend/res/css/qt.css Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/res/css/qt.css Tue Apr 02 21:00:57 2013 +0200
@@ -275,21 +275,21 @@
border-radius: 3px;
}
-HatButton {
+HatButton, ThemeButton {
text-align: left;
}
-#hatList, #hatList:hover {
+#hatList, #hatList:hover, #themeList, #themeList:hover {
border-color: #F6CB1C;
}
-#hatList QScrollBar {
+#hatList QScrollBar, #themeList QScrollBar {
background-color: #130F2A;
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
}
-#hatList {
+#hatList, #themeList {
border-color: #F6CB1C;
border-width: 3px;
border-style: solid;
@@ -297,7 +297,7 @@
border-top-left-radius: 0px;
}
-#hatList::item {
+#hatList::item, #themeList::item {
background-color: #11084A;
padding: 4px;
border-radius: 10px;
@@ -307,11 +307,11 @@
border-color: #11084A;
}
-#hatList::item:hover {
+#hatList::item:hover, #themeList::item:hover {
background-color: #150A61;
}
-#hatList::item:selected {
+#hatList::item:selected, #themeList::item:selected {
background-color: #150A61;
}
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/res/html/about.html
--- a/QTfrontend/res/html/about.html Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/res/html/about.html Tue Apr 02 21:00:57 2013 +0200
@@ -4,7 +4,9 @@
Hedgewars - Authors
@@ -30,6 +32,9 @@
WebGL port, some pas2c and GLES2 work: Meng Xiangyun <xymengxy@gmail.com>
Video recording: Stepan Podoskin <stepik-777@mail.ru>
Campaign support, first campaign: Szabolcs Orbàn <szabibibi@gmail.com>
+ Keybinds, feedback, maps and hats interfaces: Drew Gottlieb <gottlieb.drew@gmail.com>
+ Login dialogs, frontend improvements: Ondrej Skopek <skopekondrej@gmail.com>
+ Icegun weapon: Julia Struchenko <urbertar@gmail.com>
Art:
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/team.cpp
--- a/QTfrontend/team.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/team.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -226,7 +226,9 @@
OldTeamName = m_name;
}
- QSettings teamfile(QString("physfs://Teams/%1.hwt").arg(m_name), QSettings::IniFormat, 0);
+ QString fileName = QString("physfs://Teams/%1.hwt").arg(m_name);
+ DataManager::ensureFileExists(fileName);
+ QSettings teamfile(fileName, QSettings::IniFormat, 0);
teamfile.setIniCodec("UTF-8");
teamfile.setValue("Team/Name", m_name);
teamfile.setValue("Team/Grave", m_grave);
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/dialog/input_ip.cpp
--- a/QTfrontend/ui/dialog/input_ip.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/ui/dialog/input_ip.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -23,6 +23,7 @@
#include
#include "input_ip.h"
+#include "hwconsts.h"
HWHostPortDialog::HWHostPortDialog(QWidget* parent) : QDialog(parent)
{
@@ -66,5 +67,5 @@
void HWHostPortDialog::setDefaultPort()
{
- sbPort->setValue(46631);
+ sbPort->setValue(NETGAME_DEFAULT_PORT);
}
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/dialog/input_password.cpp
--- a/QTfrontend/ui/dialog/input_password.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/ui/dialog/input_password.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -29,18 +29,14 @@
{
setWindowTitle(tr("Login"));
- QString titleLabelText = "To connect to the server, please log in.\n\nIf you don't have an account on www.hedgewars.org,\njust enter your nickname.";
- QString nickLabelText = "Nickname:";
- QString passLabelText = "Password:";
-
QGridLayout * layout = new QGridLayout(this);
QLabel * titleLabel = new QLabel(this);
- titleLabel->setText(titleLabelText);
+ titleLabel->setText(tr("To connect to the server, please log in.\n\nIf you don't have an account on www.hedgewars.org,\njust enter your nickname."));
layout->addWidget(titleLabel, 0, 0);
QLabel * nickLabel = new QLabel(this);
- nickLabel->setText(nickLabelText);
+ nickLabel->setText(tr("Nickname:"));
layout->addWidget(nickLabel, 1, 0);
leNickname = new QLineEdit(this);
@@ -48,7 +44,7 @@
layout->addWidget(leNickname, 2, 0);
QLabel * passLabel = new QLabel(this);
- passLabel->setText(passLabelText);
+ passLabel->setText(tr("Password:"));
layout->addWidget(passLabel, 3, 0);
lePassword = new QLineEdit(this);
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/mouseoverfilter.cpp
--- a/QTfrontend/ui/mouseoverfilter.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/ui/mouseoverfilter.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -5,6 +5,7 @@
#include
#include
#include
+#include
#include "mouseoverfilter.h"
#include "ui/page/AbstractPage.h"
@@ -31,6 +32,10 @@
abstractpage->setButtonDescription(widget->whatsThis());
else if (widget->toolTip() != NULL)
abstractpage->setButtonDescription(widget->toolTip());
+ }
+ else if (event->type() == QEvent::FocusIn)
+ {
+ abstractpage = qobject_cast(ui->Pages->currentWidget());
// play a sound when mouse hovers certain ui elements
QPushButton * button = dynamic_cast(dist);
@@ -39,7 +44,8 @@
QComboBox * droplist = dynamic_cast(dist);
QSlider * slider = dynamic_cast(dist);
QTabWidget * tab = dynamic_cast(dist);
- if (button || textfield || checkbox || droplist || slider || tab)
+ QListView * listview = dynamic_cast(dist);
+ if (button || textfield || checkbox || droplist || slider || tab || listview)
{
SDLInteraction::instance().playSoundFile("/Sounds/steps.ogg");
}
@@ -50,9 +56,9 @@
{
abstractpage = qobject_cast(ui->Pages->currentWidget());
- if (abstractpage->getDefautDescription() != NULL)
+ if (abstractpage->getDefaultDescription() != NULL)
{
- abstractpage->setButtonDescription( * abstractpage->getDefautDescription());
+ abstractpage->setButtonDescription( * abstractpage->getDefaultDescription());
}
else
abstractpage->setButtonDescription("");
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/page/AbstractPage.cpp
--- a/QTfrontend/ui/page/AbstractPage.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/ui/page/AbstractPage.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -53,7 +53,7 @@
// add back/exit button
btnBack = formattedButton(":/res/Exit.png", true);
btnBack->setWhatsThis(tr("Go back"));
- bottomLeftLayout->addWidget(btnBack, 0);
+ bottomLeftLayout->addWidget(btnBack, 0, Qt::AlignBottom);
// add body layout as defined by the subclass
pageLayout->addLayout(bodyLayoutDefinition(), 0, 0, 1, 3);
@@ -158,13 +158,13 @@
descLabel->setText(desc);
}
-void AbstractPage::setDefautDescription(QString text)
+void AbstractPage::setDefaultDescription(QString text)
{
*defautDesc = text;
descLabel->setText(text);
}
-QString * AbstractPage::getDefautDescription()
+QString * AbstractPage::getDefaultDescription()
{
return defautDesc;
}
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/page/AbstractPage.h
--- a/QTfrontend/ui/page/AbstractPage.h Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/ui/page/AbstractPage.h Tue Apr 02 21:00:57 2013 +0200
@@ -70,12 +70,12 @@
*
* @param text the defaut desc
*/
- void setDefautDescription(QString text);
+ void setDefaultDescription(QString text);
/**
* @brief Get the desc defaut text
*/
- QString * getDefautDescription();
+ QString * getDefaultDescription();
signals:
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/page/pagemain.cpp
--- a/QTfrontend/ui/page/pagemain.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/ui/page/pagemain.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -61,12 +61,12 @@
netLayout->setSpacing(20);
netLayout->setAlignment(Qt::AlignHCenter);
- BtnNetLocal = addButton("Play local network game", (QBoxLayout*)netLayout, 0, false);
+ BtnNetLocal = addButton(tr("Play local network game"), (QBoxLayout*)netLayout, 0, false);
BtnNetLocal->setWhatsThis(tr("Play a game across a local area network"));
BtnNetLocal->setFixedSize(BtnNet->width() - 50, 60);
BtnNetLocal->setVisible(false);
- BtnNetOfficial = addButton("Play official network game", (QBoxLayout*)netLayout, 0, false);
+ BtnNetOfficial = addButton(tr("Play official network game"), (QBoxLayout*)netLayout, 0, false);
BtnNetOfficial->setWhatsThis(tr("Play a game on an official server"));
BtnNetOfficial->setFixedSize(BtnNet->width() - 50, 60);
BtnNetOfficial->setVisible(false);
@@ -77,13 +77,13 @@
BtnInfo->setWhatsThis(tr("Read about who is behind the Hedgewars Project"));
pageLayout->setAlignment(BtnInfo, Qt::AlignHCenter);
- BtnFeedback = addButton("Feedback", pageLayout, 4, 0, 1, 4, false);
- BtnFeedback->setFixedSize(86, 27);
+ BtnFeedback = addButton(tr("Feedback"), pageLayout, 4, 0, 1, 4, false);
+ BtnFeedback->setStyleSheet("padding: 5px 10px");
BtnFeedback->setWhatsThis(tr("Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars"));
pageLayout->setAlignment(BtnFeedback, Qt::AlignHCenter);
BtnDataDownload = addButton(tr("Downloadable Content"), pageLayout, 5, 0, 1, 4, false);
- BtnDataDownload->setFixedSize(176, 27);
+ BtnDataDownload->setStyleSheet("padding: 5px 10px");
BtnDataDownload->setWhatsThis(tr("Access the user created content downloadable from our website"));
pageLayout->setAlignment(BtnDataDownload, Qt::AlignHCenter);
@@ -120,6 +120,8 @@
void PageMain::connectSignals()
{
connect(BtnNet, SIGNAL(clicked()), this, SLOT(toggleNetworkChoice()));
+ connect(BtnNetLocal, SIGNAL(clicked()), this, SLOT(toggleNetworkChoice()));
+ connect(BtnNetOfficial, SIGNAL(clicked()), this, SLOT(toggleNetworkChoice()));
// TODO: add signal-forwarding required by (currently missing) encapsulation
}
@@ -127,17 +129,15 @@
{
initPage();
- if(frontendEffects) setAttribute(Qt::WA_NoSystemBackground, true);
+ if(frontendEffects)
+ setAttribute(Qt::WA_NoSystemBackground, true);
mainNote->setOpenExternalLinks(true);
- if(!isDevBuild)
- {
- setDefautDescription(QLabel::tr("Tip: ") + randomTip());
- }
- else
- {
- setDefautDescription(QLabel::tr("This development build is 'work in progress' and may not be compatible with other versions of the game, while some features might be broken or incomplete!"));
- }
+#ifdef DEBUG
+ setDefaultDescription(QLabel::tr("This development build is 'work in progress' and may not be compatible with other versions of the game, while some features might be broken or incomplete!"));
+#else
+ setDefaultDescription(QLabel::tr("Tip: ") + randomTip());
+#endif
}
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/page/pagenet.cpp
--- a/QTfrontend/ui/page/pagenet.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/ui/page/pagenet.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -72,7 +72,12 @@
BtnNetSvrStart = formattedButton(QPushButton::tr("Start server"));
BtnNetSvrStart->setMinimumWidth(180);
- BtnNetSvrStart->setVisible(haveServer);
+ QString serverPath = bindir->absolutePath() + "/hedgewars-server";
+#ifdef Q_WS_WIN
+ serverPath += + ".exe";
+#endif
+ QFile server(serverPath);
+ BtnNetSvrStart->setVisible(server.exists());
footerLayout->addStretch();
footerLayout->addWidget(BtnNetSvrStart);
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/page/pagenetgame.cpp
--- a/QTfrontend/ui/page/pagenetgame.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/ui/page/pagenetgame.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -22,6 +22,7 @@
#include
#include
#include
+#include
#include "pagenetgame.h"
#include "gamecfgwidget.h"
@@ -53,13 +54,9 @@
leRoomName->setMaximumWidth(600);
leRoomName->setFixedHeight(30);
leRoomName->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ leRoomName->setStyleSheet("border-right: 0; padding-left: 4px; border-top-right-radius: 0px; border-bottom-right-radius: 0px;");
roomConfigLayout->addWidget(leRoomName, 100);
- QLabel * lblRoomName = new QLabel(tr("Room name: "), leRoomName);
- lblRoomName->setStyleSheet("font: 12px; font-weight: bold;");
- lblRoomName->setStyleSheet(QString("font: 12px; font-weight: bold; background: none; margin-left: -%1px; margin-top: 8px;").arg(lblRoomName->width() - 20));
- leRoomName->setStyleSheet(QString("font: 12px; border-right: 0; padding-left: %1px; padding-bottom: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px;").arg(lblRoomName->width() - 14));
-
BtnUpdate = new QPushButton();
BtnUpdate->setEnabled(false);
BtnUpdate->setText(tr("Update"));
@@ -173,8 +170,11 @@
restrictJoins->setCheckable(true);
restrictTeamAdds = new QAction(QAction::tr("Restrict Team Additions"), menu);
restrictTeamAdds->setCheckable(true);
+ restrictUnregistered = new QAction(QAction::tr("Restrict Unregistered Players Join"), menu);
+ restrictUnregistered->setCheckable(true);
menu->addAction(restrictJoins);
menu->addAction(restrictTeamAdds);
+ menu->addAction(restrictUnregistered);
BtnMaster->setMenu(menu);
@@ -188,9 +188,13 @@
int newHeight = event->size().height();
if (newHeight < cutoffHeight && oldHeight >= cutoffHeight)
+ {
pGameCFG->setTabbed(true);
+ }
else if (newHeight >= cutoffHeight && oldHeight < cutoffHeight)
+ {
pGameCFG->setTabbed(false);
+ }
}
void PageNetGame::displayError(const QString & message)
@@ -227,9 +231,10 @@
{
if (!leRoomName->text().trimmed().isEmpty())
{
- emit askForUpdateRoomName(leRoomName->text());
+ m_gameSettings->setValue("frontend/lastroomname", leRoomName->text());
leRoomName->rememberCurrentText();
BtnUpdate->setEnabled(false);
+ emit askForUpdateRoomName(leRoomName->text());
}
else
{
@@ -240,6 +245,7 @@
roomMsg.setText(QMessageBox::tr("Please enter room name"));
roomMsg.setWindowModality(Qt::WindowModal);
roomMsg.exec();
+ leRoomName->setFocus();
}
}
@@ -259,9 +265,16 @@
BtnUpdate->setVisible(isMaster);
leRoomName->setVisible(isMaster);
lblRoomNameReadOnly->setVisible(!isMaster);
+ pGameCFG->setMaster(isMaster);
+ repaint();
}
void PageNetGame::setUser(const QString & nickname)
{
chatWidget->setUser(nickname);
}
+
+void PageNetGame::setSettings(QSettings *settings)
+{
+ m_gameSettings = settings;
+}
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/page/pagenetgame.h
--- a/QTfrontend/ui/page/pagenetgame.h Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/ui/page/pagenetgame.h Tue Apr 02 21:00:57 2013 +0200
@@ -26,6 +26,7 @@
class HWChatWidget;
class TeamSelWidget;
class GameCFGWidget;
+class QSettings;
class PageNetGame : public AbstractPage
{
@@ -34,11 +35,7 @@
public:
PageNetGame(QWidget* parent);
- /**
- * Sets the room name to display.
- * @param roomName room name to be displayed.
- */
- void setRoomName(const QString & roomName);
+ void setSettings(QSettings * settings);
void displayError(const QString & message);
void displayNotice(const QString & message);
@@ -52,6 +49,7 @@
QAction * restrictJoins;
QAction * restrictTeamAdds;
+ QAction * restrictUnregistered;
HWChatWidget* chatWidget;
@@ -59,6 +57,7 @@
GameCFGWidget* pGameCFG;
public slots:
+ void setRoomName(const QString & roomName);
void setReadyStatus(bool isReady);
void setUser(const QString & nickname);
void onUpdateClick();
@@ -80,6 +79,7 @@
QLayout * footerLayoutLeftDefinition();
void connectSignals();
+ QSettings * m_gameSettings;
QPushButton * btnSetup;
QLabel * lblRoomNameReadOnly;
};
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/page/pagenetserver.cpp
--- a/QTfrontend/ui/page/pagenetserver.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/ui/page/pagenetserver.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -24,8 +24,13 @@
#include
#include
#include
+#include
+#include
+#include
#include "pagenetserver.h"
+#include "hwconsts.h"
+#include "HWApplication.h"
QLayout * PageNetServer::bodyLayoutDefinition()
{
@@ -59,14 +64,21 @@
gbLayout->addWidget(labelPort, 1, 0);
sbPort = new QSpinBox(gb);
- sbPort->setMinimum(0);
+ sbPort->setMinimum(1024);
sbPort->setMaximum(65535);
gbLayout->addWidget(sbPort, 1, 1);
BtnDefault = new QPushButton(gb);
- BtnDefault->setText(QPushButton::tr("default"));
+ BtnDefault->setMinimumWidth(50);
+ BtnDefault->setText(QPushButton::tr("Reset"));
+ BtnDefault->setWhatsThis(QPushButton::tr("Set the default server port for Hedgewars"));
gbLayout->addWidget(BtnDefault, 1, 2);
+ BtnShare = new QPushButton(gb);
+ BtnShare->setText(QPushButton::tr("Invite your friends to your server in just 1 click!"));
+ BtnShare->setWhatsThis(QPushButton::tr("Click to copy your unique server URL in your clipboard. Send this link to your friends ands and they will be able to join you."));
+ gbLayout->addWidget(BtnShare, 2, 1);
+
return pageLayout;
}
@@ -75,6 +87,7 @@
QHBoxLayout * bottomLayout = new QHBoxLayout();
BtnStart = formattedButton(QPushButton::tr("Start"));
+ BtnStart->setWhatsThis(QPushButton::tr("Start private server"));
BtnStart->setMinimumWidth(180);
bottomLayout->addStretch();
@@ -86,6 +99,7 @@
void PageNetServer::connectSignals()
{
connect(BtnDefault, SIGNAL(clicked()), this, SLOT(setDefaultPort()));
+ connect(BtnShare, SIGNAL(clicked()), this, SLOT(copyUrl()));
}
PageNetServer::PageNetServer(QWidget* parent) : AbstractPage(parent)
@@ -95,5 +109,29 @@
void PageNetServer::setDefaultPort()
{
- sbPort->setValue(46631);
+ sbPort->setValue(NETGAME_DEFAULT_PORT);
}
+
+// This function assumes that the user wants to share his server while connected to
+// the Internet and that he/she is using direct access (eg no NATs). To determine the
+// IP we briefly connect to Hedgewars website and fallback to user intervention
+// after 4 seconds of timeout.
+void PageNetServer::copyUrl()
+{
+ QString address = "hwplay://";
+
+ QTcpSocket socket;
+ socket.connectToHost("www.hedgewars.org", 80);
+ if (socket.waitForConnected(4000))
+ address += socket.localAddress().toString();
+ else
+ address += "<" + tr("Insert your address here") + ">";
+
+ if (sbPort->value() != NETGAME_DEFAULT_PORT)
+ address += ":" + QString::number(sbPort->value());
+
+ QClipboard *clipboard = HWApplication::clipboard();
+ clipboard->setText(address);
+ qDebug() << address << "copied to clipboard";
+}
+
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/page/pagenetserver.h
--- a/QTfrontend/ui/page/pagenetserver.h Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/ui/page/pagenetserver.h Tue Apr 02 21:00:57 2013 +0200
@@ -30,6 +30,7 @@
QPushButton *BtnStart;
QPushButton *BtnDefault;
+ QPushButton *BtnShare;
QLabel *labelSD;
QLineEdit *leServerDescr;
QLabel *labelPort;
@@ -42,6 +43,7 @@
private slots:
void setDefaultPort();
+ void copyUrl();
};
#endif
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/page/pageroomslist.cpp
--- a/QTfrontend/ui/page/pageroomslist.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/ui/page/pageroomslist.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -16,102 +16,187 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
+#include
+#include
#include
-#include
#include
#include
#include
#include
#include
#include
-#include
+#include
+#include
+#include
#include
#include "roomslistmodel.h"
#include "ammoSchemeModel.h"
-#include "pageroomslist.h"
#include "hwconsts.h"
#include "chatwidget.h"
+#include "roomnameprompt.h"
+#include "lineeditcursor.h"
+#include "pageroomslist.h"
+
+void RoomTableView::moveDown()
+{
+ setCurrentIndex(moveCursor(QAbstractItemView::MoveDown, Qt::NoModifier));
+}
+
+void RoomTableView::moveUp()
+{
+ setCurrentIndex(moveCursor(QAbstractItemView::MoveUp, Qt::NoModifier));
+}
QLayout * PageRoomsList::bodyLayoutDefinition()
{
- QGridLayout * pageLayout = new QGridLayout();
+ QVBoxLayout * pageLayout = new QVBoxLayout();
+ pageLayout->setSpacing(0);
+
+ QGridLayout * topLayout = new QGridLayout();
+ topLayout->setSpacing(0);
+ pageLayout->addLayout(topLayout, 0);
+
+ // Help/prompt message at top
+ QLabel * lblDesc = new QLabel(tr("Search for a room:"));
+ lblDesc->setObjectName("lblDesc");
+ lblDesc->setStyleSheet("#lblDesc { color: #130F2A; background: #F6CB1C; border: solid 4px #F6CB1C; border-top-left-radius: 10px; padding: 4px 10px;}");
+ lblDesc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ lblDesc->setFixedHeight(24);
+ lblDesc->setMinimumWidth(0);
+
+ // Search text box
+ QWidget * searchContainer = new QWidget();
+ searchContainer->setFixedHeight(24);
+ searchContainer->setObjectName("searchContainer");
+ searchContainer->setStyleSheet("#searchContainer { background: #F6CB1C; border-top-right-radius: 10px; padding: 3px; }");
+ searchContainer->setFixedWidth(200);
+ searchText = new LineEditCursor(searchContainer);
+ searchText->setFixedWidth(200);
+ searchText->setMaxLength(60);
+ searchText->setFixedHeight(22);
+ searchText->setStyleSheet("LineEditCursor { border-width: 0px; border-radius: 6px; margin-top: 3px; margin-right: 3px; padding-left: 4px; padding-bottom: 2px; background-color: rgb(23, 11, 54); } LineEditCursor:hover, LineEditCursor:focus { background-color: rgb(13, 5, 68); }");
- QHBoxLayout * newRoomLayout = new QHBoxLayout();
- QLabel * roomNameLabel = new QLabel(this);
- roomNameLabel->setText(tr("Room Name:"));
- roomName = new QLineEdit(this);
- roomName->setMaxLength(60);
- newRoomLayout->addWidget(roomNameLabel);
- newRoomLayout->addWidget(roomName);
- pageLayout->addLayout(newRoomLayout, 0, 0, 1, 2);
+ // Corner widget
+ QLabel * corner = new QLabel();
+ corner->setPixmap(QPixmap(QString::fromUtf8(":/res/inverse-corner-bl.png")));
+ corner->setFixedSize(10, 10);
+
+ const QIcon& lp = QIcon(":/res/new.png");
+ //QSize sz = lp.actualSize(QSize(65535, 65535));
+ BtnCreate = new QPushButton();
+ BtnCreate->setText(tr("Create room"));
+ BtnCreate->setIcon(lp);
+ BtnCreate->setStyleSheet("padding: 4px 8px; margin-bottom: 6px;");
+
+ BtnJoin = new QPushButton(tr("Join room"));
+ BtnJoin->setStyleSheet("padding: 4px 8px; margin-bottom: 6px; margin-left: 6px;");
+ BtnJoin->setEnabled(false);
- roomsList = new QTableView(this);
+ // Add widgets to top layout
+ topLayout->addWidget(lblDesc, 1, 0);
+ topLayout->addWidget(searchContainer, 1, 1);
+ topLayout->addWidget(corner, 1, 2, Qt::AlignBottom);
+ topLayout->addWidget(BtnCreate, 0, 4, 2, 1);
+ topLayout->addWidget(BtnJoin, 0, 5, 2, 1);
+
+ // Top layout stretch
+ topLayout->setRowStretch(0, 1);
+ topLayout->setRowStretch(1, 0);
+ topLayout->setColumnStretch(3, 1);
+
+ // Room list
+
+ roomsList = new RoomTableView(this);
roomsList->setSelectionBehavior(QAbstractItemView::SelectRows);
roomsList->verticalHeader()->setVisible(false);
roomsList->horizontalHeader()->setResizeMode(QHeaderView::Interactive);
roomsList->setAlternatingRowColors(true);
roomsList->setShowGrid(false);
roomsList->setSelectionMode(QAbstractItemView::SingleSelection);
- pageLayout->addWidget(roomsList, 1, 0, 3, 2);
- pageLayout->setRowStretch(2, 100);
+ roomsList->setStyleSheet("QTableView { border-top-left-radius: 0px; }");
+ roomsList->setFocusPolicy(Qt::NoFocus);
+ pageLayout->addWidget(roomsList, 200);
+
+ // Room filters container
+
+ QWidget * filtersContainer = new QWidget();
+ filtersContainer->setMaximumWidth(800);
+ filtersContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
- QHBoxLayout * filterLayout = new QHBoxLayout();
+ pageLayout->addSpacing(7);
+ pageLayout->addWidget(filtersContainer, 0, Qt::AlignHCenter);
+ pageLayout->addSpacing(7);
+
+ QHBoxLayout * filterLayout = new QHBoxLayout(filtersContainer);
+ filterLayout->setSpacing(0);
+ filterLayout->setMargin(0);
- QLabel * stateLabel = new QLabel(this);
- CBState = new QComboBox(this);
+ const int filterSpacing = 20;
+
+ // State button
- filterLayout->addWidget(stateLabel);
- filterLayout->addWidget(CBState);
- filterLayout->addStretch(1);
+ QPushButton * btnState = new QPushButton(tr("Room state"));
+ btnState->setStyleSheet("QPushButton { padding: 2px 4px; } QPushButton:pressed { background-color: #ffcc00; border-color: #ffcc00; border-bottom-left-radius: 0px; border-bottom-right-radius: 0px; color: #11084A; }");
+ btnState->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
+ filterLayout->addWidget(btnState);
+ filterLayout->addSpacing(filterSpacing);
+
+ // State menu
- QLabel * ruleLabel = new QLabel(this);
- ruleLabel->setText(tr("Rules:"));
+ QMenu * stateMenu = new QMenu(btnState);
+ showGamesInLobby = new QAction(QAction::tr("Show games in lobby"), stateMenu);
+ showGamesInLobby->setCheckable(true);
+ showGamesInLobby->setChecked(true);
+ showGamesInProgress = new QAction(QAction::tr("Show games in-progress"), stateMenu);
+ showGamesInProgress->setCheckable(true);
+ showGamesInProgress->setChecked(true);
+ stateMenu->addAction(showGamesInLobby);
+ stateMenu->addAction(showGamesInProgress);
+ btnState->setMenu(stateMenu);
+
+ // Rules dropdown
+
CBRules = new QComboBox(this);
+ CBRules->setStyleSheet("QComboBox { border-top-left-radius: 0px; border-bottom-left-radius: 0px; border-left-width: 2px; }");
+
+ QLabel * ruleLabel = new QLabel(tr("Rules:"), this);
+ ruleLabel->setFixedHeight(CBRules->height());
+ ruleLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ ruleLabel->setStyleSheet("border: solid; border-width: 3px; border-right-width: 0px; border-color: #ffcc00; border-top-left-radius: 10px; border-bottom-left-radius: 10px; background-color: rgba(13, 5, 68, 70%);");
filterLayout->addWidget(ruleLabel);
filterLayout->addWidget(CBRules);
- filterLayout->addStretch(1);
+ filterLayout->addSpacing(filterSpacing);
+
+ // Weapons dropdown
- QLabel * weaponLabel = new QLabel(this);
- weaponLabel->setText(tr("Weapons:"));
CBWeapons = new QComboBox(this);
+ CBWeapons->setStyleSheet("QComboBox { border-top-left-radius: 0px; border-bottom-left-radius: 0px; border-left-width: 2px; }");
+
+ QLabel * weaponLabel = new QLabel(tr("Weapons:"), this);
+ weaponLabel->setFixedHeight(CBWeapons->height());
+ weaponLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ weaponLabel->setStyleSheet("border: solid; border-width: 3px; border-right-width: 0px; border-color: #ffcc00; border-top-left-radius: 10px; border-bottom-left-radius: 10px; background-color: rgba(13, 5, 68, 70%);");
filterLayout->addWidget(weaponLabel);
filterLayout->addWidget(CBWeapons);
- filterLayout->addStretch(1);
+ filterLayout->addSpacing(filterSpacing);
+
+ // Clear filters button
- QLabel * searchLabel = new QLabel(this);
- searchLabel->setText(tr("Search:"));
- searchText = new QLineEdit(this);
- searchText->setMaxLength(60);
- searchText->setMinimumWidth(100);
- searchText->setMaximumWidth(360);
- filterLayout->addWidget(searchLabel);
- filterLayout->addWidget(searchText);
- filterLayout->setStretchFactor(searchText, 2);
+ BtnClear = addButton(tr("Clear filters"), filterLayout, 0);
+ weaponLabel->setFixedHeight(CBWeapons->height());
+ BtnClear->setStyleSheet("padding: 4px;");
- pageLayout->addLayout(filterLayout, 4, 0, 1, 2);
+ // Lobby chat
chatWidget = new HWChatWidget(this, false);
- pageLayout->addWidget(chatWidget, 5, 0, 1, 3);
- pageLayout->setRowStretch(5, 350);
-
- BtnCreate = addButton(tr("Create"), pageLayout, 0, 2);
- BtnJoin = addButton(tr("Join"), pageLayout, 1, 2);
- BtnClear = addButton(tr("Clear"), pageLayout, 4, 2);
-
- // strech all but the buttons column
- pageLayout->setColumnStretch(0, 1);
- pageLayout->setColumnStretch(1, 1);
- pageLayout->setColumnStretch(2, 0);
+ pageLayout->addWidget(chatWidget, 350);
CBRules->addItem(QComboBox::tr("Any"));
- CBState->addItem(QComboBox::tr("Any"));
- CBState->addItem(QComboBox::tr("In lobby"));
- CBState->addItem(QComboBox::tr("In progress"));
return pageLayout;
}
@@ -120,18 +205,9 @@
{
QHBoxLayout * bottomLayout = new QHBoxLayout();
- lblCount = new QLabel(this);
- bottomLayout->addWidget(lblCount, 0, Qt::AlignHCenter);
- bottomLayout->setStretchFactor(lblCount, 1);
- lblCount->setText("?");
- lblCount->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
-
- BtnAdmin = addButton(tr("Admin features"), bottomLayout, 1);
- BtnAdmin->setMinimumWidth(160);
-
- // strech left part
- bottomLayout->setStretch(0, 1);
- bottomLayout->setStretch(1, 0);
+ BtnAdmin = addButton(tr("Admin features"), bottomLayout, 0);
+ BtnAdmin->setStyleSheet("padding: 4px auto;");
+ BtnAdmin->setWhatsThis(tr("Open server administration page"));
return bottomLayout;
}
@@ -143,18 +219,40 @@
connect(BtnCreate, SIGNAL(clicked()), this, SLOT(onCreateClick()));
connect(BtnJoin, SIGNAL(clicked()), this, SLOT(onJoinClick()));
connect(BtnClear, SIGNAL(clicked()), this, SLOT(onClearClick()));
+ connect(searchText, SIGNAL(moveUp()), this, SLOT(moveSelectionUp()));
+ connect(searchText, SIGNAL(moveDown()), this, SLOT(moveSelectionDown()));
+ connect(searchText, SIGNAL(returnPressed()), this, SLOT(onJoinClick()));
connect(roomsList, SIGNAL(doubleClicked (const QModelIndex &)), this, SLOT(onJoinClick()));
- connect(CBState, SIGNAL(currentIndexChanged (int)), this, SLOT(onFilterChanged()));
+ connect(roomsList, SIGNAL(clicked (const QModelIndex &)), searchText, SLOT(setFocus()));
+ connect(showGamesInLobby, SIGNAL(triggered()), this, SLOT(onFilterChanged()));
+ connect(showGamesInProgress, SIGNAL(triggered()), this, SLOT(onFilterChanged()));
connect(CBRules, SIGNAL(currentIndexChanged (int)), this, SLOT(onFilterChanged()));
connect(CBWeapons, SIGNAL(currentIndexChanged (int)), this, SLOT(onFilterChanged()));
connect(searchText, SIGNAL(textChanged (const QString &)), this, SLOT(onFilterChanged()));
connect(this, SIGNAL(askJoinConfirmation (const QString &)), this, SLOT(onJoinConfirmation(const QString &)), Qt::QueuedConnection);
+ // Set focus on search box
+ connect(this, SIGNAL(pageEnter()), searchText, SLOT(setFocus()));
+
// sorting
connect(roomsList->horizontalHeader(), SIGNAL(sortIndicatorChanged(int, Qt::SortOrder)),
this, SLOT(onSortIndicatorChanged(int, Qt::SortOrder)));
}
+void PageRoomsList::moveSelectionUp()
+{
+ roomsList->moveUp();
+}
+
+void PageRoomsList::moveSelectionDown()
+{
+ roomsList->moveDown();
+}
+
+void PageRoomsList::roomSelectionChanged(const QModelIndex & current, const QModelIndex & previous)
+{
+ BtnJoin->setEnabled(current.isValid());
+}
PageRoomsList::PageRoomsList(QWidget* parent) :
AbstractPage(parent)
@@ -419,16 +517,21 @@
void PageRoomsList::onCreateClick()
{
- if (roomName->text().size())
- emit askForCreateRoom(roomName->text());
+ RoomNamePrompt prompt(parentWidget()->parentWidget(), m_gameSettings->value("frontend/lastroomname", QString()).toString());
+ connect(&prompt, SIGNAL(roomNameChosen(const QString &)), this, SLOT(onRoomNameChosen(const QString &)));
+ prompt.exec();
+}
+
+void PageRoomsList::onRoomNameChosen(const QString & roomName)
+{
+ if (!roomName.trimmed().isEmpty())
+ {
+ m_gameSettings->setValue("frontend/lastroomname", roomName);
+ emit askForCreateRoom(roomName);
+ }
else
{
- QMessageBox roomNameMsg(this);
- roomNameMsg.setIcon(QMessageBox::Warning);
- roomNameMsg.setWindowTitle(QMessageBox::tr("Room Name - Error"));
- roomNameMsg.setText(QMessageBox::tr("Please enter room name"));
- roomNameMsg.setWindowModality(Qt::WindowModal);
- roomNameMsg.exec();
+ onCreateClick();
}
}
@@ -463,10 +566,12 @@
void PageRoomsList::onClearClick()
{
- CBState->setCurrentIndex(0);
+ showGamesInLobby->setChecked(true);
+ showGamesInProgress->setChecked(true);
CBRules->setCurrentIndex(0);
CBWeapons->setCurrentIndex(0);
searchText->clear();
+ searchText->setFocus();
}
void PageRoomsList::onJoinConfirmation(const QString & room)
@@ -487,7 +592,7 @@
void PageRoomsList::updateNickCounter(int cnt)
{
- lblCount->setText(tr("%1 players online", 0, cnt).arg(cnt));
+ setDefaultDescription(tr("%1 players online", 0, cnt).arg(cnt));
}
void PageRoomsList::setUser(const QString & nickname)
@@ -531,6 +636,12 @@
// let the table view display the last model in the filter chain
roomsList->setModel(roomsModel);
+
+ // When the data changes
+ connect(roomsModel, SIGNAL(layoutChanged()), roomsList, SLOT(repaint()));
+
+ // When a selection changes
+ connect(roomsList->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(roomSelectionChanged(const QModelIndex &, const QModelIndex &)));
}
stateFilteredModel->setSourceModel(model);
@@ -559,6 +670,8 @@
this, SLOT(saveHeaderState()));
connect(roomsList->horizontalHeader(), SIGNAL(sectionResized(int, int, int)),
this, SLOT(saveHeaderState()));
+
+ roomsList->repaint();
}
@@ -589,13 +702,15 @@
roomsModel->setFilterWildcard(QString("*%1*").arg(searchText->text()));
- int stateIdx = CBState->currentIndex();
- // any = 0, in lobby/false = 1, in progress/true = 2
+ bool stateLobby = showGamesInLobby->isChecked();
+ bool stateProgress = showGamesInProgress->isChecked();
- if (stateIdx == 0)
+ if (stateLobby && stateProgress)
stateFilteredModel->setFilterWildcard("*"); // "any"
+ else if (stateLobby != stateProgress)
+ stateFilteredModel->setFilterFixedString(QString(stateProgress));
else
- stateFilteredModel->setFilterFixedString(QString(stateIdx == 2));
+ stateFilteredModel->setFilterFixedString(QString("none")); // Basically, none.
if (CBRules->currentIndex() == 0)
schemeFilteredModel->setFilterWildcard("*"); // "any"
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/page/pageroomslist.h
--- a/QTfrontend/ui/page/pageroomslist.h Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/ui/page/pageroomslist.h Tue Apr 02 21:00:57 2013 +0200
@@ -19,6 +19,7 @@
#ifndef PAGE_ROOMLIST_H
#define PAGE_ROOMLIST_H
+#include
#include "AbstractPage.h"
class HWChatWidget;
@@ -27,6 +28,16 @@
class RoomsListModel;
class QSortFilterProxyModel;
+class RoomTableView : public QTableView
+{
+ friend class PageRoomsList;
+
+ public:
+ RoomTableView(QWidget* parent = 0) : QTableView(parent){}
+ void moveUp();
+ void moveDown();
+};
+
class PageRoomsList : public AbstractPage
{
Q_OBJECT
@@ -38,9 +49,8 @@
void displayWarning(const QString & message);
void setSettings(QSettings * settings);
- QLineEdit * roomName;
QLineEdit * searchText;
- QTableView * roomsList;
+ RoomTableView * roomsList;
QPushButton * BtnCreate;
QPushButton * BtnJoin;
QPushButton * BtnAdmin;
@@ -78,6 +88,10 @@
void onSortIndicatorChanged(int logicalIndex, Qt::SortOrder order);
void onFilterChanged();
void saveHeaderState();
+ void onRoomNameChosen(const QString &);
+ void roomSelectionChanged(const QModelIndex &, const QModelIndex &);
+ void moveSelectionUp();
+ void moveSelectionDown();
private:
QSettings * m_gameSettings;
@@ -85,6 +99,8 @@
QSortFilterProxyModel * stateFilteredModel;
QSortFilterProxyModel * schemeFilteredModel;
QSortFilterProxyModel * weaponsFilteredModel;
+ QAction * showGamesInLobby;
+ QAction * showGamesInProgress;
AmmoSchemeModel * ammoSchemeModel;
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/widget/about.cpp
--- a/QTfrontend/ui/widget/about.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/ui/widget/about.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -67,10 +67,11 @@
"a { color: #ffcc00; }"
// "a:hover { color: yellow; }"
""
- "Hedgewars
"
- "
" + QLabel::tr("Version") + " " + *cVersionString + "
"
+ "
Hedgewars " + *cVersionString + "
"
+ "
" + QLabel::tr("Revision") + " " + *cRevisionString + " (" + *cHashString + ")
"
"
http://www.hedgewars.org/
" +
- QLabel::tr("This program is distributed under the GNU General Public License v2") +
+ QLabel::tr("This program is distributed under the %1").arg("
GNU GPL v2") +
"
"
);
lbl1->setWordWrap(true);
@@ -87,9 +88,9 @@
QString libinfo = "";
#ifdef __GNUC__
- libinfo.append(QString("Compiler:
GCC %1
").arg(__VERSION__));
+ libinfo.append(QString("
GCC %1
").arg(__VERSION__));
#else
- libinfo.append(QString("Compiler: Unknown
").arg(__VERSION__));
+ libinfo.append(QString(tr("Unknown Compiler")).arg(__VERSION__) + QString("
"));
#endif
libinfo.append(QString("
SDL version: %1.%2.%3
")
@@ -112,10 +113,11 @@
.arg(PHYSFS_VER_PATCH));
QLabel * lblLibInfo = new QLabel();
+ lblLibInfo->setOpenExternalLinks(true);
lblLibInfo->setText(libinfo);
lblLibInfo->setWordWrap(true);
lblLibInfo->setMaximumWidth(280);
- leftLayout->addWidget(lblLibInfo, 0, Qt::AlignTop | Qt::AlignHCenter);
+ leftLayout->addWidget(lblLibInfo, 0, Qt::AlignHCenter);
leftLayout->addStretch(1);
setAcceptDrops(true);
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/widget/chatwidget.cpp
--- a/QTfrontend/ui/widget/chatwidget.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/ui/widget/chatwidget.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -31,12 +31,13 @@
#include
#include
#include
+#include
#include "DataManager.h"
#include "hwconsts.h"
#include "gameuiconfig.h"
#include "playerslistmodel.h"
-
+#include "HWApplication.h"
#include "chatwidget.h"
@@ -156,24 +157,18 @@
void HWChatWidget::displayError(const QString & message)
{
addLine("msg_Error", " !!! " + message);
- // scroll to the end
- chatText->moveCursor(QTextCursor::End);
}
void HWChatWidget::displayNotice(const QString & message)
{
addLine("msg_Notice", " *** " + message);
- // scroll to the end
- chatText->moveCursor(QTextCursor::End);
}
void HWChatWidget::displayWarning(const QString & message)
{
addLine("msg_Warning", " *!* " + message);
- // scroll to the end
- chatText->moveCursor(QTextCursor::End);
}
@@ -451,6 +446,8 @@
if (s_displayNone->contains(cssClass))
return; // the css forbids us to display this line
+ beforeContentAdd();
+
if (chatStrings.size() > 250)
chatStrings.removeFirst();
@@ -467,17 +464,20 @@
{
line = QString("%1").arg(line);
SDLInteraction::instance().playSoundFile(m_hilightSound);
+ HWApplication::alert(this, 800);
}
chatStrings.append(line);
chatText->setHtml(""+chatStrings.join("
")+"");
- chatText->moveCursor(QTextCursor::End);
+ afterContentAdd();
}
void HWChatWidget::onServerMessage(const QString& str)
{
+ beforeContentAdd();
+
if (chatStrings.size() > 250)
chatStrings.removeFirst();
@@ -485,7 +485,7 @@
chatText->setHtml(""+chatStrings.join("
")+"");
- chatText->moveCursor(QTextCursor::End);
+ afterContentAdd();
}
@@ -901,3 +901,21 @@
m_nicksMenu->popup(chatNicks->mapToGlobal(pos));
}
+
+void HWChatWidget::beforeContentAdd()
+{
+ m_scrollBarPos = chatText->verticalScrollBar()->value();
+ m_scrollToBottom = m_scrollBarPos == chatText->verticalScrollBar()->maximum();
+}
+
+void HWChatWidget::afterContentAdd()
+{
+ if(m_scrollToBottom)
+ {
+ chatText->verticalScrollBar()->setValue(chatText->verticalScrollBar()->maximum());
+ chatText->moveCursor(QTextCursor::End);
+ } else
+ {
+ chatText->verticalScrollBar()->setValue(m_scrollBarPos);
+ }
+}
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/widget/chatwidget.h
--- a/QTfrontend/ui/widget/chatwidget.h Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/ui/widget/chatwidget.h Tue Apr 02 21:00:57 2013 +0200
@@ -83,6 +83,8 @@
void discardStyleSheet();
void saveStyleSheet();
QString linkedNick(const QString & nickname);
+ void beforeContentAdd();
+ void afterContentAdd();
public slots:
void onChatString(const QString& str);
@@ -124,6 +126,8 @@
QList m_highlights; ///< regular expressions used for highlighting
bool notify;
bool m_autoKickEnabled;
+ bool m_scrollToBottom;
+ int m_scrollBarPos;
private slots:
void returnPressed();
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/widget/feedbackdialog.cpp
--- a/QTfrontend/ui/widget/feedbackdialog.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/ui/widget/feedbackdialog.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -30,6 +30,7 @@
#include
#include
#include
+#include
#include
@@ -73,16 +74,22 @@
QHBoxLayout * systemLayout = new QHBoxLayout();
info = new QLabel();
- info->setText(
+ info->setText(QString(
""
- "Please give us feedback!
"
- "We are always happy about suggestions, ideas, or bug reports."
- "Your email address is optional, but we may want to contact you."
- "
"
+ "")
+ .arg(tr("Please give us feedback!"))
+ .arg(tr("We are always happy about suggestions, ideas, or bug reports."))
+ .arg(tr("If you found a bug, you can see if it's already known here (english): "))
+ .arg(tr("Your email address is optional, but we may want to contact you."))
);
+ info->setOpenExternalLinks(true);
pageLayout->addWidget(info);
QVBoxLayout * summaryEmailLayout = new QVBoxLayout();
@@ -194,7 +201,7 @@
QString screen_size = "Size of the screen(s): " +
QString::number(screen->width()) + "x" + QString::number(screen->height()) + "\n";
QString number_of_screens = "Number of screens: " + QString::number(screen->screenCount()) + "\n";
- std::string processor_name = "Processor: ";
+ QString processor_name = "Processor: ";
// platform specific code
#ifdef Q_WS_MACX
@@ -237,7 +244,7 @@
MEMORYSTATUSEX status;
status.dwLength = sizeof(status);
GlobalMemoryStatusEx(&status);
- total_ram += QString::number(status.ullTotalPhys);
+ total_ram += QString::number(status.ullTotalPhys) + "\n";
switch(QSysInfo::WinVersion())
{
@@ -245,6 +252,7 @@
case QSysInfo::WV_XP: os_version += "Windows XP\n"; break;
case QSysInfo::WV_VISTA: os_version += "Windows Vista\n"; break;
case QSysInfo::WV_WINDOWS7: os_version += "Windows 7\n"; break;
+ //case QSysInfo::WV_WINDOWS8: os_version += "Windows 8\n"; break; //QT 5+
default: os_version += "Windows (Unknown version)\n"; break;
}
kernel_line += "Windows kernel\n";
@@ -273,6 +281,7 @@
delete process;
#endif
+#if defined(__i386__) || defined(__x86_64__)
// cpu info
quint32 registers[4];
quint32 i;
@@ -281,26 +290,30 @@
asm volatile
("cpuid" : "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3])
: "a" (i), "c" (0));
- processor_name += std::string((const char *)®isters[0], 4);
- processor_name += std::string((const char *)®isters[1], 4);
- processor_name += std::string((const char *)®isters[2], 4);
- processor_name += std::string((const char *)®isters[3], 4);
+ processor_name += QByteArray(reinterpret_cast(®isters[0]), 4);
+ processor_name += QByteArray(reinterpret_cast(®isters[1]), 4);
+ processor_name += QByteArray(reinterpret_cast(®isters[2]), 4);
+ processor_name += QByteArray(reinterpret_cast(®isters[3]), 4);
i = 0x80000003;
asm volatile
("cpuid" : "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3])
: "a" (i), "c" (0));
- processor_name += std::string((const char *)®isters[0], 4);
- processor_name += std::string((const char *)®isters[1], 4);
- processor_name += std::string((const char *)®isters[2], 4);
- processor_name += std::string((const char *)®isters[3], 4);
+ processor_name += QByteArray(reinterpret_cast(®isters[0]), 4);
+ processor_name += QByteArray(reinterpret_cast(®isters[1]), 4);
+ processor_name += QByteArray(reinterpret_cast(®isters[2]), 4);
+ processor_name += QByteArray(reinterpret_cast(®isters[3]), 4);
i = 0x80000004;
asm volatile
("cpuid" : "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3])
: "a" (i), "c" (0));
- processor_name += std::string((const char *)®isters[0], 4);
- processor_name += std::string((const char *)®isters[1], 4);
- processor_name += std::string((const char *)®isters[2], 4);
- processor_name += std::string((const char *)®isters[3], 3);
+ processor_name += QByteArray(reinterpret_cast(®isters[0]), 4);
+ processor_name += QByteArray(reinterpret_cast(®isters[1]), 4);
+ processor_name += QByteArray(reinterpret_cast(®isters[2]), 4);
+ processor_name += QByteArray(reinterpret_cast(®isters[3]), 4);
+ processor_name += "\n";
+#else
+ processor_name += "Unknown";
+#endif
// compiler
#ifdef __GNUC__
@@ -320,7 +333,7 @@
+ total_ram
+ screen_size
+ number_of_screens
- + QString::fromStdString(processor_name + "\n")
+ + processor_name
+ number_of_cores
+ compiler_version
+ compiler_bits
@@ -443,7 +456,8 @@
QString email = this->email->text();
QString captchaCode = this->captcha_code->text();
QString captchaID = QString::number(this->captchaID);
- QString version = "HedgewarsFoundation-Hedgewars-" + (cVersionString?(*cVersionString):QString(""));
+ QString version = "HedgewarsFoundation-Hedgewars-v" + *cVersionString + "_r" +
+ *cRevisionString + "|" + *cHashString;
if (summary.isEmpty() || description.isEmpty())
{
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/widget/flowlayout.cpp
--- a/QTfrontend/ui/widget/flowlayout.cpp Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,190 +0,0 @@
- /****************************************************************************
- **
- ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
- ** All rights reserved.
- ** Contact: Nokia Corporation (qt-info@nokia.com)
- **
- ** This file is part of the examples of the Qt Toolkit.
- **
- ** $QT_BEGIN_LICENSE:BSD$
- ** You may use this file under the terms of the BSD license as follows:
- **
- ** "Redistribution and use in source and binary forms, with or without
- ** modification, are permitted provided that the following conditions are
- ** met:
- ** * Redistributions of source code must retain the above copyright
- ** notice, this list of conditions and the following disclaimer.
- ** * Redistributions in binary form must reproduce the above copyright
- ** notice, this list of conditions and the following disclaimer in
- ** the documentation and/or other materials provided with the
- ** distribution.
- ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
- ** the names of its contributors may be used to endorse or promote
- ** products derived from this software without specific prior written
- ** permission.
- **
- ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
- ** $QT_END_LICENSE$
- **
- ****************************************************************************/
-
- #include
-
- #include "flowlayout.h"
-
-FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing)
- : QLayout(parent), m_hSpace(hSpacing), m_vSpace(vSpacing)
-{
- setContentsMargins(margin, margin, margin, margin);
-}
-
-FlowLayout::FlowLayout(int margin, int hSpacing, int vSpacing)
- : m_hSpace(hSpacing), m_vSpace(vSpacing)
-{
- setContentsMargins(margin, margin, margin, margin);
-}
-
-FlowLayout::~FlowLayout()
-{
- QLayoutItem *item;
- while ((item = takeAt(0)))
- delete item;
-}
-
-void FlowLayout::addItem(QLayoutItem *item)
-{
- itemList.append(item);
-}
-
-int FlowLayout::horizontalSpacing() const
-{
- if (m_hSpace >= 0) {
- return m_hSpace;
- } else {
- return smartSpacing(QStyle::PM_LayoutHorizontalSpacing);
- }
-}
-
-int FlowLayout::verticalSpacing() const
-{
- if (m_vSpace >= 0) {
- return m_vSpace;
- } else {
- return smartSpacing(QStyle::PM_LayoutVerticalSpacing);
- }
-}
-
-int FlowLayout::count() const
-{
- return itemList.size();
-}
-
-QLayoutItem *FlowLayout::itemAt(int index) const
-{
- return itemList.value(index);
-}
-
-QLayoutItem *FlowLayout::takeAt(int index)
-{
- if (index >= 0 && index < itemList.size())
- return itemList.takeAt(index);
- else
- return 0;
-}
-
-Qt::Orientations FlowLayout::expandingDirections() const
-{
- return 0;
-}
-
-bool FlowLayout::hasHeightForWidth() const
-{
- return true;
-}
-
-int FlowLayout::heightForWidth(int width) const
-{
- int height = doLayout(QRect(0, 0, width, 0), true);
- return height;
-}
-
-void FlowLayout::setGeometry(const QRect &rect)
-{
- QLayout::setGeometry(rect);
- doLayout(rect, false);
-}
-
-QSize FlowLayout::sizeHint() const
-{
- return minimumSize();
-}
-
-QSize FlowLayout::minimumSize() const
-{
- QSize size;
- QLayoutItem *item;
- foreach (item, itemList)
- size = size.expandedTo(item->minimumSize());
-
- size += QSize(2*margin(), 2*margin());
- return size;
-}
-
-int FlowLayout::doLayout(const QRect &rect, bool testOnly) const
-{
- int left, top, right, bottom;
- getContentsMargins(&left, &top, &right, &bottom);
- QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom);
- int x = effectiveRect.x();
- int y = effectiveRect.y();
- int lineHeight = 0;
-
- QLayoutItem *item;
- foreach (item, itemList) {
- QWidget *wid = item->widget();
- int spaceX = horizontalSpacing();
- if (spaceX == -1)
- spaceX = wid->style()->layoutSpacing(
- QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal);
- int spaceY = verticalSpacing();
- if (spaceY == -1)
- spaceY = wid->style()->layoutSpacing(
- QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical);
- int nextX = x + item->sizeHint().width() + spaceX;
- if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) {
- x = effectiveRect.x();
- y = y + lineHeight + spaceY;
- nextX = x + item->sizeHint().width() + spaceX;
- lineHeight = 0;
- }
-
- if (!testOnly)
- item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));
-
- x = nextX;
- lineHeight = qMax(lineHeight, item->sizeHint().height());
- }
- return y + lineHeight - rect.y() + bottom;
-}
-int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const
-{
- QObject *parent = this->parent();
- if (!parent) {
- return -1;
- } else if (parent->isWidgetType()) {
- QWidget *pw = static_cast(parent);
- return pw->style()->pixelMetric(pm, 0, pw);
- } else {
- return static_cast(parent)->spacing();
- }
-}
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/widget/flowlayout.h
--- a/QTfrontend/ui/widget/flowlayout.h Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
- /****************************************************************************
- **
- ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
- ** All rights reserved.
- ** Contact: Nokia Corporation (qt-info@nokia.com)
- **
- ** This file is part of the examples of the Qt Toolkit.
- **
- ** $QT_BEGIN_LICENSE:BSD$
- ** You may use this file under the terms of the BSD license as follows:
- **
- ** "Redistribution and use in source and binary forms, with or without
- ** modification, are permitted provided that the following conditions are
- ** met:
- ** * Redistributions of source code must retain the above copyright
- ** notice, this list of conditions and the following disclaimer.
- ** * Redistributions in binary form must reproduce the above copyright
- ** notice, this list of conditions and the following disclaimer in
- ** the documentation and/or other materials provided with the
- ** distribution.
- ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
- ** the names of its contributors may be used to endorse or promote
- ** products derived from this software without specific prior written
- ** permission.
- **
- ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
- ** $QT_END_LICENSE$
- **
- ****************************************************************************/
-
- #ifndef FLOWLAYOUT_H
- #define FLOWLAYOUT_H
-
- #include
- #include
- #include
- #include
- class FlowLayout : public QLayout
- {
- public:
- FlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1);
- FlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1);
- ~FlowLayout();
-
- void addItem(QLayoutItem *item);
- int horizontalSpacing() const;
- int verticalSpacing() const;
- Qt::Orientations expandingDirections() const;
- bool hasHeightForWidth() const;
- int heightForWidth(int) const;
- int count() const;
- QLayoutItem *itemAt(int index) const;
- QSize minimumSize() const;
- void setGeometry(const QRect &rect);
- QSize sizeHint() const;
- QLayoutItem *takeAt(int index);
-
- private:
- int doLayout(const QRect &rect, bool testOnly) const;
- int smartSpacing(QStyle::PixelMetric pm) const;
-
- QList itemList;
- int m_hSpace;
- int m_vSpace;
- };
-
- #endif
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/widget/gamecfgwidget.cpp
--- a/QTfrontend/ui/widget/gamecfgwidget.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/ui/widget/gamecfgwidget.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -49,6 +49,7 @@
setMaximumHeight(447);
setMinimumWidth(470);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ m_master = true;
// Easy containers for the map/game options in either stacked or tabbed mode
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/widget/hatprompt.cpp
--- a/QTfrontend/ui/widget/hatprompt.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/ui/widget/hatprompt.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -35,6 +35,26 @@
#include "HatModel.h"
#include "hatprompt.h"
+void HatListView::moveUp()
+{
+ setCurrentIndex(moveCursor(QAbstractItemView::MoveUp, Qt::NoModifier));
+}
+
+void HatListView::moveDown()
+{
+ setCurrentIndex(moveCursor(QAbstractItemView::MoveDown, Qt::NoModifier));
+}
+
+void HatListView::moveLeft()
+{
+ setCurrentIndex(moveCursor(QAbstractItemView::MoveLeft, Qt::NoModifier));
+}
+
+void HatListView::moveRight()
+{
+ setCurrentIndex(moveCursor(QAbstractItemView::MoveRight, Qt::NoModifier));
+}
+
HatPrompt::HatPrompt(int currentIndex, QWidget* parent) : QDialog(parent)
{
setModal(true);
@@ -60,7 +80,7 @@
QHBoxLayout * topLayout = new QHBoxLayout();
// Help/prompt message at top
- QLabel * lblDesc = new QLabel(tr("Select a hat"));
+ QLabel * lblDesc = new QLabel(tr("Search for a hat:"));
lblDesc->setObjectName("lblDesc");
lblDesc->setStyleSheet("#lblDesc { color: #130F2A; background: #F6CB1C; border: solid 4px #F6CB1C; border-top-left-radius: 10px; padding: 4px 10px;}");
lblDesc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
@@ -72,22 +92,18 @@
filterContainer->setFixedHeight(24);
filterContainer->setObjectName("filterContainer");
filterContainer->setStyleSheet("#filterContainer { background: #F6CB1C; border-top-right-radius: 10px; padding: 3px; }");
- filterContainer->setFixedWidth(250);
+ filterContainer->setFixedWidth(150);
txtFilter = new LineEditCursor(filterContainer);
- txtFilter->setFixedWidth(250);
+ txtFilter->setFixedWidth(150);
txtFilter->setFocus();
txtFilter->setFixedHeight(22);
+ txtFilter->setStyleSheet("LineEditCursor { border-width: 0px; border-radius: 6px; margin-top: 3px; margin-right: 3px; padding-left: 4px; padding-bottom: 2px; background-color: rgb(23, 11, 54); } LineEditCursor:hover, LineEditCursor:focus { background-color: rgb(13, 5, 68); }");
connect(txtFilter, SIGNAL(textChanged(const QString &)), this, SLOT(filterChanged(const QString &)));
connect(txtFilter, SIGNAL(moveUp()), this, SLOT(moveUp()));
connect(txtFilter, SIGNAL(moveDown()), this, SLOT(moveDown()));
connect(txtFilter, SIGNAL(moveLeft()), this, SLOT(moveLeft()));
connect(txtFilter, SIGNAL(moveRight()), this, SLOT(moveRight()));
- // Filter label
- QLabel * lblFilter = new QLabel(tr("Filter: "), txtFilter);
- lblFilter->setStyleSheet(QString("background: none; margin-left: -%1px; margin-top: 4px;").arg(lblFilter->width() / 2 - 3));
- txtFilter->setStyleSheet(QString("border-width: 0px; background-color: rgb(13, 5, 68); border-radius: 6px; margin-top: 3px; margin-right: 3px; padding-left: %1px; padding-bottom: 2px;").arg(lblFilter->width() / 2));
-
// Corner widget
QLabel * corner = new QLabel();
corner->setPixmap(QPixmap(QString::fromUtf8(":/res/inverse-corner-bl.png")));
@@ -132,22 +148,22 @@
void HatPrompt::moveUp()
{
- list->setCurrentIndex(list->moveCursor(QAbstractItemView::MoveUp, Qt::NoModifier));
+ list->moveUp();
}
void HatPrompt::moveDown()
{
- list->setCurrentIndex(list->moveCursor(QAbstractItemView::MoveDown, Qt::NoModifier));
+ list->moveDown();
}
void HatPrompt::moveLeft()
{
- list->setCurrentIndex(list->moveCursor(QAbstractItemView::MoveLeft, Qt::NoModifier));
+ list->moveLeft();
}
void HatPrompt::moveRight()
{
- list->setCurrentIndex(list->moveCursor(QAbstractItemView::MoveRight, Qt::NoModifier));
+ list->moveRight();
}
void HatPrompt::onAccepted()
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/widget/hatprompt.h
--- a/QTfrontend/ui/widget/hatprompt.h Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/ui/widget/hatprompt.h Tue Apr 02 21:00:57 2013 +0200
@@ -34,6 +34,10 @@
public:
HatListView(QWidget* parent = 0) : QListView(parent){}
+ void moveUp();
+ void moveDown();
+ void moveLeft();
+ void moveRight();
};
class HatPrompt : public QDialog
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/widget/mapContainer.cpp
--- a/QTfrontend/ui/widget/mapContainer.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/ui/widget/mapContainer.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -132,14 +132,15 @@
QLabel * lblMapPreviewText = new QLabel(this);
lblMapPreviewText->setText(tr("Map preview:"));
leftLayout->addWidget(lblMapPreviewText, 0);
- leftLayout->addSpacing(2);
/* Map Preview */
- mapPreview = new QLabel(this);
+ mapPreview = new QPushButton(this);
mapPreview->setObjectName("mapPreview");
mapPreview->setFixedSize(256, 128);
+ mapPreview->setContentsMargins(0, 0, 0, 0);
leftLayout->addWidget(mapPreview, 0);
+ connect(mapPreview, SIGNAL(clicked()), this, SLOT(previewClicked()));
/* Bottom-Left layout */
@@ -215,7 +216,7 @@
mazeStyles = new QListWidget();
new QListWidgetItem(tr("Small tunnels"), mazeStyles);
new QListWidgetItem(tr("Medium tunnels"), mazeStyles);
- new QListWidgetItem(tr("Largetunnels"), mazeStyles);
+ new QListWidgetItem(tr("Large tunnels"), mazeStyles);
new QListWidgetItem(tr("Small islands"), mazeStyles);
new QListWidgetItem(tr("Medium islands"), mazeStyles);
new QListWidgetItem(tr("Large islands"), mazeStyles);
@@ -230,7 +231,7 @@
lblDesc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
lblDesc->setAlignment(Qt::AlignTop | Qt::AlignLeft);
lblDesc->setStyleSheet("font: 10px;");
- bottomLeftLayout->addWidget(lblDesc, 1);
+ bottomLeftLayout->addWidget(lblDesc, 100);
/* Add stretch above theme button */
@@ -249,14 +250,13 @@
/* Set defaults */
- setRandomTheme();
setRandomSeed();
setMazeSize(0);
setTemplateFilter(0);
staticMapChanged(m_staticMapModel->index(0, 0));
missionMapChanged(m_missionMapModel->index(0, 0));
- updateTheme(m_themeModel->index(0, 0));
changeMapType(MapModel::GeneratedMap);
+ setRandomTheme();
}
void HWMapContainer::setImage(const QImage newImage)
@@ -270,7 +270,7 @@
px.setMask(bm);
p.fillRect(pxres.rect(), linearGrad);
- p.drawPixmap(QPoint(0, 0), px);
+ p.drawPixmap(0, 0, px);
addInfoToPreview(pxres);
pMap = 0;
@@ -300,7 +300,14 @@
p.drawText(image.rect().width() - hhSmall.rect().width() - 14 - (hhLimit > 9 ? 10 : 0), 18, text);
p.drawPixmap(image.rect().width() - hhSmall.rect().width() - 5, 5, hhSmall.rect().width(), hhSmall.rect().height(), hhSmall);
- mapPreview->setPixmap(finalImage);
+ // Shrink, crop, and center preview image
+ QPixmap centered(QSize(m_previewSize.width() - 6, m_previewSize.height() - 6));
+ QPainter pc(¢ered);
+ pc.fillRect(centered.rect(), linearGrad);
+ pc.drawPixmap(-3, -3, finalImage);
+
+ mapPreview->setIcon(QIcon(centered));
+ mapPreview->setIconSize(centered.size());
}
void HWMapContainer::askForGeneratedPreview()
@@ -333,6 +340,19 @@
cType->setEnabled(false);
}
+void HWMapContainer::previewClicked()
+{
+ switch (m_mapInfo.type)
+ {
+ case MapModel::HandDrawnMap:
+ emit drawMapRequested();
+ break;
+ default:
+ setRandomMap();
+ break;
+ }
+}
+
QString HWMapContainer::getCurrentSeed() const
{
return m_seed;
@@ -432,7 +452,7 @@
void HWMapContainer::setTheme(const QString & theme)
{
- QModelIndexList mdl = m_themeModel->match(m_themeModel->index(0), Qt::DisplayRole, theme);
+ QModelIndexList mdl = m_themeModel->match(m_themeModel->index(0), ThemeModel::ActualNameRole, theme);
if(mdl.size())
updateTheme(mdl.at(0));
@@ -442,6 +462,8 @@
void HWMapContainer::setRandomMap()
{
+ if (!m_master) return;
+
setRandomSeed();
switch(m_mapInfo.type)
{
@@ -471,6 +493,7 @@
if(!m_themeModel->rowCount()) return;
quint32 themeNum = rand() % m_themeModel->rowCount();
updateTheme(m_themeModel->index(themeNum));
+ emit themeChanged(m_theme);
}
void HWMapContainer::intSetTemplateFilter(int filter)
@@ -594,7 +617,8 @@
{
case MapModel::Invalid:
failIcon = QPixmap(":/res/btnDisabled.png");
- mapPreview->setPixmap(failIcon);
+ mapPreview->setIcon(QIcon(failIcon));
+ mapPreview->setIconSize(failIcon.size());
break;
case MapModel::GeneratedMap:
askForGeneratedPreview();
@@ -611,7 +635,7 @@
if(!success)
{
- mapPreview->setPixmap(QPixmap());
+ mapPreview->setIcon(QIcon());
return;
}
@@ -730,6 +754,8 @@
}
}
+ repaint();
+
emit mapgenChanged(mapgen);
}
@@ -752,7 +778,7 @@
void HWMapContainer::showThemePrompt()
{
- ThemePrompt prompt(this);
+ ThemePrompt prompt(m_themeID, this);
int theme = prompt.exec() - 1; // Since 0 means canceled, so all indexes are +1'd
if (theme < 0) return;
@@ -763,8 +789,9 @@
void HWMapContainer::updateTheme(const QModelIndex & current)
{
- m_theme = selectedTheme = current.data().toString();
- QIcon icon = qVariantValue(current.data(Qt::UserRole));
+ m_theme = selectedTheme = current.data(ThemeModel::ActualNameRole).toString();
+ m_themeID = current.row();
+ QIcon icon = qVariantValue(current.data(Qt::DecorationRole));
QSize iconSize = icon.actualSize(QSize(65535, 65535));
btnTheme->setFixedHeight(64);
btnTheme->setIconSize(iconSize);
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/widget/mapContainer.h
--- a/QTfrontend/ui/widget/mapContainer.h Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/ui/widget/mapContainer.h Tue Apr 02 21:00:57 2013 +0200
@@ -107,13 +107,14 @@
void missionMapChanged(const QModelIndex & map, const QModelIndex & old = QModelIndex());
void loadDrawing();
void showSeedPrompt();
+ void previewClicked();
protected:
virtual void resizeEvent ( QResizeEvent * event );
private:
QVBoxLayout mainLayout;
- QLabel* mapPreview;
+ QPushButton* mapPreview;
QComboBox* chooseMap;
MapModel * m_staticMapModel;
MapModel * m_missionMapModel;
@@ -162,6 +163,7 @@
void updateThemeButtonSize();
MapModel::MapInfo m_mapInfo;
+ int m_themeID;
QString m_theme;
QString m_curMap;
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/widget/roomnameprompt.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/roomnameprompt.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,82 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "roomnameprompt.h"
+
+RoomNamePrompt::RoomNamePrompt(QWidget* parent, const QString & roomName) : QDialog(parent)
+{
+ setModal(true);
+ setWindowFlags(Qt::Sheet);
+ setWindowModality(Qt::WindowModal);
+ setMinimumSize(360, 130);
+ resize(360, 130);
+ setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+
+ // Layout
+ QVBoxLayout * dialogLayout = new QVBoxLayout(this);
+
+ // Label
+ label = new QLabel(tr("Enter a name for your room."));
+ label->setWordWrap(true);
+ dialogLayout->addWidget(label, 0);
+
+ // Input box
+ editBox = new QLineEdit();
+ editBox->setText(roomName);
+ editBox->setMaxLength(59); // It didn't like 60 :(
+ editBox->setStyleSheet("QLineEdit { padding: 3px; }");
+ editBox->selectAll();
+ dialogLayout->addWidget(editBox, 1);
+
+ dialogLayout->addStretch(1);
+
+ // Buttons
+ QHBoxLayout * buttonLayout = new QHBoxLayout();
+ buttonLayout->addStretch(1);
+ dialogLayout->addLayout(buttonLayout);
+
+ QPushButton * btnCancel = new QPushButton(tr("Cancel"));
+ QPushButton * btnOkay = new QPushButton(tr("Create room"));
+ connect(btnCancel, SIGNAL(clicked()), this, SLOT(reject()));
+ connect(btnOkay, SIGNAL(clicked()), this, SLOT(accept()));
+#ifdef Q_WS_MAC
+ buttonLayout->addWidget(btnCancel);
+ buttonLayout->addWidget(btnOkay);
+#else
+ buttonLayout->addWidget(btnOkay);
+ buttonLayout->addWidget(btnCancel);
+#endif
+ btnOkay->setDefault(true);
+
+ setStyleSheet("QPushButton { padding: 5px; }");
+
+ connect(btnOkay, SIGNAL(clicked()), this, SLOT(setRoomName()));
+}
+
+void RoomNamePrompt::setRoomName()
+{
+ emit roomNameChosen(editBox->text());
+}
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/widget/roomnameprompt.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/roomnameprompt.h Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,45 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef ROOMNAMEPROMPT_H
+#define ROOMNAMEPROMPT_H
+
+#include
+
+class QLineEdit;
+class QLabel;
+
+class RoomNamePrompt : public QDialog
+{
+ Q_OBJECT
+
+ public:
+ RoomNamePrompt(QWidget* parent, const QString & roomName);
+
+ signals:
+ void roomNameChosen(const QString & roomName);
+
+ private slots:
+ void setRoomName();
+
+ private:
+ QLineEdit * editBox;
+ QLabel * label;
+};
+
+#endif // ROOMNAMEPROMPT_H
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/widget/seedprompt.cpp
--- a/QTfrontend/ui/widget/seedprompt.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/ui/widget/seedprompt.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -62,8 +62,13 @@
QPushButton * btnOkay = new QPushButton(tr("Set seed"));
connect(btnCancel, SIGNAL(clicked()), this, SLOT(reject()));
connect(btnOkay, SIGNAL(clicked()), this, SLOT(accept()));
+#ifdef Q_WS_MAC
buttonLayout->addWidget(btnCancel);
buttonLayout->addWidget(btnOkay);
+#else
+ buttonLayout->addWidget(btnOkay);
+ buttonLayout->addWidget(btnCancel);
+#endif
btnOkay->setDefault(true);
}
else
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/widget/teamselect.cpp
--- a/QTfrontend/ui/widget/teamselect.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/ui/widget/teamselect.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -257,7 +257,7 @@
frameDontPlaying = new FrameTeams();
// Add notice about number of required teams.
- numTeamNotice = new QLabel("Two teams are required to play!");
+ numTeamNotice = new QLabel(tr("At least two teams are required to play!"));
mainLayout.addWidget(numTeamNotice);
QPalette p;
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/widget/themeprompt.cpp
--- a/QTfrontend/ui/widget/themeprompt.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/ui/widget/themeprompt.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -17,20 +17,46 @@
*/
#include
-#include
+#include
+#include
#include
#include
#include
#include
#include
+#include
+#include
#include
+#include
+#include
-#include "flowlayout.h"
#include "DataManager.h"
+#include "lineeditcursor.h"
#include "ThemeModel.h"
#include "themeprompt.h"
-ThemePrompt::ThemePrompt(QWidget* parent) : QDialog(parent)
+
+void ThemeListView::moveUp()
+{
+ setCurrentIndex(moveCursor(QAbstractItemView::MoveUp, Qt::NoModifier));
+}
+
+void ThemeListView::moveDown()
+{
+ setCurrentIndex(moveCursor(QAbstractItemView::MoveDown, Qt::NoModifier));
+}
+
+void ThemeListView::moveLeft()
+{
+ setCurrentIndex(moveCursor(QAbstractItemView::MoveLeft, Qt::NoModifier));
+}
+
+void ThemeListView::moveRight()
+{
+ setCurrentIndex(moveCursor(QAbstractItemView::MoveRight, Qt::NoModifier));
+}
+
+ThemePrompt::ThemePrompt(int currentIndex, QWidget* parent) : QDialog(parent)
{
setModal(true);
setWindowFlags(Qt::Sheet);
@@ -39,63 +65,122 @@
resize(550, 430);
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ setStyleSheet("QPushButton { padding: 5px; margin-top: 10px; }");
+
+ // Theme model, and a model for setting a filter
+ ThemeModel * themeModel = DataManager::instance().themeModel();
+ filterModel = new QSortFilterProxyModel();
+ filterModel->setSourceModel(themeModel);
+ filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
+
// Grid
- QVBoxLayout * dialogLayout = new QVBoxLayout(this);
+ QGridLayout * dialogLayout = new QGridLayout(this);
dialogLayout->setSpacing(0);
+ dialogLayout->setColumnStretch(1, 1);
+
+ QHBoxLayout * topLayout = new QHBoxLayout();
// Help/prompt message at top
- QLabel * lblDesc = new QLabel(tr("Select a theme for this map"));
- lblDesc->setStyleSheet("color: #130F2A; background: #F6CB1C; border: solid 4px #F6CB1C; border-top-left-radius: 10px; border-top-right-radius: 10px; padding: auto 20px;");
+ QLabel * lblDesc = new QLabel(tr("Search for a theme:"));
+ lblDesc->setObjectName("lblDesc");
+ lblDesc->setStyleSheet("#lblDesc { color: #130F2A; background: #F6CB1C; border: solid 4px #F6CB1C; border-top-left-radius: 10px; padding: 4px 10px;}");
lblDesc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
lblDesc->setFixedHeight(24);
lblDesc->setMinimumWidth(0);
- // Scroll area and container for theme icons
- QWidget * themesContainer = new QWidget();
- FlowLayout * themesGrid = new FlowLayout();
- themesContainer->setLayout(themesGrid);
- QScrollArea * scrollArea = new QScrollArea();
- scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
- scrollArea->setObjectName("scrollArea");
- scrollArea->setStyleSheet("QScrollBar, #scrollArea { background-color: #130F2A; } #scrollArea { border-color: #F6CB1C; border-width: 3px; border-top-width: 0; border-style: solid; border-bottom-left-radius: 10px; border-bottom-right-radius: 10px; }");
- scrollArea->setWidgetResizable(true);
- scrollArea->setFrameShape(QFrame::NoFrame);
- scrollArea->setWidget(themesContainer);
+ // Filter text box
+ QWidget * filterContainer = new QWidget();
+ filterContainer->setFixedHeight(24);
+ filterContainer->setObjectName("filterContainer");
+ filterContainer->setStyleSheet("#filterContainer { background: #F6CB1C; border-top-right-radius: 10px; padding: 3px; }");
+ filterContainer->setFixedWidth(150);
+ txtFilter = new LineEditCursor(filterContainer);
+ txtFilter->setFixedWidth(150);
+ txtFilter->setFocus();
+ txtFilter->setFixedHeight(22);
+ txtFilter->setStyleSheet("LineEditCursor { border-width: 0px; border-radius: 6px; margin-top: 3px; margin-right: 3px; padding-left: 4px; padding-bottom: 2px; background-color: rgb(23, 11, 54); } LineEditCursor:hover, LineEditCursor:focus { background-color: rgb(13, 5, 68); }");
+ connect(txtFilter, SIGNAL(textChanged(const QString &)), this, SLOT(filterChanged(const QString &)));
+ connect(txtFilter, SIGNAL(moveUp()), this, SLOT(moveUp()));
+ connect(txtFilter, SIGNAL(moveDown()), this, SLOT(moveDown()));
+ connect(txtFilter, SIGNAL(moveLeft()), this, SLOT(moveLeft()));
+ connect(txtFilter, SIGNAL(moveRight()), this, SLOT(moveRight()));
+
+ // Corner widget
+ QLabel * corner = new QLabel();
+ corner->setPixmap(QPixmap(QString::fromUtf8(":/res/inverse-corner-bl.png")));
+ corner->setFixedSize(10, 10);
+
+ // Add widgets to top layout
+ topLayout->addWidget(lblDesc);
+ topLayout->addWidget(filterContainer);
+ topLayout->addWidget(corner, 0, Qt::AlignBottom);
+ topLayout->addStretch(1);
// Cancel button (closes dialog)
QPushButton * btnCancel = new QPushButton(tr("Cancel"));
- btnCancel->setStyleSheet("padding: 5px; margin-top: 10px;");
connect(btnCancel, SIGNAL(clicked()), this, SLOT(reject()));
+ // Select button
+ QPushButton * btnSelect = new QPushButton(tr("Use selected theme"));
+ btnSelect->setDefault(true);
+ connect(btnSelect, SIGNAL(clicked()), this, SLOT(onAccepted()));
+
+ // Add themes
+ list = new ThemeListView();
+ list->setModel(filterModel);
+ list->setViewMode(QListView::IconMode);
+ list->setResizeMode(QListView::Adjust);
+ list->setMovement(QListView::Static);
+ list->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ list->setSpacing(8);
+ list->setWordWrap(true);
+ list->setSelectionMode(QAbstractItemView::SingleSelection);
+ list->setObjectName("themeList");
+ list->setCurrentIndex(filterModel->index(currentIndex, 0));
+ connect(list, SIGNAL(activated(const QModelIndex &)), this, SLOT(themeChosen(const QModelIndex &)));
+ connect(list, SIGNAL(clicked(const QModelIndex &)), this, SLOT(themeChosen(const QModelIndex &)));
+
// Add elements to layouts
- dialogLayout->addWidget(lblDesc, 0);
- dialogLayout->addWidget(scrollArea, 1);
- dialogLayout->addWidget(btnCancel, 0, Qt::AlignLeft);
+ dialogLayout->addLayout(topLayout, 0, 0, 1, 3);
+ dialogLayout->addWidget(list, 1, 0, 1, 3);
+ dialogLayout->addWidget(btnCancel, 2, 0, 1, 1, Qt::AlignLeft);
+ dialogLayout->addWidget(btnSelect, 2, 2, 1, 1, Qt::AlignRight);
+}
- // Tooltip label for theme name
- lblToolTip = new QLabel(this);
+void ThemePrompt::moveUp()
+{
+ list->moveUp();
+}
- // Add theme buttons
- ThemeModel * themes = DataManager::instance().themeModel();
- for (int i = 0; i < themes->rowCount(); i++)
- {
- QModelIndex index = themes->index(i, 0);
- QToolButton * btn = new QToolButton();
- bool dlc = themes->data(index, Qt::UserRole + 2).toBool();
- btn->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
- btn->setIcon(qVariantValue(themes->data(index, Qt::UserRole)));
- btn->setText((dlc ? "*" : "") + themes->data(index, Qt::DisplayRole).toString());
- btn->setIconSize(QSize(60, 60));
- btn->setProperty("themeID", QVariant(i));
- btn->setStyleSheet("padding: 2px;");
- connect(btn, SIGNAL(clicked()), this, SLOT(themeClicked()));
- themesGrid->addWidget(btn);
- }
+void ThemePrompt::moveDown()
+{
+ list->moveDown();
+}
+
+void ThemePrompt::moveLeft()
+{
+ list->moveLeft();
+}
+
+void ThemePrompt::moveRight()
+{
+ list->moveRight();
+}
+
+void ThemePrompt::onAccepted()
+{
+ themeChosen(list->currentIndex());
}
// When a theme is selected
-void ThemePrompt::themeClicked()
+void ThemePrompt::themeChosen(const QModelIndex & index)
{
- QWidget * btn = (QWidget*)sender();
- done(btn->property("themeID").toInt() + 1); // Since returning 0 means canceled
+ done(filterModel->mapToSource(index).row() + 1); // Since returning 0 means canceled
}
+
+// When the text in the filter text box is changed
+void ThemePrompt::filterChanged(const QString & text)
+{
+ filterModel->setFilterFixedString(text);
+ list->setCurrentIndex(filterModel->index(0, 0));
+}
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui/widget/themeprompt.h
--- a/QTfrontend/ui/widget/themeprompt.h Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/ui/widget/themeprompt.h Tue Apr 02 21:00:57 2013 +0200
@@ -21,21 +21,45 @@
#include
#include
+#include
-class QLabel;
+class QLineEdit;
+class QModelIndex;
+class QSortFilterProxyModel;
+class LineEditCursor;
+
+class ThemeListView : public QListView
+{
+ friend class ThemePrompt;
+
+ public:
+ ThemeListView(QWidget* parent = 0) : QListView(parent){}
+ void moveUp();
+ void moveDown();
+ void moveLeft();
+ void moveRight();
+};
class ThemePrompt : public QDialog
{
Q_OBJECT
public:
- ThemePrompt(QWidget* parent);
+ ThemePrompt(int currentIndex = 0, QWidget* parent = 0);
private:
- QLabel * lblToolTip;
+ LineEditCursor * txtFilter;
+ ThemeListView * list;
+ QSortFilterProxyModel * filterModel;
private slots:
- void themeClicked();
+ void onAccepted();
+ void themeChosen(const QModelIndex & index);
+ void filterChanged(const QString & text);
+ void moveUp();
+ void moveDown();
+ void moveLeft();
+ void moveRight();
};
#endif // THEMEPROMPT_H
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/ui_hwform.cpp
--- a/QTfrontend/ui_hwform.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/ui_hwform.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -54,7 +54,11 @@
HWForm->setObjectName(QString::fromUtf8("HWForm"));
HWForm->resize(QSize(640, 480).expandedTo(HWForm->minimumSizeHint()));
HWForm->setMinimumSize(QSize(720, 450));
- HWForm->setWindowTitle(QMainWindow::tr("Hedgewars %1").arg(*cVersionString));
+ QString title = QMainWindow::tr("Hedgewars %1").arg(*cVersionString);
+#ifdef DEBUG
+ title += QMainWindow::tr("-r%1 (%2)").arg(*cRevisionString, *cHashString);
+#endif
+ HWForm->setWindowTitle(title);
centralWidget = new QWidget(HWForm);
centralWidget->setObjectName(QString::fromUtf8("centralWidget"));
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/util/DataManager.cpp
--- a/QTfrontend/util/DataManager.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/util/DataManager.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -176,3 +176,12 @@
m_colorsModel->item(i)->setData(QColor(colors[i]));
}
}
+
+bool DataManager::ensureFileExists(const QString &fileName)
+{
+ QFile tmpfile(fileName);
+ if (!tmpfile.exists())
+ return tmpfile.open(QFile::WriteOnly);
+ else
+ return true;
+}
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/util/DataManager.h
--- a/QTfrontend/util/DataManager.h Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/util/DataManager.h Tue Apr 02 21:00:57 2013 +0200
@@ -117,6 +117,8 @@
QStandardItemModel * colorsModel();
QStandardItemModel * bindsModel();
+ static bool ensureFileExists(const QString & fileName);
+
public slots:
/// Reloads data from storage.
void reload();
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/util/FileEngine.cpp
--- a/QTfrontend/util/FileEngine.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/util/FileEngine.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -327,12 +327,12 @@
void FileEngineHandler::mount(const QString &path)
{
- PHYSFS_mount(path.toUtf8().constData(), NULL, 1);
+ PHYSFS_mount(path.toUtf8().constData(), NULL, 0);
}
void FileEngineHandler::mount(const QString & path, const QString & mountPoint)
{
- PHYSFS_mount(path.toUtf8().constData(), mountPoint.toUtf8().constData(), 1);
+ PHYSFS_mount(path.toUtf8().constData(), mountPoint.toUtf8().constData(), 0);
}
void FileEngineHandler::setWriteDir(const QString &path)
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/util/MessageDialog.cpp
--- a/QTfrontend/util/MessageDialog.cpp Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/util/MessageDialog.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -17,23 +17,39 @@
*/
#include "MessageDialog.h"
+#include "HWApplication.h"
+
+int MessageDialog::ShowFatalMessage(const QString & msg, QWidget * parent)
+{
+ return ShowMessage(QMessageBox::tr("Hedgewars - Error"),
+ msg,
+ QMessageBox::Critical,
+ parent);
+}
int MessageDialog::ShowErrorMessage(const QString & msg, QWidget * parent)
{
- return ShowMessage(msg, QMessageBox::tr("Hedgewars - Warning"), QMessageBox::Warning, parent);
+ return ShowMessage(QMessageBox::tr("Hedgewars - Warning"),
+ msg,
+ QMessageBox::Warning,
+ parent);
}
int MessageDialog::ShowInfoMessage(const QString & msg, QWidget * parent)
{
- return ShowMessage(msg, QMessageBox::tr("Hedgewars - Information"), QMessageBox::Information, parent);
+ return ShowMessage(QMessageBox::tr("Hedgewars - Information"),
+ msg,
+ QMessageBox::Information,
+ parent);
}
-int MessageDialog::ShowMessage(const QString & msg, const QString & title, QMessageBox::Icon icon, QWidget * parent)
+int MessageDialog::ShowMessage(const QString & title, const QString & msg, QMessageBox::Icon icon, QWidget * parent)
{
- QMessageBox msgMsg(parent);
+ QMessageBox msgMsg(parent ? parent : HWApplication::activeWindow());
+ msgMsg.setWindowTitle(title != NULL ? title : "Hedgewars");
+ msgMsg.setText(msg);
msgMsg.setIcon(icon);
- msgMsg.setWindowTitle(title.isEmpty() ? QMessageBox::tr("Hedgewars") : title);
- msgMsg.setText(msg);
msgMsg.setWindowModality(Qt::WindowModal);
+
return msgMsg.exec();
}
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/util/MessageDialog.h
--- a/QTfrontend/util/MessageDialog.h Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/util/MessageDialog.h Tue Apr 02 21:00:57 2013 +0200
@@ -19,7 +19,6 @@
#ifndef MESSAGEDIALOG_H
#define MESSAGEDIALOG_H
-#include
#include
class QWidget;
@@ -27,9 +26,18 @@
class MessageDialog
{
public:
+ static int ShowFatalMessage(const QString & msg, QWidget * parent = 0);
static int ShowErrorMessage(const QString & msg, QWidget * parent = 0);
static int ShowInfoMessage(const QString & msg, QWidget * parent = 0);
- static int ShowMessage(const QString & msg, const QString & title = QString(), QMessageBox::Icon icon = QMessageBox::NoIcon, QWidget * parent = 0);
+ /**
+ * @brief Displays a message.
+ * @param title message title or NULL
if no/default title
+ * @param msg message to display
+ * @param icon (optional) icon to be displayed next to the message
+ * @param parent parent Widget
+ * @return a QMessageBox::StandardButton value indicating which button was clicked
+ */
+ static int ShowMessage(const QString & title, const QString & msg, QMessageBox::Icon icon = QMessageBox::NoIcon, QWidget * parent = 0);
};
#endif
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/util/platform/M3InstallController.m
--- a/QTfrontend/util/platform/M3InstallController.m Wed Feb 20 02:21:58 2013 +0100
+++ b/QTfrontend/util/platform/M3InstallController.m Tue Apr 02 21:00:57 2013 +0200
@@ -70,21 +70,43 @@
//Delete the app that is installed
if ([[NSFileManager defaultManager] fileExistsAtPath:appsPath]) {
- [[NSFileManager defaultManager] removeFileAtPath:appsPath handler:nil];
+ if ([NSFileManager instancesRespondToSelector:@selector(removeItemAtPath:error:)])
+ [[NSFileManager defaultManager] removeItemAtPath:appsPath error:nil];
+ else
+ //casting hides the deprecation warning
+ [(id)[NSFileManager defaultManager] removeFileAtPath:appsPath handler:nil];
}
//Delete the app that is installed
- if ([[NSFileManager defaultManager] copyPath:[[NSBundle mainBundle] bundlePath] toPath:appsPath
- handler:nil]) {
+ BOOL success = NO;
+ if ([NSFileManager instancesRespondToSelector:@selector(copyItemAtPath:toPath:error:)])
+ success = [[NSFileManager defaultManager] copyItemAtPath:[[NSBundle mainBundle] bundlePath]
+ toPath:appsPath
+ error:nil];
+ else
+ success = [(id)[NSFileManager defaultManager] copyPath:[[NSBundle mainBundle] bundlePath]
+ toPath:appsPath
+ handler:nil];
+ if (success) {
NSRunAlertPanel([NSString stringWithFormat:NSLocalizedString(@"%@ installed successfully", @"App Name installed successfully"), appName],
[NSString stringWithFormat:NSLocalizedString(@"%@ was installed in /Applications", @"App Name was installed in /Applications"), appName],
NSLocalizedString(@"Quit", @"Quit"), nil, nil);
} else {
if ([[NSFileManager defaultManager] fileExistsAtPath:userAppsPath]) {
- [[NSFileManager defaultManager] removeFileAtPath:userAppsPath handler:nil];
+ if ([NSFileManager instancesRespondToSelector:@selector(removeItemAtPath:error:)])
+ [[NSFileManager defaultManager] removeItemAtPath:userAppsPath error:nil];
+ else
+ [(id)[NSFileManager defaultManager] removeFileAtPath:userAppsPath handler:nil];
}
- if ([[NSFileManager defaultManager] copyPath:[[NSBundle mainBundle] bundlePath] toPath:userAppsPath
- handler:nil]) {
- NSRunAlertPanel([NSString stringWithFormat:NSLocalizedString(@"%@ installed successfully", @"AppName installed successfully"), appName],
+ if ([NSFileManager instancesRespondToSelector:@selector(copyItemAtPath:toPath:error:)])
+ success = [[NSFileManager defaultManager] copyItemAtPath:[[NSBundle mainBundle] bundlePath]
+ toPath:userAppsPath
+ error:nil];
+ else
+ success = [(id)[NSFileManager defaultManager] copyPath:[[NSBundle mainBundle] bundlePath]
+ toPath:userAppsPath
+ handler:nil];
+ if (success) {
+ NSRunAlertPanel([NSString stringWithFormat:NSLocalizedString(@"%@ installed successfully", @"AppName installed successfully"), appName],
[NSString stringWithFormat:NSLocalizedString(@"%@ was installed in %@", @"App Name was installed in %@"), appName, [[NSString stringWithString:@"~/Applications"] stringByExpandingTildeInPath]],
NSLocalizedString(@"Quit", @"Quit"), nil, nil);
} else {
diff -r 404ddce27b23 -r c13ebed437cb QTfrontend/weapons.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/weapons.h Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,66 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2013 Vittorio Giovara
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+// TODO: keep on documenting all the weapons
+//skip---------------------------------|
+//structure------------------------------------------------------------------|
+
+#define AMMOLINE_DEFAULT_QT "9391929422199121032235111001201000000211110101011111121"
+#define AMMOLINE_DEFAULT_PROB "0405040541600655546554464776576666666155510101115411121"
+#define AMMOLINE_DEFAULT_DELAY "0000000000000205500000040007004000000000220000000600020"
+#define AMMOLINE_DEFAULT_CRATE "1311110312111111123114111111111111111211111101111111121"
+
+#define AMMOLINE_CRAZY_QT "9999999999999999992999999999999999299999999909999992999"
+#define AMMOLINE_CRAZY_PROB "1111110111111111111111111111111111111111111101111111111"
+#define AMMOLINE_CRAZY_DELAY "0000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_CRAZY_CRATE "1311110312111111123114111111111111111211110101111111121"
+
+#define AMMOLINE_PROMODE_QT "9090009000000000000009000000000000000000000000000000000"
+#define AMMOLINE_PROMODE_PROB "0000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_PROMODE_DELAY "0000000000000205500000040007004000000000200000000000020"
+#define AMMOLINE_PROMODE_CRATE "1111110111111111111111111111111111111111100101111111121"
+
+#define AMMOLINE_SHOPPA_QT "0000009900000000000000000000000000000000000000000000000"
+#define AMMOLINE_SHOPPA_PROB "4444410044244402210112121222422000000002000400010011001"
+#define AMMOLINE_SHOPPA_DELAY "0000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_SHOPPA_CRATE "1111110111111111111111111111111111111111101101111111121"
+
+#define AMMOLINE_CLEAN_QT "1010009000010000011000000000000000000000000000001000000"
+#define AMMOLINE_CLEAN_PROB "0405040541600655546554464776576666666155510101115411121"
+#define AMMOLINE_CLEAN_DELAY "0000000000000000000000000000000000000000000000000000020"
+#define AMMOLINE_CLEAN_CRATE "1311110312111111123114111111111111111211111101111111121"
+
+#define AMMOLINE_MINES_QT "0000009900090000000300000000000000000000000000000000000"
+#define AMMOLINE_MINES_PROB "0000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_MINES_DELAY "0000000000000205500000040007004000000000200000000600020"
+#define AMMOLINE_MINES_CRATE "1111110111111111111111111111111111111111111101111111121"
+
+#define AMMOLINE_PORTALS_QT "9000009002000000002100000000000000110000090000000000000"
+#define AMMOLINE_PORTALS_PROB "0405040541600655546554464776576666666155510101115411121"
+#define AMMOLINE_PORTALS_DELAY "0000000000000205500000040007004000000000200000000600020"
+#define AMMOLINE_PORTALS_CRATE "1311110312111111123114111111111111111211111101111111121"
+
+#define AMMOLINE_ONEEVERY_QT "1111119111111111111111111111111111111111111111111111111"
+#define AMMOLINE_ONEEVERY_PROB "1111110111111111111111111111111111111111111111111111111"
+#define AMMOLINE_ONEEVERY_DELAY "0000000000000205500000040007004000000000220000000600020"
+#define AMMOLINE_ONEEVERY_CRATE "1111110111111111111111111111111111111111111111111111111"
+
+//When adding new weapons also inster one element in cDefaultAmmos list (hwconsts.cpp.in)
+
+
diff -r 404ddce27b23 -r c13ebed437cb README
--- a/README Wed Feb 20 02:21:58 2013 +0100
+++ b/README Tue Apr 02 21:00:57 2013 +0200
@@ -12,3 +12,6 @@
- http://code.google.com/p/hedgewars/wiki/BuildingOnWindows
- http://code.google.com/p/hedgewars/wiki/BuildingOnMac
+Dependencies:
+you can find an outline of the necessary dependencies in the INSTALL file.
+
diff -r 404ddce27b23 -r c13ebed437cb cmake_modules/CPackConfig.cmake
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/cmake_modules/CPackConfig.cmake Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,99 @@
+
+# revision information in cpack-generated names
+if(CMAKE_BUILD_TYPE MATCHES DEBUG)
+ set(full_suffix "${HEDGEWARS_VERSION}-r${HEDGEWARS_REVISION}")
+else()
+ set(full_suffix "${HEDGEWARS_VERSION}")
+endif()
+
+# CPack variables
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Hedgewars, a free turn-based strategy game")
+set(CPACK_PACKAGE_VENDOR "Hedgewars Project")
+set(CPACK_PACKAGE_FILE_NAME "Hedgewars-${full_suffix}")
+set(CPACK_SOURCE_PACKAGE_FILE_NAME "hedgewars-src-${full_suffix}")
+set(CPACK_SOURCE_GENERATOR "TBZ2")
+set(CPACK_PACKAGE_EXECUTABLES "hedgewars" "Hedgewars")
+set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/COPYING")
+set(CPACK_PACKAGE_INSTALL_DIRECTORY "Hedgewars ${full_suffix}")
+set(CPACK_STRIP_FILES true)
+
+if(WIN32 AND NOT UNIX)
+ set(CPACK_NSIS_DISPLAY_NAME "Hedgewars")
+ set(CPACK_NSIS_HELP_LINK "http://www.hedgewars.org/")
+ set(CPACK_NSIS_URL_INFO_ABOUT "http://www.hedgewars.org/")
+ set(CPACK_NSIS_CONTACT "unC0Rr@gmail.com")
+ set(CPACK_NSIS_MODIFY_PATH OFF)
+ set(CPACK_NSIS_EXECUTABLES_DIRECTORY "${target_binary_install_dir}")
+ set(CPACK_NSIS_MUI_FINISHPAGE_RUN "hedgewars${CMAKE_EXECUTABLE_SUFFIX}")
+ set(CPACK_GENERATOR "ZIP;NSIS")
+ set(CPACK_PACKAGE_INSTALL_REGISTRY_KEY "hedgewars")
+endif(WIN32 AND NOT UNIX)
+
+set(CPACK_SOURCE_IGNORE_FILES
+ #temporary files
+ "~"
+ ".swp"
+ #version control
+ "\\\\.hg"
+ #output binary/library
+ "\\\\.exe$"
+ "\\\\.a$"
+ "\\\\.so$"
+ "\\\\.dylib$"
+ "\\\\.dll$"
+ "\\\\.ppu$"
+ "\\\\.o$"
+ "\\\\.cxx$"
+ #graphics
+ "\\\\.xcf$"
+ "\\\\.svg$"
+ "\\\\.svgz$"
+ "\\\\.psd$"
+ "\\\\.sifz$"
+ #misc
+ "\\\\.core$"
+ "\\\\.sh$"
+ "\\\\.orig$"
+ "\\\\.layout$"
+ "\\\\.db$"
+ "\\\\.dof$"
+ #archives
+ "\\\\.zip$"
+ "\\\\.gz$"
+ "\\\\.bz2$"
+ "\\\\.tmp$"
+ #cmake-configured files
+ "hwconsts\\\\.cpp$"
+ "config\\\\.inc$"
+ "hwengine\\\\.desktop$"
+ "Info\\\\.plist$"
+ #other cmake generated files
+ "Makefile"
+ "Doxyfile"
+ "CMakeFiles"
+ "[dD]ebug$"
+ "[rR]elease$"
+ "CPack"
+ "cmake_install\\\\.cmake$"
+ "CMakeCache\\\\.txt$"
+# "^${CMAKE_CURRENT_SOURCE_DIR}/misc/libtremor"
+# "^${CMAKE_CURRENT_SOURCE_DIR}/misc/libfreetype"
+# "^${CMAKE_CURRENT_SOURCE_DIR}/misc/liblua"
+ "^${CMAKE_CURRENT_SOURCE_DIR}/misc/libopenalbridge"
+ "^${CMAKE_CURRENT_SOURCE_DIR}/project_files/frontlib"
+ "^${CMAKE_CURRENT_SOURCE_DIR}/project_files/promotional_art"
+ "^${CMAKE_CURRENT_SOURCE_DIR}/project_files/cmdlineClient"
+ "^${CMAKE_CURRENT_SOURCE_DIR}/tools/templates"
+ "^${CMAKE_CURRENT_SOURCE_DIR}/bin/checkstack*"
+ "^${CMAKE_CURRENT_SOURCE_DIR}/doc"
+ "^${CMAKE_CURRENT_SOURCE_DIR}/templates"
+ "^${CMAKE_CURRENT_SOURCE_DIR}/tmp"
+ "^${CMAKE_CURRENT_SOURCE_DIR}/utils"
+ "^${CMAKE_CURRENT_SOURCE_DIR}/share/hedgewars/Data/Maps/test"
+ "^${CMAKE_CURRENT_SOURCE_DIR}/install_manifest.txt"
+ "^${CMAKE_CURRENT_SOURCE_DIR}/CMakeCache.txt"
+ "^${CMAKE_CURRENT_SOURCE_DIR}/hedgewars\\\\."
+)
+
+include(CPack)
+
diff -r 404ddce27b23 -r c13ebed437cb cmake_modules/FindFFMPEG.cmake
--- a/cmake_modules/FindFFMPEG.cmake Wed Feb 20 02:21:58 2013 +0100
+++ b/cmake_modules/FindFFMPEG.cmake Tue Apr 02 21:00:57 2013 +0200
@@ -1,96 +1,83 @@
-# - Try to find ffmpeg libraries (libavcodec, libavformat and libavutil)
+# Find ffmpeg/libav libraries (libavcodec, libavformat and libavutil)
# Once done this will define
#
-# FFMPEG_FOUND - system has ffmpeg or libav
-# FFMPEG_INCLUDE_DIR - the ffmpeg include directory
-# FFMPEG_LIBRARIES - Link these to use ffmpeg
-# FFMPEG_LIBAVCODEC
-# FFMPEG_LIBAVFORMAT
-# FFMPEG_LIBAVUTIL
+# FFMPEG_FOUND - system has libavcodec, libavformat, libavutil
+# FFMPEG_INCLUDE_DIR - the libav include directories
+# FFMPEG_LIBRARIES - the libav libraries
+#
+# LIBAVCODEC_LIBRARY - the libavcodec library
+# LIBAVCODEC_INCLUDE_DIR - the libavcodec include directory
+# LIBAVFORMAT_LIBRARY - the libavformat library
+# LIBAVUTIL_LIBRARY - the libavutil library
#
# Copyright (c) 2008 Andreas Schneider
# Modified for other libraries by Lasse Kärkkäinen
# Modified for Hedgewars by Stepik777
+# Copyright (c) 2013 Vittorio Giovara
#
# Redistribution and use is allowed according to the terms of the New
# BSD license.
#
-set(FFMPEG_FOUND FALSE)
+include(FindPackageHandleStandardArgs)
+
-if (FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIR)
- # in cache already
- set(FFMPEG_FOUND TRUE)
-else (FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIR)
- # silence output option
- if (FFMPEG_FIND_QUIETLY)
- set(VERBOSITY "QUIET")
- endif ()
- # use pkg-config to get the directories and then use these values
- # in the FIND_PATH() and FIND_LIBRARY() calls
- find_package(PkgConfig)
- if (PKG_CONFIG_FOUND)
+# use pkg-config to get the directories and then use these values
+# in the FIND_PATH() and FIND_LIBRARY() calls
+find_package(PkgConfig)
+if (PKG_CONFIG_FOUND)
pkg_check_modules(_FFMPEG_AVCODEC libavcodec ${VERBOSITY})
pkg_check_modules(_FFMPEG_AVFORMAT libavformat ${VERBOSITY})
pkg_check_modules(_FFMPEG_AVUTIL libavutil ${VERBOSITY})
- endif (PKG_CONFIG_FOUND)
+endif (PKG_CONFIG_FOUND)
- find_path(FFMPEG_AVCODEC_INCLUDE_DIR
+find_path(LIBAVCODEC_INCLUDE_DIR
NAMES libavcodec/avcodec.h
- PATHS ${_FFMPEG_AVCODEC_INCLUDE_DIRS}
+ PATHS ${_AVCODEC_INCLUDE_DIRS}
/usr/include /usr/local/include #system level
/opt/local/include #macports
/sw/include #fink
- PATH_SUFFIXES ffmpeg libav
- )
+ PATH_SUFFIXES libav ffmpeg
+)
- find_library(FFMPEG_LIBAVCODEC
+#TODO: add other include paths
+
+find_library(LIBAVCODEC_LIBRARY
NAMES avcodec
- PATHS ${_FFMPEG_AVCODEC_LIBRARY_DIRS}
+ PATHS ${_AVCODEC_LIBRARY_DIRS}
/usr/lib /usr/local/lib #system level
/opt/local/lib #macports
/sw/lib #fink
- )
+)
- find_library(FFMPEG_LIBAVFORMAT
+find_library(LIBAVFORMAT_LIBRARY
NAMES avformat
- PATHS ${_FFMPEG_AVFORMAT_LIBRARY_DIRS}
+ PATHS ${_AVFORMAT_LIBRARY_DIRS}
/usr/lib /usr/local/lib #system level
/opt/local/lib #macports
/sw/lib #fink
- )
+)
- find_library(FFMPEG_LIBAVUTIL
+find_library(LIBAVUTIL_LIBRARY
NAMES avutil
- PATHS ${_FFMPEG_AVUTIL_LIBRARY_DIRS}
+ PATHS ${_AVUTIL_LIBRARY_DIRS}
/usr/lib /usr/local/lib #system level
/opt/local/lib #macports
/sw/lib #fink
- )
-
- if (FFMPEG_LIBAVCODEC AND FFMPEG_LIBAVFORMAT)
- set(FFMPEG_FOUND TRUE)
- endif()
-
- if (FFMPEG_FOUND)
- set(FFMPEG_INCLUDE_DIR ${FFMPEG_AVCODEC_INCLUDE_DIR})
+)
- set(FFMPEG_LIBRARIES
- ${FFMPEG_LIBAVCODEC}
- ${FFMPEG_LIBAVFORMAT}
- ${FFMPEG_LIBAVUTIL}
- )
- endif (FFMPEG_FOUND)
+find_package_handle_standard_args(FFMPEG DEFAULT_MSG LIBAVCODEC_LIBRARY LIBAVCODEC_INCLUDE_DIR
+ LIBAVFORMAT_LIBRARY
+ LIBAVUTIL_LIBRARY
+ )
+set(FFMPEG_INCLUDE_DIR ${LIBAVCODEC_INCLUDE_DIR}
+ #TODO: add other include paths
+ )
+set(FFMPEG_LIBRARIES ${LIBAVCODEC_LIBRARY}
+ ${LIBAVFORMAT_LIBRARY}
+ ${LIBAVUTIL_LIBRARY}
+ )
- if (FFMPEG_FOUND)
- if (NOT FFMPEG_FIND_QUIETLY)
- message(STATUS "Found FFMPEG/LibAV: ${FFMPEG_LIBRARIES}, ${FFMPEG_INCLUDE_DIR}")
- endif (NOT FFMPEG_FIND_QUIETLY)
- else (FFMPEG_FOUND)
- if (FFMPEG_FIND_REQUIRED)
- message(FATAL_ERROR "Could NOT find libavcodec or libavformat or libavutil")
- endif (FFMPEG_FIND_REQUIRED)
- endif (FFMPEG_FOUND)
+mark_as_advanced(FFMPEG_INCLUDE_DIR FFMPEG_LIBRARIES LIBAVCODEC_LIBRARY LIBAVCODEC_INCLUDE_DIR LIBAVFORMAT_LIBRARY LIBAVUTIL_LIBRARY)
-endif (FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIR)
diff -r 404ddce27b23 -r c13ebed437cb cmake_modules/FindFreePascal.cmake
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/cmake_modules/FindFreePascal.cmake Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,37 @@
+# - Try to find the FreePascal executable
+# Once done this will define
+#
+# FREEPASCAL_FOUND - system has Freepascal
+# FREEPASCAL_VERSION - Freepascal version
+# FREEPASCAL_EXECUTABLE - Freepascal executable
+#
+# Copyright (c) 2012, Bryan Dunsmore
+# Copyright (c) 2013, Vittorio Giovara
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+
+find_program(FREEPASCAL_EXECUTABLE
+ NAMES fpc
+ PATHS /opt/local/bin /usr/local/bin /usr/bin
+ )
+
+if (FREEPASCAL_EXECUTABLE)
+ # check Freepascal version
+ execute_process(COMMAND ${FREEPASCAL_EXECUTABLE} -iV
+ OUTPUT_VARIABLE FREEPASCAL_VERSION
+ ERROR_VARIABLE FREEPASCAL_VERSION_ERROR
+ RESULT_VARIABLE FREEPASCAL_VERSION_RESULT
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+
+ if(NOT ${FREEPASCAL_VERSION_RESULT} EQUAL 0)
+ message(SEND_ERROR "Command \"${FREEPASCAL_EXECUTABLE} -iV\" failed with output: ${FREEPASCAL_VERSION_ERROR}")
+ endif()
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(FreePascal DEFAULT_MSG FREEPASCAL_EXECUTABLE FREEPASCAL_VERSION)
+mark_as_advanced(FREEPASCAL_VERSION)
+
diff -r 404ddce27b23 -r c13ebed437cb cmake_modules/FindFreepascal.cmake
--- a/cmake_modules/FindFreepascal.cmake Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-# Load Freepascal
-if (FPC)
- set(FPC_EXECUTABLE ${FPC})
-else()
- find_program(FPC_EXECUTABLE
- NAMES fpc
- PATHS /opt/local/bin /usr/local/bin /usr/bin)
-endif()
-
-# Check Freepascal version
-if (FPC_EXECUTABLE)
- exec_program(${FPC_EXECUTABLE} ARGS "-v" OUTPUT_VARIABLE FPC_VERSION_FULL)
-
- string(REGEX MATCH "[0-9]+\\.[0-9]+" FPC_VERSION_LONG "${FPC_VERSION_FULL}")
- string(REGEX REPLACE "([0-9]+\\.[0-9]+)" "\\1" FPC_VERSION "${FPC_VERSION_LONG}")
- message(STATUS "Found Freepascal: ${FPC_EXECUTABLE} (version ${FPC_VERSION})")
-else()
- message(FATAL_ERROR "Could NOT find Freepascal")
-endif()
-
-# Check for noexecstack flag support
-message(STATUS "Checking whether linker needs explicit noexecstack")
-set(NOEXECSTACK_FLAGS "-k-z" "-knoexecstack")
-file(WRITE ${EXECUTABLE_OUTPUT_PATH}/checkstack.pas "begin end.")
-
-execute_process(COMMAND ${FPC_EXECUTABLE} ${NOEXECSTACK_FLAGS} checkstack.pas
- WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}
- RESULT_VARIABLE TEST_NOEXECSTACK
- OUTPUT_QUIET ERROR_QUIET)
-
-if (TEST_NOEXECSTACK)
- set(NOEXECSTACK_FLAGS "")
- message(STATUS "Checking whether linker needs explicit noexecstack -- no")
-else(TEST_NOEXECSTACK)
- message(STATUS "Checking whether linker needs explicit noexecstack -- yes")
-endif(TEST_NOEXECSTACK)
-
diff -r 404ddce27b23 -r c13ebed437cb cmake_modules/FindGHC.cmake
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/cmake_modules/FindGHC.cmake Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,38 @@
+# - Try to find the Glasgow Haskell Compiler executable
+# Once done this will define
+#
+# GHC_FOUND - system has GHC
+# GHC_VERSION - GHC version
+# GHC_EXECUTABLE - GHC executable
+#
+# Copyright (c) 2013, Vittorio Giovara
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+
+find_program(GHC_EXECUTABLE
+ NAMES ghc
+ PATHS /opt/local/bin /usr/local/bin /usr/bin
+ )
+
+if (GHC_EXECUTABLE)
+ # check Freepascal version
+ execute_process(COMMAND ${GHC_EXECUTABLE} -V
+ OUTPUT_VARIABLE GHC_VERSION_OUTPUT
+ ERROR_VARIABLE GHC_VERSION_ERROR
+ RESULT_VARIABLE GHC_VERSION_RESULT
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+
+ if(${GHC_VERSION_RESULT} EQUAL 0)
+ string(REGEX MATCH "([0-9]+)" GHC_VERSION ${GHC_VERSION_OUTPUT})
+ else()
+ message(SEND_ERROR "Command \"${GHC_EXECUTABLE} -V\" failed with output: ${GHC_VERSION_ERROR}")
+ endif()
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(GHC DEFAULT_MSG GHC_EXECUTABLE GHC_VERSION)
+mark_as_advanced(GHC_VERSION)
+
diff -r 404ddce27b23 -r c13ebed437cb cmake_modules/FindOggVorbis.cmake
--- a/cmake_modules/FindOggVorbis.cmake Wed Feb 20 02:21:58 2013 +0100
+++ b/cmake_modules/FindOggVorbis.cmake Tue Apr 02 21:00:57 2013 +0200
@@ -1,61 +1,68 @@
-### SuperTux - Removed unused vorbisenc library
-
# - Try to find the OggVorbis libraries
# Once done this will define
#
-# OGGVORBIS_FOUND - system has OggVorbis
-# OGGVORBIS_VERSION - set either to 1 or 2
+# OGGVORBIS_FOUND - system has both Ogg and Vorbis
+# OGGVORBIS_VERSION - set either to 1 or 2
# OGGVORBIS_INCLUDE_DIR - the OggVorbis include directory
-# OGGVORBIS_LIBRARIES - The libraries needed to use OggVorbis
-# OGG_LIBRARY - The Ogg library
-# VORBIS_LIBRARY - The Vorbis library
-# VORBISFILE_LIBRARY - The VorbisFile library
-# Copyright (c) 2006, Richard Laerkaeng,
+# OGGVORBIS_LIBRARIES - the libraries needed to use OggVorbis
+#
+# OGG_LIBRARY - the Ogg library
+# OGG_INCLUDE_DIR - the Ogg include directory
+# VORBIS_LIBRARY - the Vorbis library
+# VORBIS_INCLUDE_DIR - the Vorbis include directory
+# VORBISFILE_LIBRARY - the VorbisFile library
+#
+# Copyright (c) 2006, Richard Laerkaeng
+# Copyright (c) 2013, Vittorio Giovara
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+### sommer [SuperTux]
+## - Removed unused vorbisenc library
+## - reversed order of libraries, so that cmake 2.4.5 for Windows generates an MSYS Makefile that will link correctly
+
+### koda [Hedgewars]
+## - split ogg and vorbis lookup
+## - special case for framework handling
+## - standard variables handling
+
include (CheckLibraryExists)
-find_path(VORBIS_INCLUDE_DIR vorbis/vorbisfile.h)
+include (FindPackageHandleStandardArgs)
+
+find_path(OGG_INCLUDE_DIR ogg.h PATH_SUFFIXES ogg)
+find_path(VORBIS_INCLUDE_DIR vorbisfile.h PATH_SUFFIXES vorbis)
+
+find_library(OGG_LIBRARY NAMES Ogg ogg)
+find_library(VORBIS_LIBRARY NAMES Vorbis vorbis)
+find_library(VORBISFILE_LIBRARY NAMES vorbisfile)
-find_library(OGG_LIBRARY NAMES ogg)
-find_library(VORBIS_LIBRARY NAMES vorbis)
-find_library(VORBISFILE_LIBRARY NAMES vorbisfile)
-if(APPLE AND NOT VORBISFILE_LIBRARY)
-# [koda] (for Hedgewars) frameworks don't come with libvorbisfile
- set(VORBISFILE_LIBRARY "${VORBIS_LIBRARY}")
+set(_CMAKE_REQUIRED_LIBRARIES_TMP ${CMAKE_REQUIRED_LIBRARIES})
+set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${OGGVORBIS_LIBRARIES})
+check_library_exists(${VORBIS_LIBRARY} vorbis_bitrate_addblock "" HAVE_LIBVORBISENC2)
+set(CMAKE_REQUIRED_LIBRARIES ${_CMAKE_REQUIRED_LIBRARIES_TMP})
+
+if(HAVE_LIBVORBISENC2)
+ set(OGGVORBIS_VERSION 2)
+else(HAVE_LIBVORBISENC2)
+ set(OGGVORBIS_VERSION 1)
+endif(HAVE_LIBVORBISENC2)
+
+if(${OGG_LIBRARY} MATCHES ".framework" AND ${VORBIS_LIBRARY} MATCHES ".framework")
+ set(VORBISFILE_LIBRARY "") #vorbisfile will appear as NOTFOUND and discarded
+ set(fphsa_vorbis_list VORBIS_LIBRARY)
+else()
+ set(fphsa_vorbis_list VORBISFILE_LIBRARY VORBIS_LIBRARY)
endif()
-if (OGG_LIBRARY AND VORBIS_LIBRARY AND VORBISFILE_LIBRARY)
- set(OGGVORBIS_FOUND TRUE)
-# [sommer] (for SuperTux) reversed order of libraries, so that cmake 2.4.5 for Windows generates an MSYS Makefile that will link correctly
-# set(OGGVORBIS_LIBRARIES ${OGG_LIBRARY} ${VORBIS_LIBRARY} ${VORBISFILE_LIBRARY})
- set(OGGVORBIS_LIBRARIES ${VORBISFILE_LIBRARY} ${VORBIS_LIBRARY} ${OGG_LIBRARY})
- set(_CMAKE_REQUIRED_LIBRARIES_TMP ${CMAKE_REQUIRED_LIBRARIES})
- set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${OGGVORBIS_LIBRARIES})
- check_library_exists(vorbis vorbis_bitrate_addblock "" HAVE_LIBVORBISENC2)
- set(CMAKE_REQUIRED_LIBRARIES ${_CMAKE_REQUIRED_LIBRARIES_TMP})
- if (HAVE_LIBVORBISENC2)
- set (OGGVORBIS_VERSION 2)
- else (HAVE_LIBVORBISENC2)
- set (OGGVORBIS_VERSION 1)
- endif (HAVE_LIBVORBISENC2)
-else ()
- set(OGGVORBIS_VERSION)
- set(OGGVORBIS_FOUND FALSE)
-endif ()
-if (OGGVORBIS_FOUND)
- if (NOT OggVorbis_FIND_QUIETLY)
- message(STATUS "Found OggVorbis: ${OGGVORBIS_LIBRARIES}")
- endif (NOT OggVorbis_FIND_QUIETLY)
-else (OGGVORBIS_FOUND)
- if (OggVorbis_FIND_REQUIRED)
- message(FATAL_ERROR "Could NOT find OggVorbis libraries")
- else (OggVorbis_FIND_REQUIRED)
- if (NOT OggVorbis_FIND_QUIETLY)
- message(STATUS "Could NOT find OggVorbis libraries")
- endif (NOT OggVorbis_FIND_QUIETLY)
- endif(OggVorbis_FIND_REQUIRED)
-endif (OGGVORBIS_FOUND)
+find_package_handle_standard_args(OggVorbis DEFAULT_MSG ${fphsa_vorbis_list} OGG_LIBRARY
+ OGG_INCLUDE_DIR VORBIS_INCLUDE_DIR)
+unset(fphsa_vorbis_list)
+set(OGGVORBIS_LIBRARIES ${VORBISFILE_LIBRARY} ${VORBIS_LIBRARY} ${OGG_LIBRARY})
+set(OGGVORBIS_INCLUDE_DIR ${VORBIS_INCLUDE_DIR} ${OGG_INCLUDE_DIR})
+
+mark_as_advanced(OGGVORBIS_VERSION OGGVORBIS_INCLUDE_DIR OGGVORBIS_LIBRARIES
+ OGG_LIBRARY OGG_INCLUDE_DIR VORBIS_LIBRARY VORBIS_INCLUDE_DIR VORBISFILE_LIBRARY)
+
diff -r 404ddce27b23 -r c13ebed437cb cmake_modules/FindSDL_Extras.cmake
--- a/cmake_modules/FindSDL_Extras.cmake Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-#if the headers are not installed, the newer apis won't be activated
-
-#find which version of SDL_mixer we have (for Mix_Init)
-find_file(sdlmixer_h SDL_mixer.h ${SDLMIXER_INCLUDE_DIR})
-if(sdlmixer_h)
- file(STRINGS ${sdlmixer_h} sdlmixer_majorversion_tmp REGEX "SDL_MIXER_MAJOR_VERSION[\t' ']+[0-9]+")
- file(STRINGS ${sdlmixer_h} sdlmixer_minorversion_tmp REGEX "SDL_MIXER_MINOR_VERSION[\t' ']+[0-9]+")
- file(STRINGS ${sdlmixer_h} sdlmixer_patchversion_tmp REGEX "SDL_MIXER_PATCHLEVEL[\t' ']+[0-9]+")
- string(REGEX MATCH ".([0-9]+)" sdlmixer_majorversion "${sdlmixer_majorversion_tmp}")
- string(REGEX MATCH ".([0-9]+)" sdlmixer_minorversion "${sdlmixer_minorversion_tmp}")
- string(REGEX MATCH ".([0-9]+)" sdlmixer_patchversion "${sdlmixer_patchversion_tmp}")
- math(EXPR sdlmixer_version "${sdlmixer_majorversion}*10000 + ${sdlmixer_minorversion}*100 + ${sdlmixer_patchversion}")
-
- if(sdlmixer_version GREATER "10209")
- message(STATUS "Mix_Init() is present")
- list(APPEND pascal_flags "-dSDL_MIXER_NEWER")
- endif()
-endif()
-
-#find which version of SDL_image we have (for IMG_Init)
-find_file(sdlimage_h SDL_image.h ${SDLIMAGE_INCLUDE_DIR})
-if(sdlimage_h)
- file(STRINGS ${sdlimage_h} sdlimage_majorversion_tmp REGEX "SDL_IMAGE_MAJOR_VERSION[\t' ']+[0-9]+")
- file(STRINGS ${sdlimage_h} sdlimage_minorversion_tmp REGEX "SDL_IMAGE_MINOR_VERSION[\t' ']+[0-9]+")
- file(STRINGS ${sdlimage_h} sdlimage_patchversion_tmp REGEX "SDL_IMAGE_PATCHLEVEL[\t' ']+[0-9]+")
- string(REGEX MATCH ".([0-9]+)" sdlimage_majorversion "${sdlimage_majorversion_tmp}")
- string(REGEX MATCH ".([0-9]+)" sdlimage_minorversion "${sdlimage_minorversion_tmp}")
- string(REGEX MATCH ".([0-9]+)" sdlimage_patchversion "${sdlimage_patchversion_tmp}")
- math(EXPR sdlimage_version "${sdlimage_majorversion}*10000 + ${sdlimage_minorversion}*100 + ${sdlimage_patchversion}")
-
- if(sdlimage_version GREATER "010207")
- message(STATUS "IMG_Init() is present")
- list(APPEND pascal_flags "-dSDL_IMAGE_NEWER")
- endif()
-endif()
-
diff -r 404ddce27b23 -r c13ebed437cb cmake_modules/FindSparkle.cmake
--- a/cmake_modules/FindSparkle.cmake Wed Feb 20 02:21:58 2013 +0100
+++ b/cmake_modules/FindSparkle.cmake Tue Apr 02 21:00:57 2013 +0200
@@ -1,39 +1,23 @@
-### Hedgewars
-
-# - Try to find the Sparkle framework
+# Find Sparkle.framework
+#
# Once done this will define
-#
# SPARKLE_FOUND - system has Sparkle
# SPARKLE_INCLUDE_DIR - the Sparkle include directory
# SPARKLE_LIBRARY - The library needed to use Sparkle
-# Copyright (c) 2009, Vittorio Giovara,
+# Copyright (c) 2009, Vittorio Giovara
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
#
-# Redistribution and use is allowed according to the terms of a Creative Commons license.
-# For details see http://creativecommons.org/licenses/by-sa/3.0/
-# original version of this module was derived from Richard Laerkaeng,
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+include(FindPackageHandleStandardArgs)
-include (CheckLibraryExists)
find_path(SPARKLE_INCLUDE_DIR Sparkle.h)
find_library(SPARKLE_LIBRARY NAMES Sparkle)
-if (SPARKLE_INCLUDE_DIR AND SPARKLE_LIBRARY)
- set(SPARKLE_FOUND TRUE)
-else ()
- set(SPARKLE_FOUND FALSE)
-endif ()
+find_package_handle_standard_args(Sparkle DEFAULT_MSG SPARKLE_INCLUDE_DIR SPARKLE_LIBRARY)
+mark_as_advanced(SPARKLE_INCLUDE_DIR SPARKLE_LIBRARY)
-if (SPARKLE_FOUND)
- if (NOT SPARKLE_FIND_QUIETLY)
- message(STATUS "Found Sparkle: ${SPARKLE_LIBRARY}")
- endif ()
-else ()
- if (SPARKLE_FIND_REQUIRED)
- message(FATAL_ERROR "Could NOT find Sparkle framework")
- else ()
- if (NOT SPARKLE_FIND_QUIETLY)
- message(STATUS "Could NOT find Sparkle framework, autoupdate feature will be disabled")
- endif()
- endif ()
-endif ()
-
diff -r 404ddce27b23 -r c13ebed437cb cmake_modules/utils.cmake
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/cmake_modules/utils.cmake Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,30 @@
+
+macro(find_package_or_fail _PKG_NAME)
+ find_package(${_PKG_NAME})
+ string(TOUPPER ${_PKG_NAME} _PKG_NAME_UP)
+ if(NOT ${_PKG_NAME_UP}_FOUND)
+ message(SEND_ERROR "Missing ${_PKG_NAME}! Please install it and rerun cmake.")
+ endif(NOT ${_PKG_NAME_UP}_FOUND)
+endmacro(find_package_or_fail _PKG_NAME)
+
+macro(find_package_or_disable _PKG_NAME _VAR_NAME)
+ find_package(${_PKG_NAME})
+ string(TOUPPER ${_PKG_NAME} _PKG_NAME_UP)
+ if(NOT ${_PKG_NAME_UP}_FOUND)
+ message(SEND_ERROR "Missing ${_PKG_NAME}! Rerun cmake with -D${_VAR_NAME}=1 to build without it.")
+ endif(NOT ${_PKG_NAME_UP}_FOUND)
+endmacro(find_package_or_disable _PKG_NAME _VAR_NAME)
+
+macro(find_package_or_disable_msg _PKG_NAME _VAR_NAME _MSG)
+ if(NOT ${_VAR_NAME})
+ find_package_or_disable(${_PKG_NAME} ${_VAR_NAME})
+ else(NOT ${_VAR_NAME})
+ message(STATUS "${_PKG_NAME} disabled. ${_MSG}")
+ string(TOUPPER ${_PKG_NAME} _PKG_NAME_UP)
+ set(${_PKG_NAME_UP}_FOUND false)
+ endif(NOT ${_VAR_NAME})
+endmacro(find_package_or_disable_msg _PKG_NAME _VAR_NAME _MSG)
+
+
+#TODO: find_package_or_bundle
+
diff -r 404ddce27b23 -r c13ebed437cb gameServer/Actions.hs
--- a/gameServer/Actions.hs Wed Feb 20 02:21:58 2013 +0100
+++ b/gameServer/Actions.hs Tue Apr 02 21:00:57 2013 +0200
@@ -32,62 +32,9 @@
import ConfigFile
import EngineInteraction
-data Action =
- AnswerClients ![ClientChan] ![B.ByteString]
- | SendServerMessage
- | SendServerVars
- | MoveToRoom RoomIndex
- | MoveToLobby B.ByteString
- | RemoveTeam B.ByteString
- | SendTeamRemovalMessage B.ByteString
- | RemoveRoom
- | FinishGame
- | UnreadyRoomClients
- | JoinLobby
- | ProtocolError B.ByteString
- | Warning B.ByteString
- | NoticeMessage Notice
- | ByeClient B.ByteString
- | KickClient ClientIndex
- | KickRoomClient ClientIndex
- | BanClient NominalDiffTime B.ByteString ClientIndex
- | BanIP B.ByteString NominalDiffTime B.ByteString
- | BanNick B.ByteString NominalDiffTime B.ByteString
- | BanList
- | Unban B.ByteString
- | ChangeMaster (Maybe ClientIndex)
- | RemoveClientTeams
- | ModifyClient (ClientInfo -> ClientInfo)
- | ModifyClient2 ClientIndex (ClientInfo -> ClientInfo)
- | ModifyRoomClients (ClientInfo -> ClientInfo)
- | ModifyRoom (RoomInfo -> RoomInfo)
- | ModifyServerInfo (ServerInfo -> ServerInfo)
- | AddRoom B.ByteString B.ByteString
- | SendUpdateOnThisRoom
- | CheckRegistered
- | ClearAccountsCache
- | ProcessAccountInfo AccountInfo
- | AddClient ClientInfo
- | DeleteClient ClientIndex
- | PingAll
- | StatsAction
- | RestartServer
- | AddNick2Bans B.ByteString B.ByteString UTCTime
- | AddIP2Bans B.ByteString B.ByteString UTCTime
- | CheckBanned Bool
- | SaveReplay
- | Stats
-
type CmdHandler = [B.ByteString] -> Reader (ClientIndex, IRnC) [Action]
-instance NFData Action where
- rnf (AnswerClients chans msg) = chans `deepseq` msg `deepseq` ()
- rnf a = a `seq` ()
-
---instance NFData B.ByteString
-instance NFData (Chan a)
-
othersChans :: StateT ServerState IO [ClientChan]
othersChans = do
@@ -214,7 +161,7 @@
rnc <- gets roomsClients
io $ do
- modifyClient rnc (\cl -> cl{teamsInGame = 0, isReady = False, isMaster = False, isInGame = False}) ci
+ modifyClient rnc (\cl -> cl{teamsInGame = 0, isReady = False, isMaster = False, isInGame = False, clientClan = Nothing}) ci
modifyRoom rnc (\r -> r{playersIn = playersIn r + 1}) ri
moveClientToRoom rnc ri ci
@@ -430,7 +377,7 @@
uid <- client's clUID
-- allow multiple checker logins
haveSameNick <- liftM (not . null . tail . filter (\c -> (not $ isChecker c) && caseInsensitiveCompare (nick c) n)) allClientsS
- if haveSameNick && (not checker) then
+ if (not checker) && haveSameNick then
if p < 38 then
processAction $ ByeClient $ loc "Nickname is already in use"
else
@@ -455,8 +402,12 @@
when (not b) $ (if c then checkerLogin else playerLogin) passwd isAdmin
Guest -> do
b <- isBanned
+ c <- client's isChecker
when (not b) $
- processAction JoinLobby
+ if c then
+ checkerLogin "" False
+ else
+ processAction JoinLobby
Admin -> do
mapM_ processAction [ModifyClient (\cl -> cl{isAdministrator = True}), JoinLobby]
chan <- client's sendChan
@@ -588,6 +539,7 @@
when (not $ ci `Set.member` rc)
$ processAction $ ModifyServerInfo (\s -> s{bans = BanByIP ip reason expiring : bans s})
+
processAction (CheckBanned byIP) = do
clTime <- client's connectTime
clNick <- client's nick
@@ -607,6 +559,7 @@
getBanReason (BanByIP _ msg _) = msg
getBanReason (BanByNick _ msg _) = msg
+
processAction PingAll = do
rnc <- gets roomsClients
io (allClientsM rnc) >>= mapM_ (kickTimeouted rnc)
@@ -648,12 +601,19 @@
processAction Stats = do
cls <- allClientsS
- let stats = versions cls
- processAction $ Warning stats
- where
- versions = B.concat . ((:) ""])
- . concatMap (\(p, n :: Int) -> ["", protoNumber2ver p, " | ", showB n, " |
"])
- . Map.toList . Map.fromListWith (+) . map (\c -> (clientProto c, 1))
+ rms <- allRoomsS
+ let clientsMap = Map.fromListWith (+) . map (\c -> (clientProto c, 1 :: Int)) $ cls
+ let roomsMap = Map.fromListWith (+) . map (\c -> (roomProto c, 1 :: Int)) . filter ((/=) 0 . roomProto) $ rms
+ let keys = Map.keysSet clientsMap `Set.union` Map.keysSet roomsMap
+ let versionsStats = B.concat . ((:) ""])
+ . concatMap (\p -> [
+ "", protoNumber2ver p
+ , " | ", showB $ Map.findWithDefault 0 p clientsMap
+ , " | ", showB $ Map.findWithDefault 0 p roomsMap
+ , " |
"])
+ . Set.toList $ keys
+ processAction $ Warning versionsStats
+
#if defined(OFFICIAL_SERVER)
processAction SaveReplay = do
@@ -663,6 +623,29 @@
io $ do
r <- room'sM rnc id ri
saveReplay r
+
+
+processAction CheckRecord = do
+ p <- client's clientProto
+ c <- client's sendChan
+ (cinfo, l) <- io $ loadReplay (fromIntegral p)
+ when (not . null $ l) $
+ mapM_ processAction [
+ AnswerClients [c] ("REPLAY" : l)
+ , ModifyClient $ \c -> c{checkInfo = cinfo}
+ ]
+
+processAction (CheckFailed msg) = do
+ Just (CheckInfo fileName _) <- client's checkInfo
+ io $ moveFailedRecord fileName
+
+processAction (CheckSuccess info) = do
+ Just (CheckInfo fileName _) <- client's checkInfo
+ io $ moveCheckedRecord fileName
+
#else
processAction SaveReplay = return ()
+processAction CheckRecord = return ()
+processAction (CheckFailed _) = return ()
+processAction (CheckSuccess _) = return ()
#endif
diff -r 404ddce27b23 -r c13ebed437cb gameServer/CMakeLists.txt
--- a/gameServer/CMakeLists.txt Wed Feb 20 02:21:58 2013 +0100
+++ b/gameServer/CMakeLists.txt Tue Apr 02 21:00:57 2013 +0200
@@ -1,4 +1,7 @@
+include(${CMAKE_MODULE_PATH}/utils.cmake)
+
+find_package_or_disable(GHC NOSERVER)
set(hwserver_sources
OfficialServer/DBInteraction.hs
@@ -34,7 +37,7 @@
${haskell_flags})
add_custom_command(OUTPUT "${EXECUTABLE_OUTPUT_PATH}/hedgewars-server${CMAKE_EXECUTABLE_SUFFIX}"
- COMMAND "${ghc_executable}"
+ COMMAND "${GHC_EXECUTABLE}"
ARGS ${ghc_flags}
MAIN_DEPENDENCY ${hwserv_main}
DEPENDS ${hwserver_sources}
diff -r 404ddce27b23 -r c13ebed437cb gameServer/ClientIO.hs
--- a/gameServer/ClientIO.hs Wed Feb 20 02:21:58 2013 +0100
+++ b/gameServer/ClientIO.hs Tue Apr 02 21:00:57 2013 +0200
@@ -37,7 +37,7 @@
unless (B.null recvBS) $ do
let (packets, newrecvBuf) = bs2Packets $ B.append recvBuf recvBS
forM_ packets sendPacket
- receiveWithBufferLoop newrecvBuf
+ receiveWithBufferLoop $ B.copy newrecvBuf
sendPacket packet = writeChan chan $ ClientMessage (ci, packet)
diff -r 404ddce27b23 -r c13ebed437cb gameServer/CoreTypes.hs
--- a/gameServer/CoreTypes.hs Wed Feb 20 02:21:58 2013 +0100
+++ b/gameServer/CoreTypes.hs Tue Apr 02 21:00:57 2013 +0200
@@ -1,4 +1,4 @@
-{-# LANGUAGE OverloadedStrings, DeriveDataTypeable #-}
+{-# LANGUAGE CPP, OverloadedStrings, DeriveDataTypeable #-}
module CoreTypes where
import Control.Concurrent
@@ -12,11 +12,79 @@
import Control.Exception
import Data.Typeable
import Data.TConfig
+import Control.DeepSeq
-----------------------
import RoomsAndClients
+
+#if __GLASGOW_HASKELL__ < 706
+instance NFData B.ByteString
+#endif
+
+instance NFData (Chan a)
+
+instance NFData Action where
+ rnf (AnswerClients chans msg) = chans `deepseq` msg `deepseq` ()
+ rnf a = a `seq` ()
+
+data Action =
+ AnswerClients ![ClientChan] ![B.ByteString]
+ | SendServerMessage
+ | SendServerVars
+ | MoveToRoom RoomIndex
+ | MoveToLobby B.ByteString
+ | RemoveTeam B.ByteString
+ | SendTeamRemovalMessage B.ByteString
+ | RemoveRoom
+ | FinishGame
+ | UnreadyRoomClients
+ | JoinLobby
+ | ProtocolError B.ByteString
+ | Warning B.ByteString
+ | NoticeMessage Notice
+ | ByeClient B.ByteString
+ | KickClient ClientIndex
+ | KickRoomClient ClientIndex
+ | BanClient NominalDiffTime B.ByteString ClientIndex
+ | BanIP B.ByteString NominalDiffTime B.ByteString
+ | BanNick B.ByteString NominalDiffTime B.ByteString
+ | BanList
+ | Unban B.ByteString
+ | ChangeMaster (Maybe ClientIndex)
+ | RemoveClientTeams
+ | ModifyClient (ClientInfo -> ClientInfo)
+ | ModifyClient2 ClientIndex (ClientInfo -> ClientInfo)
+ | ModifyRoomClients (ClientInfo -> ClientInfo)
+ | ModifyRoom (RoomInfo -> RoomInfo)
+ | ModifyServerInfo (ServerInfo -> ServerInfo)
+ | AddRoom B.ByteString B.ByteString
+ | SendUpdateOnThisRoom
+ | CheckRegistered
+ | ClearAccountsCache
+ | ProcessAccountInfo AccountInfo
+ | AddClient ClientInfo
+ | DeleteClient ClientIndex
+ | PingAll
+ | StatsAction
+ | RestartServer
+ | AddNick2Bans B.ByteString B.ByteString UTCTime
+ | AddIP2Bans B.ByteString B.ByteString UTCTime
+ | CheckBanned Bool
+ | SaveReplay
+ | Stats
+ | CheckRecord
+ | CheckFailed B.ByteString
+ | CheckSuccess [B.ByteString]
+
type ClientChan = Chan [B.ByteString]
+data CheckInfo =
+ CheckInfo
+ {
+ recordFileName :: String,
+ recordTeams :: [TeamInfo]
+ }
+
data ClientInfo =
ClientInfo
{
@@ -38,8 +106,10 @@
isAdministrator :: Bool,
isChecker :: Bool,
isKickedFromServer :: Bool,
- clientClan :: Maybe B.ByteString,
- teamsInGame :: Word
+ clientClan :: !(Maybe B.ByteString),
+ checkInfo :: Maybe CheckInfo,
+ teamsInGame :: Word,
+ actionsPending :: [Action]
}
instance Eq ClientInfo where
@@ -66,6 +136,9 @@
}
deriving (Show, Read)
+instance Eq TeamInfo where
+ (==) = (==) `on` teamname
+
data GameInfo =
GameInfo
{
diff -r 404ddce27b23 -r c13ebed437cb gameServer/EngineInteraction.hs
--- a/gameServer/EngineInteraction.hs Wed Feb 20 02:21:58 2013 +0100
+++ b/gameServer/EngineInteraction.hs Tue Apr 02 21:00:57 2013 +0200
@@ -1,3 +1,5 @@
+{-# LANGUAGE OverloadedStrings #-}
+
module EngineInteraction where
import qualified Data.Set as Set
@@ -5,8 +7,14 @@
import qualified Codec.Binary.Base64 as Base64
import qualified Data.ByteString.Char8 as B
import qualified Data.ByteString as BW
+import qualified Data.Map as Map
+import qualified Data.List as L
+import Data.Word
+import Data.Bits
+import Control.Arrow
-------------
import CoreTypes
+import Utils
toEngineMsg :: B.ByteString -> B.ByteString
@@ -20,19 +28,130 @@
removeLength _ = Nothing
-checkNetCmd :: B.ByteString -> (Bool, Bool)
+splitMessages :: B.ByteString -> [B.ByteString]
+splitMessages = L.unfoldr (\b -> if B.null b then Nothing else Just $ B.splitAt (1 + fromIntegral (BW.head b)) b)
+
+
+checkNetCmd :: B.ByteString -> (B.ByteString, B.ByteString)
checkNetCmd msg = check decoded
where
- decoded = fromEngineMsg msg
- check Nothing = (False, False)
- check (Just ms) | B.length ms > 0 = let m = B.head ms in (m `Set.member` legalMessages, m == '+')
- | otherwise = (False, False)
+ decoded = liftM (splitMessages . BW.pack) $ Base64.decode $ B.unpack msg
+ check Nothing = (B.empty, B.empty)
+ check (Just msgs) = let (a, b) = (filter isLegal msgs, filter isNonEmpty a) in (encode a, encode b)
+ encode = B.pack . Base64.encode . BW.unpack . B.concat
+ isLegal m = (B.length m > 1) && (flip Set.member legalMessages . B.head . B.tail $ m)
+ isNonEmpty = (/=) '+' . B.head . B.tail
legalMessages = Set.fromList $ "M#+LlRrUuDdZzAaSjJ,sNpPwtghbc12345" ++ slotMessages
slotMessages = "\128\129\130\131\132\133\134\135\136\137\138"
-gameInfo2Replay :: GameInfo -> B.ByteString
-gameInfo2Replay GameInfo{roundMsgs = rm,
- teamsAtStart = teams,
- giMapParams = params1,
- giParams = params2} = undefined
+replayToDemo :: [TeamInfo]
+ -> Map.Map B.ByteString B.ByteString
+ -> Map.Map B.ByteString [B.ByteString]
+ -> [B.ByteString]
+ -> [B.ByteString]
+replayToDemo teams mapParams params msgs = concat [
+ [em "TD"]
+ , maybeScript
+ , maybeMap
+ , [eml ["etheme ", head $ params Map.! "THEME"]]
+ , [eml ["eseed ", mapParams Map.! "SEED"]]
+ , [eml ["e$gmflags ", showB gameFlags]]
+ , schemeFlags
+ , [eml ["e$template_filter ", mapParams Map.! "TEMPLATE"]]
+ , [eml ["e$mapgen ", mapgen]]
+ , mapgenSpecific
+ , concatMap teamSetup teams
+ , msgs
+ , [em "!"]
+ ]
+ where
+ em = toEngineMsg
+ eml = em . B.concat
+ mapGenTypes = ["+rnd+", "+maze+", "+drawn+"]
+ maybeScript = let s = head $ params Map.! "SCRIPT" in if s == "Normal" then [] else [eml ["escript Scripts/Multiplayer/", s, ".lua"]]
+ maybeMap = let m = mapParams Map.! "MAP" in if m `elem` mapGenTypes then [] else [eml ["emap ", m]]
+ scheme = tail $ params Map.! "SCHEME"
+ mapgen = mapParams Map.! "MAPGEN"
+ mapgenSpecific = case mapgen of
+ "+maze+" -> [eml ["e$maze_size ", head $ params Map.! "MAZE_SIZE"]]
+ "+drawn" -> drawnMapData . head $ params Map.! "DRAWNMAP"
+ _ -> []
+ gameFlags :: Word32
+ gameFlags = foldl (\r (b, f) -> if b == "false" then r else r .|. f) 0 $ zip scheme gameFlagConsts
+ schemeFlags = map (\(v, (n, m)) -> eml [n, " ", showB $ (readInt_ v) * m])
+ $ filter (\(_, (n, _)) -> not $ B.null n)
+ $ zip (drop (length gameFlagConsts) scheme) schemeParams
+ ammoStr :: B.ByteString
+ ammoStr = head . tail $ params Map.! "AMMO"
+ ammo = let l = B.length ammoStr `div` 4; ((a, b), (c, d)) = (B.splitAt l . fst &&& B.splitAt l . snd) . B.splitAt (l * 2) $ ammoStr in
+ (map (\(x, y) -> eml [x, " ", y]) $ zip ["eammloadt", "eammprob", "eammdelay", "eammreinf"] [a, b, c, d])
+ ++ [em "eammstore" | scheme !! 14 == "true" || scheme !! 20 == "false"]
+ initHealth = scheme !! 27
+ teamSetup :: TeamInfo -> [B.ByteString]
+ teamSetup t = (++) ammo $
+ eml ["eaddteam ", showB $ (1 + (readInt_ $ teamcolor t) :: Int) * 2113696, " ", teamname t]
+ : em "erdriven"
+ : eml ["efort ", teamfort t]
+ : take (2 * hhnum t) (
+ concatMap (\(HedgehogInfo hname hhat) -> [
+ eml ["eaddhh ", showB $ difficulty t, " ", initHealth, " ", hname]
+ , eml ["ehat ", hhat]
+ ])
+ $ hedgehogs t
+ )
+
+drawnMapData :: B.ByteString -> [B.ByteString]
+drawnMapData = error "drawnMapData"
+
+schemeParams :: [(B.ByteString, Int)]
+schemeParams = [
+ ("e$damagepct", 1)
+ , ("e$turntime", 1000)
+ , ("", 0)
+ , ("e$sd_turns", 1)
+ , ("e$casefreq", 1)
+ , ("e$minestime", 1000)
+ , ("e$minesnum", 1)
+ , ("e$minedudpct", 1)
+ , ("e$explosives", 1)
+ , ("e$healthprob", 1)
+ , ("e$hcaseamount", 1)
+ , ("e$waterrise", 1)
+ , ("e$healthdec", 1)
+ , ("e$ropepct", 1)
+ , ("e$getawaytime", 1)
+ ]
+
+
+gameFlagConsts :: [Word32]
+gameFlagConsts = [
+ 0x00001000
+ , 0x00000010
+ , 0x00000004
+ , 0x00000008
+ , 0x00000020
+ , 0x00000040
+ , 0x00000080
+ , 0x00000100
+ , 0x00000200
+ , 0x00000400
+ , 0x00000800
+ , 0x00002000
+ , 0x00004000
+ , 0x00008000
+ , 0x00010000
+ , 0x00020000
+ , 0x00040000
+ , 0x00080000
+ , 0x00100000
+ , 0x00200000
+ , 0x00400000
+ , 0x00800000
+ , 0x01000000
+ , 0x02000000
+ , 0x04000000
+ ]
+
+
+
diff -r 404ddce27b23 -r c13ebed437cb gameServer/HWProtoChecker.hs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gameServer/HWProtoChecker.hs Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,36 @@
+{-# LANGUAGE OverloadedStrings #-}
+module HWProtoChecker where
+
+import qualified Data.Map as Map
+import Data.Maybe
+import Data.List
+import Control.Monad.Reader
+--------------------------------------
+import CoreTypes
+import Actions
+import Utils
+import HandlerUtils
+import RoomsAndClients
+import EngineInteraction
+
+
+handleCmd_checker :: CmdHandler
+
+handleCmd_checker ["READY"] = return [CheckRecord]
+
+handleCmd_checker ["CHECKED", "FAIL", msg] = do
+ isChecking <- liftM (isJust . checkInfo) thisClient
+ if not isChecking then
+ return []
+ else
+ return [CheckFailed msg, ModifyClient $ \c -> c{checkInfo = Nothing}]
+
+
+handleCmd_checker ("CHECKED" : "OK" : info) = do
+ isChecking <- liftM (isJust . checkInfo) thisClient
+ if not isChecking then
+ return []
+ else
+ return [CheckSuccess info, ModifyClient $ \c -> c{checkInfo = Nothing}]
+
+handleCmd_checker _ = return [ProtocolError "Unknown command"]
diff -r 404ddce27b23 -r c13ebed437cb gameServer/HWProtoCore.hs
--- a/gameServer/HWProtoCore.hs Wed Feb 20 02:21:58 2013 +0100
+++ b/gameServer/HWProtoCore.hs Tue Apr 02 21:00:57 2013 +0200
@@ -11,6 +11,7 @@
import HWProtoNEState
import HWProtoLobbyState
import HWProtoInRoomState
+import HWProtoChecker
import HandlerUtils
import RoomsAndClients
import Utils
@@ -29,12 +30,12 @@
handleCmd ["PONG"] = do
cl <- thisClient
if pingsQueue cl == 0 then
- return [ProtocolError "Protocol violation"]
+ return $ actionsPending cl ++ [ModifyClient (\c -> c{actionsPending = []})]
else
return [ModifyClient (\c -> c{pingsQueue = pingsQueue c - 1})]
-handleCmd ("CMD" : params) =
- let c = concatMap B.words params in
+handleCmd ("CMD" : parameters) =
+ let c = concatMap B.words parameters in
if not $ null c then
h $ (upperCase . head $ c) : tail c
else
@@ -42,12 +43,22 @@
where
h ["DELEGATE", n] = handleCmd ["DELEGATE", n]
h ["STATS"] = handleCmd ["STATS"]
+ h ["PART", msg] = handleCmd ["PART", msg]
+ h ["QUIT", msg] = handleCmd ["QUIT", msg]
+ h ["GLOBAL", msg] = do
+ rnc <- liftM snd ask
+ let chans = map (sendChan . client rnc) $ allClients rnc
+ return [AnswerClients chans ["CHAT", "[global notice]", msg]]
h c = return [Warning . B.concat . L.intersperse " " $ "Unknown cmd" : c]
handleCmd cmd = do
(ci, irnc) <- ask
- if logonPassed (irnc `client` ci) then
- handleCmd_loggedin cmd
+ let cl = irnc `client` ci
+ if logonPassed cl then
+ if isChecker cl then
+ handleCmd_checker cmd
+ else
+ handleCmd_loggedin cmd
else
handleCmd_NotEntered cmd
diff -r 404ddce27b23 -r c13ebed437cb gameServer/HWProtoInRoomState.hs
--- a/gameServer/HWProtoInRoomState.hs Wed Feb 20 02:21:58 2013 +0100
+++ b/gameServer/HWProtoInRoomState.hs Tue Apr 02 21:00:57 2013 +0200
@@ -77,9 +77,12 @@
SendUpdateOnThisRoom,
ModifyClient (\c -> c{teamsInGame = teamsInGame c + 1, clientClan = Just teamColor}),
AnswerClients clChan ["TEAM_ACCEPTED", tName],
- AnswerClients clChan ["HH_NUM", tName, showB $ hhnum newTeam],
AnswerClients othChans $ teamToNet $ newTeam,
- AnswerClients roomChans ["TEAM_COLOR", tName, teamColor]
+ AnswerClients roomChans ["TEAM_COLOR", tName, teamColor],
+ ModifyClient $ \c -> c{actionsPending = actionsPending cl
+ ++ [AnswerClients clChan ["HH_NUM", tName, showB $ hhnum newTeam]]
+ },
+ AnswerClients [sendChan cl] ["PING"]
]
where
canAddNumber rt = (48::Int) - (sum $ map hhnum rt)
@@ -97,7 +100,6 @@
handleCmd_inRoom ["REMOVE_TEAM", tName] = do
(ci, _) <- ask
r <- thisRoom
- clNick <- clientNick
let maybeTeam = findTeam r
let team = fromJust maybeTeam
@@ -105,18 +107,18 @@
return $
if isNothing $ maybeTeam then
[Warning $ loc "REMOVE_TEAM: no such team"]
- else if clNick /= teamowner team then
+ else if ci /= teamownerId team then
[ProtocolError $ loc "Not team owner!"]
else
[RemoveTeam tName,
ModifyClient
(\c -> c{
teamsInGame = teamsInGame c - 1,
- clientClan = if teamsInGame c == 1 then Nothing else Just $ anotherTeamClan ci r
+ clientClan = if teamsInGame c == 1 then Nothing else Just $ anotherTeamClan ci team r
})
]
where
- anotherTeamClan ci = teamcolor . fromJust . find (\t -> teamownerId t == ci) . teams
+ anotherTeamClan ci team = teamcolor . fromMaybe (error "CHECKPOINT 011") . find (\t -> (teamownerId t == ci) && (t /= team)) . teams
findTeam = find (\t -> tName == teamname t) . teams
@@ -124,7 +126,7 @@
cl <- thisClient
r <- thisRoom
clChan <- thisClientChans
- roomChans <- roomClientsChans
+ others <- roomOthersChans
let maybeTeam = findTeam r
let team = fromJust maybeTeam
@@ -138,7 +140,7 @@
[AnswerClients clChan ["HH_NUM", teamName, showB $ hhnum team]]
else
[ModifyRoom $ modifyTeam team{hhnum = hhNumber},
- AnswerClients roomChans ["HH_NUM", teamName, showB hhNumber]]
+ AnswerClients others ["HH_NUM", teamName, showB hhNumber]]
where
hhNumber = readInt_ numberStr
findTeam = find (\t -> teamName == teamname t) . teams
@@ -182,6 +184,7 @@
["CLIENT_FLAGS", if isReady cl then "-r" else "+r", nick cl]
]
+
handleCmd_inRoom ["START_GAME"] = do
(ci, rnc) <- ask
cl <- thisClient
@@ -217,16 +220,16 @@
rm <- thisRoom
chans <- roomOthersChans
- if teamsInGame cl > 0 && (isJust $ gameInfo rm) && isLegal then
- return $ AnswerClients chans ["EM", msg]
- : [ModifyRoom (\r -> r{gameInfo = liftM (\g -> g{roundMsgs = msg : roundMsgs g}) $ gameInfo r}) | not isKeepAlive]
+ if teamsInGame cl > 0 && (isJust $ gameInfo rm) && (not $ B.null legalMsgs) then
+ return $ AnswerClients chans ["EM", legalMsgs]
+ : [ModifyRoom (\r -> r{gameInfo = liftM (\g -> g{roundMsgs = nonEmptyMsgs : roundMsgs g}) $ gameInfo r}) | not $ B.null nonEmptyMsgs]
else
return []
where
- (isLegal, isKeepAlive) = checkNetCmd msg
+ (legalMsgs, nonEmptyMsgs) = checkNetCmd msg
-handleCmd_inRoom ["ROUNDFINISHED", correctly] = do
+handleCmd_inRoom ["ROUNDFINISHED", _] = do
cl <- thisClient
rm <- thisRoom
chans <- roomClientsChans
@@ -242,7 +245,7 @@
else
return [] -- don't accept this message twice
where
- isCorrect = correctly == "1"
+-- isCorrect = correctly == "1"
-- compatibility with clients with protocol < 38
handleCmd_inRoom ["ROUNDFINISHED"] =
@@ -274,6 +277,7 @@
else
[ModifyRoom (\r -> r{isRegisteredOnly = not $ isRegisteredOnly r})]
+
handleCmd_inRoom ["ROOM_NAME", newName] = do
cl <- thisClient
rs <- allRoomInfos
@@ -297,10 +301,19 @@
(thisClientId, rnc) <- ask
maybeClientId <- clientByNick kickNick
master <- liftM isMaster thisClient
+ rm <- thisRoom
let kickId = fromJust maybeClientId
+ let kickCl = rnc `client` kickId
let sameRoom = clientRoom rnc thisClientId == clientRoom rnc kickId
+ let notOnly2Players = (length . group . sort . map teamowner . teams $ rm) > 2
return
- [KickRoomClient kickId | master && isJust maybeClientId && (kickId /= thisClientId) && sameRoom]
+ [KickRoomClient kickId |
+ master
+ && isJust maybeClientId
+ && (kickId /= thisClientId)
+ && sameRoom
+ && ((isNothing $ gameInfo rm) || notOnly2Players || teamsInGame kickCl == 0)
+ ]
handleCmd_inRoom ["DELEGATE", newAdmin] = do
@@ -323,7 +336,8 @@
chans <- roomSameClanChans
return [AnswerClients chans ["EM", engineMsg cl]]
where
- engineMsg cl = toEngineMsg $ B.concat ["b", nick cl, "(team): ", msg, "\x20\x20"]
+ engineMsg cl = toEngineMsg $ B.concat ["b", nick cl, " (team): ", msg, "\x20\x20"]
+
handleCmd_inRoom ["BAN", banNick] = do
(thisClientId, rnc) <- ask
diff -r 404ddce27b23 -r c13ebed437cb gameServer/HWProtoLobbyState.hs
--- a/gameServer/HWProtoLobbyState.hs Wed Feb 20 02:21:58 2013 +0100
+++ b/gameServer/HWProtoLobbyState.hs Tue Apr 02 21:00:57 2013 +0200
@@ -92,9 +92,12 @@
, AnswerClients [sendChan cl] $ ["CLIENT_FLAGS", "+h", ownerNick]
]
++ (if clientProto cl < 38 then map (readynessMessage cl) jRoomClients else [sendStateFlags cl jRoomClients])
- ++ answerFullConfig cl (mapParams jRoom) (params jRoom)
- ++ answerTeams cl jRoom
- ++ watchRound cl jRoom chans
+ ++ [AnswerClients [sendChan cl] ["PING"]
+ , ModifyClient $ \c -> c{actionsPending = actionsPending cl
+ ++ answerFullConfig cl (mapParams jRoom) (params jRoom)
+ ++ answerTeams cl jRoom
+ ++ watchRound cl jRoom chans}
+ ]
where
readynessMessage cl c = AnswerClients [sendChan cl] [if isReady c then "READY" else "NOT_READY", nick c]
@@ -135,13 +138,14 @@
handleCmd_lobby ["FOLLOW", asknick] = do
(_, rnc) <- ask
+ clChan <- liftM sendChan thisClient
ci <- clientByNick asknick
let ri = clientRoom rnc $ fromJust ci
- let clRoom = room rnc ri
+ let roomName = name $ room rnc ri
if isNothing ci || ri == lobbyId then
return []
else
- handleCmd_lobby ["JOIN_ROOM", name clRoom]
+ liftM ((:) (AnswerClients [clChan] ["JOINING", roomName])) $ handleCmd_lobby ["JOIN_ROOM", roomName]
---------------------------
-- Administrator's stuff --
diff -r 404ddce27b23 -r c13ebed437cb gameServer/NetRoutines.hs
--- a/gameServer/NetRoutines.hs Wed Feb 20 02:21:58 2013 +0100
+++ b/gameServer/NetRoutines.hs Tue Apr 02 21:00:57 2013 +0200
@@ -45,7 +45,9 @@
False
False
Nothing
+ Nothing
0
+ []
)
writeChan chan $ Accept newClient
diff -r 404ddce27b23 -r c13ebed437cb gameServer/OfficialServer/GameReplayStore.hs
--- a/gameServer/OfficialServer/GameReplayStore.hs Wed Feb 20 02:21:58 2013 +0100
+++ b/gameServer/OfficialServer/GameReplayStore.hs Tue Apr 02 21:00:57 2013 +0200
@@ -9,18 +9,57 @@
import Data.Maybe
import Data.Unique
import Control.Monad
+import Data.List
+import qualified Data.ByteString as B
+import System.Directory
---------------
import CoreTypes
+import EngineInteraction
+pickReplayFile :: Int -> IO String
+pickReplayFile p = do
+ files <- liftM (filter (isSuffixOf ('.' : show p))) $ getDirectoryContents "replays"
+ if (not $ null files) then
+ return $ "replays/" ++ head files
+ else
+ return ""
+
saveReplay :: RoomInfo -> IO ()
saveReplay r = do
let gi = fromJust $ gameInfo r
when (allPlayersHaveRegisteredAccounts gi) $ do
time <- getCurrentTime
u <- liftM hashUnique newUnique
- let fileName = "replays/" ++ show time ++ "-" ++ show u
+ let fileName = "replays/" ++ show time ++ "-" ++ show u ++ "." ++ show (roomProto r)
let replayInfo = (teamsAtStart gi, Map.toList $ mapParams r, Map.toList $ params r, roundMsgs gi)
E.catch
(writeFile fileName (show replayInfo))
(\(e :: IOException) -> warningM "REPLAYS" $ "Couldn't write to " ++ fileName ++ ": " ++ show e)
+
+
+loadReplay :: Int -> IO (Maybe CheckInfo, [B.ByteString])
+loadReplay p = E.handle (\(e :: SomeException) -> warningM "REPLAYS" "Problems reading replay" >> return (Nothing, [])) $ do
+ fileName <- pickReplayFile p
+ if (not $ null fileName) then
+ loadFile fileName
+ else
+ return (Nothing, [])
+ where
+ loadFile :: String -> IO (Maybe CheckInfo, [B.ByteString])
+ loadFile fileName = E.handle (\(e :: SomeException) ->
+ warningM "REPLAYS" ("Problems reading " ++ fileName ++ ": " ++ show e) >> return (Nothing, [])) $ do
+ (teams, params1, params2, roundMsgs) <- liftM read $ readFile fileName
+ return $ (
+ Just (CheckInfo fileName teams)
+ , replayToDemo teams (Map.fromList params1) (Map.fromList params2) (reverse roundMsgs)
+ )
+
+moveFailedRecord :: String -> IO ()
+moveFailedRecord fn = E.handle (\(e :: SomeException) -> warningM "REPLAYS" $ show e) $
+ renameFile fn ("failed/" ++ drop 8 fn)
+
+
+moveCheckedRecord :: String -> IO ()
+moveCheckedRecord fn = E.handle (\(e :: SomeException) -> warningM "REPLAYS" $ show e) $
+ renameFile fn ("checked/" ++ drop 8 fn)
diff -r 404ddce27b23 -r c13ebed437cb gameServer/OfficialServer/checker.hs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gameServer/OfficialServer/checker.hs Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,183 @@
+{-# LANGUAGE CPP, ScopedTypeVariables, OverloadedStrings #-}
+module Main where
+
+import qualified Control.Exception as Exception
+import System.IO
+import System.Log.Logger
+import qualified Data.ConfigFile as CF
+import Control.Monad.Error
+import System.Directory
+import Control.Monad.State
+import Control.Concurrent.Chan
+import Control.Concurrent
+import Network
+import Network.BSD
+import Network.Socket hiding (recv)
+import Network.Socket.ByteString
+import qualified Data.ByteString.Char8 as B
+import qualified Data.ByteString as BW
+import qualified Codec.Binary.Base64 as Base64
+import System.Process
+import Data.Maybe
+import qualified Data.List as L
+#if !defined(mingw32_HOST_OS)
+import System.Posix
+#endif
+
+data Message = Packet [B.ByteString]
+ | CheckFailed B.ByteString
+ | CheckSuccess [B.ByteString]
+ deriving Show
+
+serverAddress = "netserver.hedgewars.org"
+protocolNumber = "43"
+
+getLines :: Handle -> IO [String]
+getLines h = g
+ where
+ g = do
+ l <- liftM Just (hGetLine h) `Exception.catch` (\(_ :: Exception.IOException) -> return Nothing)
+ if isNothing l then
+ return []
+ else
+ do
+ lst <- g
+ return $ fromJust l : lst
+
+
+engineListener :: Chan Message -> Handle -> IO ()
+engineListener coreChan h = do
+ output <- getLines h
+ debugM "Engine" $ show output
+ if isNothing $ L.find start output then
+ writeChan coreChan $ CheckFailed "No stats msg"
+ else
+ writeChan coreChan $ CheckSuccess []
+ where
+ start = flip L.elem ["WINNERS", "DRAW"]
+
+
+checkReplay :: Chan Message -> [B.ByteString] -> IO ()
+checkReplay coreChan msgs = do
+ tempDir <- getTemporaryDirectory
+ (fileName, h) <- openBinaryTempFile tempDir "checker-demo"
+ B.hPut h . BW.pack . concat . map (fromJust . Base64.decode . B.unpack) $ msgs
+ hFlush h
+ hClose h
+
+ (_, Just hOut, _, _) <- createProcess (proc "/usr/home/unC0Rr/Sources/Hedgewars/Releases/0.9.18/bin/hwengine"
+ ["/usr/home/unC0Rr/.hedgewars"
+ , "/usr/home/unC0Rr/Sources/Hedgewars/Releases/0.9.18/share/hedgewars/Data"
+ , fileName
+ , "--set-audio"
+ , "0"
+ , "0"
+ , "0"
+ ])
+ {std_out = CreatePipe}
+ hSetBuffering hOut LineBuffering
+ void $ forkIO $ engineListener coreChan hOut
+
+
+takePacks :: State B.ByteString [[B.ByteString]]
+takePacks = do
+ modify (until (not . B.isPrefixOf pDelim) (B.drop 2))
+ packet <- state $ B.breakSubstring pDelim
+ buf <- get
+ if B.null buf then put packet >> return [] else
+ if B.null packet then return [] else do
+ packets <- takePacks
+ return (B.splitWith (== '\n') packet : packets)
+ where
+ pDelim = "\n\n"
+
+
+recvLoop :: Socket -> Chan Message -> IO ()
+recvLoop s chan =
+ ((receiveWithBufferLoop B.empty >> return "Connection closed")
+ `Exception.catch` (\(e :: Exception.SomeException) -> return . B.pack . show $ e)
+ )
+ >>= disconnected
+ where
+ disconnected msg = writeChan chan $ Packet ["BYE", msg]
+ receiveWithBufferLoop recvBuf = do
+ recvBS <- recv s 4096
+ unless (B.null recvBS) $ do
+ let (packets, newrecvBuf) = runState takePacks $ B.append recvBuf recvBS
+ forM_ packets sendPacket
+ receiveWithBufferLoop $ B.copy newrecvBuf
+
+ sendPacket packet = writeChan chan $ Packet packet
+
+
+session :: B.ByteString -> B.ByteString -> Socket -> IO ()
+session l p s = do
+ noticeM "Core" "Connected"
+ coreChan <- newChan
+ forkIO $ recvLoop s coreChan
+ forever $ do
+ p <- readChan coreChan
+ case p of
+ Packet p -> do
+ debugM "Network" $ "Recv: " ++ show p
+ onPacket coreChan p
+ CheckFailed msg -> do
+ warningM "Check" "Check failed"
+ answer ["CHECKED", "FAIL", msg]
+ answer ["READY"]
+ CheckSuccess msgs -> do
+ warningM "Check" "Check succeeded"
+ answer ("CHECKED" : "OK" : msgs)
+ answer ["READY"]
+ where
+ answer :: [B.ByteString] -> IO ()
+ answer p = do
+ debugM "Network" $ "Send: " ++ show p
+ sendAll s $ B.unlines p `B.snoc` '\n'
+ onPacket :: Chan Message -> [B.ByteString] -> IO ()
+ onPacket _ ("CONNECTED":_) = do
+ answer ["CHECKER", protocolNumber, l, p]
+ answer ["READY"]
+ onPacket _ ["PING"] = answer ["PONG"]
+ onPacket chan ("REPLAY":msgs) = do
+ checkReplay chan msgs
+ warningM "Check" "Started check"
+ onPacket _ ("BYE" : xs) = error $ show xs
+ onPacket _ _ = return ()
+
+
+main :: IO ()
+main = withSocketsDo $ do
+#if !defined(mingw32_HOST_OS)
+ installHandler sigPIPE Ignore Nothing
+ installHandler sigCHLD Ignore Nothing
+#endif
+
+ updateGlobalLogger "Core" (setLevel DEBUG)
+ updateGlobalLogger "Network" (setLevel DEBUG)
+ updateGlobalLogger "Check" (setLevel DEBUG)
+ updateGlobalLogger "Engine" (setLevel DEBUG)
+
+ Right (login, password) <- runErrorT $ do
+ d <- liftIO $ getHomeDirectory
+ conf <- join . liftIO . CF.readfile CF.emptyCP $ d ++ "/.hedgewars/hedgewars.ini"
+ l <- CF.get conf "net" "nick"
+ p <- CF.get conf "net" "passwordhash"
+ return (B.pack l, B.pack p)
+
+
+ Exception.bracket
+ setupConnection
+ (\s -> noticeM "Core" "Shutting down" >> sClose s)
+ (session login password)
+ where
+ setupConnection = do
+ noticeM "Core" "Connecting to the server..."
+
+ proto <- getProtocolNumber "tcp"
+ let hints = defaultHints { addrFlags = [AI_ADDRCONFIG, AI_CANONNAME] }
+ (addr:_) <- getAddrInfo (Just hints) (Just serverAddress) Nothing
+ let (SockAddrInet _ host) = addrAddress addr
+ sock <- socket AF_INET Stream proto
+ connect sock (SockAddrInet 46631 host)
+ return sock
diff -r 404ddce27b23 -r c13ebed437cb gameServer/RoomsAndClients.hs
--- a/gameServer/RoomsAndClients.hs Wed Feb 20 02:21:58 2013 +0100
+++ b/gameServer/RoomsAndClients.hs Tue Apr 02 21:00:57 2013 +0200
@@ -23,6 +23,7 @@
room'sM,
allClientsM,
clientsM,
+ roomsM,
roomClientsM,
roomClientsIndicesM,
withRoomsAndClients,
@@ -160,6 +161,9 @@
clientsM :: MRoomsAndClients r c -> IO [c]
clientsM (MRoomsAndClients (_, clients)) = indicesM clients >>= mapM (liftM client' . readElem clients)
+roomsM :: MRoomsAndClients r c -> IO [r]
+roomsM (MRoomsAndClients (rooms, _)) = indicesM rooms >>= mapM (liftM room' . readElem rooms)
+
roomClientsIndicesM :: MRoomsAndClients r c -> RoomIndex -> IO [ClientIndex]
roomClientsIndicesM (MRoomsAndClients (rooms, _)) (RoomIndex ri) = liftM roomClients' (rooms `readElem` ri)
diff -r 404ddce27b23 -r c13ebed437cb gameServer/ServerState.hs
--- a/gameServer/ServerState.hs Wed Feb 20 02:21:58 2013 +0100
+++ b/gameServer/ServerState.hs Tue Apr 02 21:00:57 2013 +0200
@@ -5,6 +5,7 @@
ServerState(..),
client's,
allClientsS,
+ allRoomsS,
roomClientsS,
sameProtoClientsS,
io
@@ -40,6 +41,9 @@
allClientsS :: StateT ServerState IO [ClientInfo]
allClientsS = gets roomsClients >>= liftIO . clientsM
+allRoomsS :: StateT ServerState IO [RoomInfo]
+allRoomsS = gets roomsClients >>= liftIO . roomsM
+
roomClientsS :: RoomIndex -> StateT ServerState IO [ClientInfo]
roomClientsS ri = do
rnc <- gets roomsClients
diff -r 404ddce27b23 -r c13ebed437cb gameServer/Utils.hs
--- a/gameServer/Utils.hs Wed Feb 20 02:21:58 2013 +0100
+++ b/gameServer/Utils.hs Tue Apr 02 21:00:57 2013 +0200
@@ -56,7 +56,7 @@
t : replaceTeam tm ts
illegalName :: B.ByteString -> Bool
-illegalName s = B.null s || B.all isSpace s || isSpace (B.head s) || isSpace (B.last s) || B.any isIllegalChar s
+illegalName s = B.null s || B.length s > 40 || B.all isSpace s || isSpace (B.head s) || isSpace (B.last s) || B.any isIllegalChar s
where
isIllegalChar c = c `List.elem` "$()*+?[]^{|}"
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/CMakeLists.txt
--- a/hedgewars/CMakeLists.txt Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/CMakeLists.txt Tue Apr 02 21:00:57 2013 +0200
@@ -4,17 +4,28 @@
find_package(SDL_ttf)
find_package(SDL_mixer)
-include(${CMAKE_SOURCE_DIR}/cmake_modules/FindSDL_Extras.cmake)
+include (CheckLibraryExists)
+#Mix_Init/Mix_Quit from SDL_mixer 1.2.10
+check_library_exists(${SDLMIXER_LIBRARY} Mix_Init "" HAVE_MIXINIT)
+if(HAVE_MIXINIT)
+ list(APPEND pascal_flags "-dSDL_MIXER_NEWER")
+endif()
+#IMG_Init/IMG_Quit from SDL_image 1.2.8
+check_library_exists(${SDLIMAGE_LIBRARY} IMG_Init "" HAVE_IMGINIT)
+if(HAVE_IMGINIT)
+ list(APPEND pascal_flags "-dSDL_IMAGE_NEWER")
+endif()
+
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.inc.in ${CMAKE_CURRENT_BINARY_DIR}/config.inc)
#SOURCE AND PROGRAMS SECTION
if(${LIBENGINE})
set(engine_output_name "${CMAKE_SHARED_LIBRARY_PREFIX}hwengine${CMAKE_SHARED_LIBRARY_SUFFIX}")
- set(hwengine_project ${CMAKE_CURRENT_SOURCE_DIR}/hwLibrary.pas)
+ set(hwengine_project hwLibrary.pas)
else()
set(engine_output_name "hwengine${CMAKE_EXECUTABLE_SUFFIX}")
- set(hwengine_project ${CMAKE_CURRENT_SOURCE_DIR}/hwengine.pas)
+ set(hwengine_project hwengine.pas)
endif()
if (APPLE)
@@ -92,7 +103,7 @@
)
if(${LIBENGINE})
- message(WARNING "Engine will be built as library (experimental)")
+ message(${WARNING} "Engine will be built as library (experimental)")
list(APPEND pascal_flags "-dHWLIBRARY")
# create position independent code, only required for x68_64 builds, similar to -fPIC
@@ -110,16 +121,18 @@
endif(${LIBENGINE})
+include(${CMAKE_MODULE_PATH}/utils.cmake)
#opengl 2
IF(${GL2})
set(pascal_flags "-dGL2" ${pascal_flags})
message(STATUS "Building using OpenGL 2")
ENDIF(${GL2})
-# Check Freepascal version
-find_package(Freepascal)
+
+find_package_or_fail(FreePascal)
-if (FPC_VERSION VERSION_LESS required_fpc_version)
- message(FATAL_ERROR "Freepascal is too old, minimum version required is ${required_fpc_version}")
+#when cmake-2.6 support is dropped, this ought to be inside FindFreePascal.cmake
+if (FREEPASCAL_VERSION VERSION_LESS required_fpc_version)
+ message(FATAL_ERROR "Freepascal ${FREEPASCAL_VERSION} is too old, minimum version required is ${required_fpc_version}")
endif()
@@ -152,82 +165,71 @@
list(APPEND pascal_flags "-k${SDLMAIN_LIB}")
endif()
+
+ #when you have multiple ld installation make sure you get the one bundled with the compiler
+ get_filename_component(compiler_dir ${CMAKE_C_COMPILER} PATH)
+ list(APPEND pascal_flags "-FD${compiler_dir}")
endif(APPLE)
-if(NOT NOPNG)
- find_package(PNG)
- if(${PNG_FOUND})
- list(APPEND pascal_flags "-dPNG_SCREENSHOTS")
- if(APPLE) # fpc png unit doesn't pull the library (see bug 21833)
- list(APPEND pascal_flags "-k${PNG_LIBRARY}")
- endif()
- else()
- message(WARNING "Screenshots will be in BMP format because libpng was not found")
- endif()
-else()
- message(STATUS "Screenshots will be in BMP format per user request")
+find_package_or_disable_msg(PNG NOPNG "Screenshots will be saved in BMP")
+if(PNG_FOUND)
+ list(REMOVE_AT PNG_LIBRARIES 1) #removing the zlib library path
+ get_filename_component(PNG_LIB_DIR ${PNG_LIBRARIES} PATH)
+ list(APPEND pascal_flags "-dPNG_SCREENSHOTS" "-Fl${PNG_LIB_DIR}")
endif()
#this command is a workaround to some inlining issues present in older FreePascal versions and fixed in 2.6
-if(FPC_VERSION VERSION_LESS "2.6")
+if(FREEPASCAL_VERSION VERSION_LESS "2.6")
#under some configurations CMAKE_BUILD_TOOL fails to pass on the jobserver, breaking parallel compilation
if(UNIX)
set(SAFE_BUILD_TOOL $(MAKE))
else()
set(SAFE_BUILD_TOOL ${CMAKE_BUILD_TOOL})
endif()
- add_custom_target(ENGINECLEAN COMMAND ${SAFE_BUILD_TOOL} "clean" "${PROJECT_BINARY_DIR}" "${CMAKE_SOURCE_DIR}/hedgewars")
+ add_custom_target(ENGINECLEAN COMMAND ${SAFE_BUILD_TOOL} "clean" "${PROJECT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}")
endif()
-if(NOT NOVIDEOREC)
- set(FFMPEG_FIND_QUIETLY true)
- find_package(FFMPEG)
- if(${FFMPEG_FOUND})
- # TODO: this check is only for SDL < 2
- # fpc will take care of linking but we need to have this library installed
- find_package(GLUT REQUIRED)
+if(${FFMPEG_FOUND})
+ # TODO: this check is only for SDL < 2
+ # fpc will take care of linking but we need to have this library installed
+ find_package(GLUT REQUIRED)
- #TODO: convert avwrapper to .pas unit so we can skip this step
- include_directories(${FFMPEG_INCLUDE_DIR})
+ #TODO: convert avwrapper to .pas unit so we can skip this step
+ include_directories(${FFMPEG_INCLUDE_DIR})
+ list(APPEND pascal_flags "-dUSE_VIDEO_RECORDING")
+ if(WIN32)
+ # there are some problems with linking our avwrapper as static lib, so link it as shared
+ add_library(avwrapper SHARED videorec/avwrapper.c)
+ target_link_libraries(avwrapper ${FFMPEG_LIBRARIES})
+ install(PROGRAMS "${EXECUTABLE_OUTPUT_PATH}/${CMAKE_SHARED_LIBRARY_PREFIX}avwrapper${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION ${target_library_install_dir})
list(APPEND pascal_flags "-dUSE_VIDEO_RECORDING")
- IF (WIN32)
- # there are some problems with linking our avwrapper as static lib, so link it as shared
- add_library(avwrapper SHARED videorec/avwrapper.c)
- target_link_libraries(avwrapper ${FFMPEG_LIBRARIES})
- install(PROGRAMS "${EXECUTABLE_OUTPUT_PATH}/${CMAKE_SHARED_LIBRARY_PREFIX}avwrapper${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION ${target_library_install_dir})
- ELSE()
- add_library(avwrapper STATIC videorec/avwrapper.c)
- list(APPEND pascal_flags "-k${FFMPEG_LIBAVCODEC}" "-k${FFMPEG_LIBAVFORMAT}" "-k${FFMPEG_LIBAVUTIL}")
- ENDIF()
else()
- message(WARNING "Could NOT find FFMPEG/LibAV, video recording will be disabled")
+ add_library(avwrapper STATIC videorec/avwrapper.c)
endif()
-else()
- message(STATUS "Video recording disabled by user")
endif()
-set(fpc_flags ${NOEXECSTACK_FLAGS} ${pascal_flags} ${hwengine_project})
+set(fpc_flags ${pascal_flags} ${hwengine_project})
if(NOT APPLE)
#here is the command for standard executables or for shared library
add_custom_command(OUTPUT "${EXECUTABLE_OUTPUT_PATH}/${engine_output_name}"
- COMMAND "${FPC_EXECUTABLE}"
+ COMMAND "${FREEPASCAL_EXECUTABLE}"
ARGS ${fpc_flags} -o${engine_output_name}
- MAIN_DEPENDENCY ${hwengine_project}
DEPENDS ${engine_sources}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
else()
#these are the dependencies for building a universal binary on Mac OS X
foreach (build_arch ${powerpc_build} ${i386_build} ${x86_64_build})
list(APPEND lipo_args_list "${EXECUTABLE_OUTPUT_PATH}/hwengine.${build_arch}")
add_custom_command(OUTPUT "${EXECUTABLE_OUTPUT_PATH}/hwengine.${build_arch}"
- COMMAND "${FPC_EXECUTABLE}"
+ COMMAND "${FREEPASCAL_EXECUTABLE}"
ARGS ${fpc_flags} -ohwengine.${build_arch} -P${build_arch}
- MAIN_DEPENDENCY ${hwengine_project}
DEPENDS ${engine_sources}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
add_custom_target(hwengine.${build_arch} ALL DEPENDS "${EXECUTABLE_OUTPUT_PATH}/hwengine.${build_arch}")
add_custom_command(TARGET hwengine.${build_arch} POST_BUILD
@@ -252,8 +254,12 @@
add_dependencies(hwengine lua)
endif()
-# compile physfs before engine
-add_dependencies(hwengine physfs)
+# same for physfs
+if(NOT PHYSFS_FOUND)
+ add_dependencies(hwengine physfs)
+endif()
+
+add_dependencies(hwengine physlayer)
#when ffmpeg/libav is found we need to compile it before engine
#TODO: convert avwrapper to .pas unit so we can skip this step
@@ -262,7 +268,7 @@
endif()
#this command is a workaround to some inlining issues present in older FreePascal versions and fixed in 2.6
-if((FPC_VERSION VERSION_LESS "2.6") AND (NOVIDEOREC OR NOT ${FFMPEG_FOUND}))
+if((FREEPASCAL_VERSION VERSION_LESS "2.6") AND (NOT ${FFMPEG_FOUND}))
add_dependencies(hwengine ENGINECLEAN)
endif()
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/GSHandlers.inc
--- a/hedgewars/GSHandlers.inc Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/GSHandlers.inc Tue Apr 02 21:00:57 2013 +0200
@@ -92,7 +92,7 @@
else
begin
- if (gi^.State and gstMoving) = 0 then
+ if ((gi^.State and gstMoving) = 0) and (gi^.Hedgehog^.Effects[heFrozen] = 0) then
begin
gi^.dX.isNegative:= X 0) then
begin
lf:= Land[yy, xx] and (lfObject or lfBasic or lfIndestructible);
+ if lf = 0 then lf:= lfObject;
// If there's room below keep falling
if (((yy-1) and LAND_HEIGHT_MASK) = 0) and (Land[yy-1, xx] = 0) then
begin
@@ -679,7 +680,7 @@
begin
rx:= rx div 2;ry:= ry div 2;
end;
- if Land[yy + py, xx + px] and $FF00 = 0 then
+ if Land[yy + py, xx + px] <= lfAllObjMask then
if gun then
begin
LandDirty[yy div 32, xx div 32]:= 1;
@@ -1020,7 +1021,7 @@
if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y, x] <> 0) then
inc(Gear^.Damage);
// let's interrupt before a collision to give portals a chance to catch the bullet
- if (Gear^.Damage = 1) and (Gear^.Tag = 0) and (Land[y, x] > 255) then
+ if (Gear^.Damage = 1) and (Gear^.Tag = 0) and not(CheckLandValue(x, y, lfLandMask)) then
begin
Gear^.Tag := 1;
Gear^.Damage := 0;
@@ -1153,15 +1154,15 @@
dec(Gear^.Timer);
case Gear^.Kind of
gtATStartGame:
- begin
+ begin
AllInactive := false;
if Gear^.Timer = 0 then
begin
AddCaption(trmsg[sidStartFight], cWhiteColor, capgrpGameState);
end
- end;
+ end;
gtATFinishGame:
- begin
+ begin
AllInactive := false;
if Gear^.Timer = 1000 then
begin
@@ -1175,8 +1176,8 @@
SendIPC(_S'q');
GameState := gsExit
end
+ end;
end;
-end;
if Gear^.Timer = 0 then
DeleteGear(Gear)
end;
@@ -1242,7 +1243,7 @@
end
else
begin
- if CheckLandValue(hwRound(Gear^.X), hwRound(Gear^.Y + Gear^.dY + cGravity), $FF00) then
+ if CheckLandValue(hwRound(Gear^.X), hwRound(Gear^.Y + Gear^.dY + cGravity), lfLandMask) then
begin
Gear^.dY := Gear^.dY + cGravity;
Gear^.Y := Gear^.Y + Gear^.dY
@@ -1252,7 +1253,7 @@
end;
Gear^.X := Gear^.X + HHGear^.dX;
- if CheckLandValue(hwRound(Gear^.X), hwRound(Gear^.Y)-cHHRadius, $FF00) then
+ if CheckLandValue(hwRound(Gear^.X), hwRound(Gear^.Y)-cHHRadius, lfLandMask) then
begin
HHGear^.X := Gear^.X;
HHGear^.Y := Gear^.Y - int2hwFloat(cHHRadius)
@@ -1401,6 +1402,14 @@
BTPrevAngle := High(LongInt);
BTSteps := 0;
HHGear := Gear^.Hedgehog^.Gear;
+ HedgehogChAngle(HHGear);
+ Gear^.dX := SignAs(AngleSin(HHGear^.Angle) * _0_5, Gear^.dX);
+ Gear^.dY := AngleCos(HHGear^.Angle) * ( - _0_5);
+ DrawTunnel(HHGear^.X,
+ HHGear^.Y + Gear^.dY * cHHRadius - _1 -
+ ((hwAbs(Gear^.dX) / (hwAbs(Gear^.dX) + hwAbs(Gear^.dY))) * _0_5 * 7),
+ Gear^.dX, Gear^.dY,
+ cHHStepTicks, cHHRadius * 2 + 7);
HHGear^.Message := 0;
HHGear^.State := HHGear^.State or gstNotKickable;
Gear^.doStep := @doStepBlowTorchWork
@@ -1784,7 +1793,7 @@
Gear^.Y := Gear^.Y + Gear^.dY;
if (not Gear^.dY.isNegative) and (Gear^.dY > _0_001) then
- SetAllHHToActive;
+ SetAllHHToActive(false);
if (not Gear^.dY.isNegative) and (TestCollisionYwithGear(Gear, 1) <> 0) then
begin
@@ -2385,7 +2394,9 @@
repeat
CurrentTeam^.CurrHedgehog := Succ(CurrentTeam^.CurrHedgehog) mod (CurrentTeam^.HedgehogsNumber);
- until (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Gear <> nil) and (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Gear^.Damage = 0);
+ until (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Gear <> nil) and
+ (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Gear^.Damage = 0) and
+ (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Effects[heFrozen]=0);
SwitchCurrentHedgehog(@CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog]);
AmmoMenuInvalidated:= true;
@@ -2418,7 +2429,7 @@
////////////////////////////////////////////////////////////////////////////////
procedure doStepMortar(Gear: PGear);
-var
+var
dX, dY, gdX, gdY: hwFloat;
i: LongInt;
dxn, dyn: boolean;
@@ -2745,7 +2756,7 @@
HHGear := Gear^.Hedgehog^.Gear;
HHGear^.Message := HHGear^.Message and (not gmAttack);
- Gear^.CollisionMask:= $FF7F;
+ Gear^.CollisionMask:= lfNotCurrentMask;
FollowGear := Gear;
@@ -2879,30 +2890,32 @@
procedure doStepDrillDrilling(Gear: PGear);
var
t: PGearArray;
- ox, oy: hwFloat;
+ tempColl: Word;
begin
AllInactive := false;
-
- if (Gear^.Timer > 0) and ((Gear^.Timer mod 10) = 0) then
- begin
- ox := Gear^.X;
- oy := Gear^.Y;
- Gear^.X := Gear^.X + Gear^.dX;
- Gear^.Y := Gear^.Y + Gear^.dY;
- DrawTunnel(oX, oY, Gear^.dX, Gear^.dY, 2, 6);
- if (Gear^.Timer mod 30) = 0 then
- AddVisualGear(hwRound(Gear^.X + _20 * Gear^.dX), hwRound(Gear^.Y + _20 * Gear^.dY), vgtDust);
- if (CheckGearDrowning(Gear)) then
- begin
- StopSoundChan(Gear^.SoundChannel);
- exit
- end
+ if (Gear^.Timer > 0) and (Gear^.Timer mod 10 <> 0) then
+ begin
+ dec(Gear^.Timer);
+ exit;
+ end;
+
+ DrawTunnel(Gear^.X, Gear^.Y, Gear^.dX, Gear^.dY, 2, 6);
+ Gear^.X := Gear^.X + Gear^.dX;
+ Gear^.Y := Gear^.Y + Gear^.dY;
+ if (Gear^.Timer mod 30) = 0 then
+ AddVisualGear(hwRound(Gear^.X + _20 * Gear^.dX), hwRound(Gear^.Y + _20 * Gear^.dY), vgtDust);
+ if (CheckGearDrowning(Gear)) then
+ begin
+ StopSoundChan(Gear^.SoundChannel);
+ exit
end;
- if GameTicks > Gear^.FlightTime then
+ tempColl:= Gear^.CollisionMask;
+ Gear^.CollisionMask:= $007F;
+ if (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) <> 0) or TestCollisionXWithGear(Gear, hwSign(Gear^.dX)) or (GameTicks > Gear^.FlightTime) then
t := CheckGearsCollision(Gear)
-
else t := nil;
+ Gear^.CollisionMask:= tempColl;
//fixes drill not exploding when touching HH bug
if (Gear^.Timer = 0) or ((t <> nil) and (t^.Count <> 0))
@@ -3016,7 +3029,7 @@
ry := rndSign(getRandomf * _0_1);
ball:= AddGear(gx, gy, gtBall, 0, SignAs(AngleSin(HHGear^.Angle) * _0_8, HHGear^.dX) + rx, AngleCos(HHGear^.Angle) * ( - _0_8) + ry, 0);
- ball^.CollisionMask:= $FF7F;
+ ball^.CollisionMask:= lfNotCurrentMask;
PlaySound(sndGun);
end;
@@ -3588,7 +3601,7 @@
doPortalColorSwitch();
// destroy portal if ground it was attached too is gone
- if ((Land[hwRound(Gear^.Y), hwRound(Gear^.X)] and $FF00) = 0)
+ if (Land[hwRound(Gear^.Y), hwRound(Gear^.X)] <= lfAllObjMask)
or (Gear^.Timer < 1)
or (Gear^.Hedgehog^.Team <> CurrentHedgehog^.Team)
or (hwRound(Gear^.Y) > cWaterLine) then
@@ -3628,7 +3641,7 @@
break;
// don't port portals or other gear that wouldn't make sense
- if (iterator^.Kind in [gtPortal, gtRope, gtAirAttack])
+ if (iterator^.Kind in [gtPortal, gtRope, gtAirAttack, gtIceGun])
or (iterator^.PortalCounter > 32) then
continue;
@@ -4371,14 +4384,14 @@
flame:= AddGear(gx, gy, gtFlame, gstTmpFlag,
SignAs(AngleSin(HHGear^.Angle) * speed, HHGear^.dX) + rx,
AngleCos(HHGear^.Angle) * ( - speed) + ry, 0);
- flame^.CollisionMask:= $FF7F;
+ flame^.CollisionMask:= lfNotCurrentMask;
if (Gear^.Health mod 30) = 0 then
begin
flame:= AddGear(gx, gy, gtFlame, 0,
SignAs(AngleSin(HHGear^.Angle) * speed, HHGear^.dX) + rx,
AngleCos(HHGear^.Angle) * ( - speed) + ry, 0);
- flame^.CollisionMask:= $FF7F;
+ flame^.CollisionMask:= lfNotCurrentMask;
end
end;
Gear^.Timer:= Gear^.Tag
@@ -4455,7 +4468,7 @@
land:= AddGear(gx, gy, gtFlake, gstTmpFlag,
SignAs(AngleSin(HHGear^.Angle) * speed, HHGear^.dX) + rx,
AngleCos(HHGear^.Angle) * ( - speed) + ry, 0);
- land^.CollisionMask:= $FF7F;
+ land^.CollisionMask:= lfNotCurrentMask;
Gear^.Timer:= Gear^.Tag
end;
@@ -4579,8 +4592,8 @@
if CheckLandValue(hwRound(Gear^.X + Gear^.dX + SignAs(_6,Gear^.dX)), hwRound(Gear^.Y + _1_9)
, lfIndestructible) then
begin
- Gear^.X := Gear^.X + Gear^.dX;
- Gear^.Y := Gear^.Y + _1_9;
+ //Gear^.X := Gear^.X + Gear^.dX;
+ Gear^.Y := Gear^.Y + _1_9
end;
end;
if TestCollisionYwithGear(Gear, 1) <> 0 then
@@ -4591,14 +4604,15 @@
end
else
begin
- Gear^.dY := Gear^.dY + cGravity;
- Gear^.Y := Gear^.Y + Gear^.dY;
+ //Gear^.dY := Gear^.dY + cGravity;
+ //Gear^.Y := Gear^.Y + Gear^.dY;
if hwRound(Gear^.Y) > cWaterLine then
Gear^.Timer := 1
end;
- Gear^.X := Gear^.X + HitGear^.dX;
+ //Gear^.X := Gear^.X + HitGear^.dX;
HitGear^.X := Gear^.X;
+ HitGear^.Y := Gear^.Y;
SetLittle(HitGear^.dY);
HitGear^.Active:= true;
end;
@@ -4727,6 +4741,7 @@
procedure doStepResurrector(Gear: PGear);
var
graves: PGearArrayS;
+ hh: PHedgehog;
i: LongInt;
len: Integer;
begin
@@ -4735,12 +4750,24 @@
if graves.size > 0 then
begin
+ hh := Gear^.Hedgehog;
for i:= 0 to graves.size - 1 do
begin
PHedgehog(graves.ar^[i]^.Hedgehog)^.Gear := nil;
graves.ar^[i]^.Health := 0;
end;
Gear^.doStep := @doStepResurrectorWork;
+ if ((Gear^.Message and gmAttack) <> 0) and (hh^.Gear^.Health > 0) and (TurnTimeLeft > 0) then
+ begin
+ if LongInt(graves.size) <= Gear^.Tag then Gear^.Tag:= 0;
+ dec(hh^.Gear^.Health);
+ if (hh^.Gear^.Health = 0) and (hh^.Gear^.Damage = 0) then
+ hh^.Gear^.Damage:= 1;
+ RenderHealth(hh^);
+ RecountTeamHealth(hh^.Team);
+ inc(graves.ar^[Gear^.Tag]^.Health);
+ inc(Gear^.Tag)
+ end
end
else
begin
@@ -4953,7 +4980,7 @@
end;
Gear^.Pos:= 4;
// This condition might need tweaking
- Gear^.Timer:= GetRandom(cHedgehogTurnTime*TeamsCount*2)+cHedgehogTurnTime*2
+ Gear^.Timer:= GetRandom(cHedgehogTurnTime*TeamsCount)+cHedgehogTurnTime
end;
if (Gear^.Pos = 4) then
@@ -4989,7 +5016,7 @@
Gear^.Power:= 0;
end
end
- else dec(Gear^.Timer);
+ else if (CurrentHedgehog^.Team^.Clan = Gear^.Hedgehog^.Team^.Clan) then dec(Gear^.Timer)
end;
end;
@@ -5047,39 +5074,83 @@
For now we assume a "ray" like a deagle projected out from the gun.
All these effects assume the ray's angle is not changed and that the target type was unchanged over a number of ticks. This is a simplifying assumption for "gun was applying freezing effect to the same target".
* When fired at water a layer of ice textured land is added above the water.
- * When fired at non-ice land (land and $FF00 and not lfIce) the land is overlaid with a thin layer of ice textured land around that point (say, 1 or 2px into land, 1px above). For attractiveness, a slope would probably be needed.
+ * When fired at non-ice land (land and lfLandMask and not lfIce) the land is overlaid with a thin layer of ice textured land around that point (say, 1 or 2px into land, 1px above). For attractiveness, a slope would probably be needed.
* When fired at a hog (land and $00FF <> 0), while the hog is targetted, the hog's state is set to frozen. As long as the gun is on the hog, a frozen hog sprite creeps up from the feet to the head. If the effect is interrupted before reaching the top, the freezing state is cleared.
A frozen hog will animate differently. To be decided, but possibly in a similar fashion to a grave when it comes to explosions. The hog might (possibly) not be damaged by explosions. This might make freezing potentially useful for friendlies in a bad position. It might be better to allow damage though.
A frozen hog stays frozen for a certain number of turns. Each turn the frozen overlay becomes fainter, until it fades and the hog animates normally again.
*)
+
+procedure updateFuel(Gear: PGear);
+var
+ t:LongInt;
+begin
+ t:= Gear^.Health div 10;
+ if (t <> Gear^.Damage) and ((GameTicks and $3F) = 0) then
+ begin
+ Gear^.Damage:= t;
+ FreeTexture(Gear^.Tex);
+ Gear^.Tex := RenderStringTex(trmsg[sidFuel] + ': ' + inttostr(t) +
+ '%', cWhiteColor, fntSmall)
+ end;
+ if GameTicks mod 10 = 0 then dec(Gear^.Health);
+end;
+
+
+procedure updateTarget(Gear:PGear; newX, newY:HWFloat);
+// var
+// iter:PGear;
+begin
+ with Gear^ do
+ begin
+ dX:= newX;
+ dY:= newY;
+ Pos:= 0;
+ Target.X:= NoPointX;
+ LastDamage:= nil;
+ X:= Hedgehog^.Gear^.X;
+ Y:= Hedgehog^.Gear^.Y;
+ //unfreeze all semifrozen hogs - make this generic hog cleanup
+(*
+ iter := GearsList;
+ while iter <> nil do
+ begin
+ if (iter^.Kind = gtHedgehog) and
+ (iter^.Hedgehog^.Effects[heFrozen] and $FF = 0) then
+ iter^.Hedgehog^.Effects[heFrozen]:= 0;
+ iter:= iter^.NextGear
+ end
+*)
+ end;
+end;
+
procedure doStepIceGun(Gear: PGear);
+const iceWaitCollision:Longint = 0;
+const iceCollideWithGround:Longint = 1;
+//const iceWaitNextTarget:Longint = 2;
+//const iceCollideWithHog:Longint = 4;
+const iceCollideWithWater:Longint = 5;
+//const waterFreezingTime:Longint = 500;
+const groundFreezingTime:Longint = 1000;
+const iceRadius = 32;
+const iceHeight = 40;
var
HHGear: PGear;
+ landRect: TSDL_Rect;
ndX, ndY: hwFloat;
i, t, gX, gY: LongInt;
hogs: PGearArrayS;
len: Integer;
begin
HHGear := Gear^.Hedgehog^.Gear;
- if (Gear^.Health = 0) or (HHGear = nil) or (HHGear^.Damage <> 0) then
+ if (Gear^.Message and gmAttack <> 0) or (Gear^.Health = 0) or (HHGear = nil) or (HHGear^.Damage <> 0) then
begin
DeleteGear(Gear);
AfterAttack;
exit
end
- else
- begin
- t:= Gear^.Health div 10;
- if (t <> Gear^.Damage) and ((GameTicks and $3F) = 0) then
- begin
- Gear^.Damage:= t;
- FreeTexture(Gear^.Tex);
- Gear^.Tex := RenderStringTex(trmsg[sidFuel] + ': ' + inttostr(t) +
- '%', cWhiteColor, fntSmall)
- end
- end;
- if GameTicks mod 10 = 0 then dec(Gear^.Health);
+ else if Gear^.Message and (gmUp or gmDown) = 0 then updateFuel(Gear);
+
with Gear^ do
begin
HedgehogChAngle(HHGear);
@@ -5089,22 +5160,8 @@
((Target.X <> NoPointX) and (Target.X and LAND_WIDTH_MASK = 0) and
(Target.Y and LAND_HEIGHT_MASK = 0) and ((Land[Target.Y, Target.X] = 0))) then
begin
- dX:= ndX;
- dY:= ndY;
- Pos:= 0;
- Target.X:= NoPointX;
- LastDamage:= nil;
- X:= HHGear^.X;
- Y:= HHGear^.Y;
-(* unfreeze all semifrozen hogs - make this generic hog cleanup
- iter := GearsList;
- while iter <> nil do
- begin
- if (iter^.Kind = gtHedgehog) and
- (iter^.Hedgehog^.Effects[heFrozen] < 0) then
- iter^.Hedgehog^.Effects[heFrozen]:= 0;
- iter:= iter^.NextGear
- end *)
+ updateTarget(Gear, ndX, ndY);
+ Timer := iceWaitCollision;
end
else
begin
@@ -5113,22 +5170,67 @@
gX:= hwRound(X);
gY:= hwRound(Y);
if Target.X = NoPointX then t:= hwRound(hwSqr(X-HHGear^.X)+hwSqr(Y-HHGear^.Y));
+
if Target.X <> NoPointX then
begin
+ CheckCollisionWithLand(Gear);
+ if (State and gstCollision) <> 0 then
+ begin
+ if Timer = iceWaitCollision then
+ begin
+ Timer := iceCollideWithGround;
+ Power := GameTicks;
+ end
+ end
+ else if (target.y >= cWaterLine) then
+ begin
+ if Timer = iceWaitCollision then
+ begin
+ Timer := iceCollideWithWater;
+ Power := GameTicks;
+ end;
+ end;
+
if (abs(gX-Target.X) < 2) and (abs(gY-Target.Y) < 2) then
begin
X:= HHGear^.X;
Y:= HHGear^.Y
end;
+
+ if (Timer = iceCollideWithGround) and ((GameTicks - Power) > groundFreezingTime) then
+ begin
+ FillRoundInLand(target.x, target.y, iceRadius, icePixel);
+ landRect.x := min(max(target.x - iceRadius, 0), LAND_WIDTH - 1);
+ landRect.y := min(max(target.y - iceRadius, 0), LAND_HEIGHT - 1);
+ landRect.w := min(2*iceRadius, LAND_WIDTH - landRect.x - 1);
+ landRect.h := min(2*iceRadius, LAND_HEIGHT - landRect.y - 1);
+ UpdateLandTexture(landRect.x, landRect.w, landRect.y, landRect.h, true);
+
+ // FillRoundInLandWithIce(Target.X, Target.Y, iceRadius);
+ SetAllHHToActive;
+ Timer := iceWaitCollision;
+ end;
+
+ if (Timer = iceCollideWithWater) and ((GameTicks - Power) > groundFreezingTime) then
+ begin
+ DrawIceBreak(Target.X, cWaterLine - iceHeight, iceRadius, iceHeight);
+ SetAllHHToActive;
+ Timer := iceWaitCollision;
+ end;
+
// freeze nearby hogs
- if GameTicks mod 10 = 0 then dec(Gear^.Health);
- hogs := GearsNear(Gear^.X, Gear^.Y, gtHedgehog, Gear^.Radius);
+ hogs := GearsNear(int2hwFloat(Target.X), int2hwFloat(Target.Y), gtHedgehog, Gear^.Radius*2);
if hogs.size > 0 then
for i:= 0 to hogs.size - 1 do
if hogs.ar^[i] <> HHGear then
- begin
- //if Gear^.Hedgehog^.Effects[heFrozen]:= 0;
- end;
+ if GameTicks mod 5 = 0 then
+ begin
+ hogs.ar^[i]^.Active:= true;
+ if hogs.ar^[i]^.Hedgehog^.Effects[heFrozen] < 256 then
+ hogs.ar^[i]^.Hedgehog^.Effects[heFrozen] := hogs.ar^[i]^.Hedgehog^.Effects[heFrozen] + 1
+ else if hogs.ar^[i]^.Hedgehog^.Effects[heFrozen] = 256 then
+ hogs.ar^[i]^.Hedgehog^.Effects[heFrozen]:= 200000;//cHedgehogTurnTime + cReadyDelay
+ end;
inc(Pos)
end
else if (t > 400) and ((gY > cWaterLine) or
@@ -5140,14 +5242,14 @@
X:= HHGear^.X;
Y:= HHGear^.Y
end;
- if (gX > max(LAND_WIDTH,4096)*2) or
+ {if (gX > max(LAND_WIDTH,4096)*2) or
(gX < -max(LAND_WIDTH,4096)) or
(gY < -max(LAND_HEIGHT,4096)) or
(gY > max(LAND_HEIGHT,4096)+512) then
- begin
+ begin
X:= HHGear^.X;
Y:= HHGear^.Y
- end
+ end}
end
end;
end;
@@ -5288,7 +5390,7 @@
var a: real;
begin
// Gear is shrunk so it can actually escape the hog without carving into the terrain
- if (Gear^.Radius = 6) and (Gear^.CollisionMask = $FFFF) then Gear^.Radius:= 16;
+ if (Gear^.Radius = 4) and (Gear^.CollisionMask = $FFFF) then Gear^.Radius:= 7;
if Gear^.Damage > 100 then Gear^.CollisionMask:= 0
else if Gear^.Damage > 30 then
if GetRandom(max(4,18-Gear^.Damage div 10)) < 3 then Gear^.CollisionMask:= 0;
@@ -5297,6 +5399,7 @@
if (Gear^.State and gstMoving <> 0) and (Gear^.State and gstCollision = 0) then
begin
DeleteCI(Gear);
+ Gear^.Radius:= 7;
// used for damage and impact calc. needs balancing I think
Gear^.Health:= hwRound(hwSqr((hwAbs(Gear^.dY)+hwAbs(Gear^.dX))*_4));
doStepFallingGear(Gear);
@@ -5332,9 +5435,8 @@
Gear^.dX:= _0;
Gear^.dY:= _0;
Gear^.State:= Gear^.State and (not gstMoving) or gstCollision;
- Gear^.Radius:= 20;
+ Gear^.Radius:= 16;
if Gear^.Health > 0 then AmmoShove(Gear, Gear^.Health, 0);
- Gear^.Radius:= 16;
Gear^.Health:= 0;
Gear^.Timer:= 500;
AddGearCI(Gear)
@@ -5373,7 +5475,7 @@
if Gear^.State and gstDrowning <> 0 then exit;
with Gear^ do
begin
- if CheckLandValue(gx, gy, $FF00) then
+ if CheckLandValue(gx, gy, lfLandMask) then
begin
t:= Angle + hwRound((hwAbs(dX)+hwAbs(dY)) * _10);
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/PNGh.pas
--- a/hedgewars/PNGh.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/PNGh.pas Tue Apr 02 21:00:57 2013 +0200
@@ -23,15 +23,14 @@
uses png;
-{$IFDEF FPC}
- {$PACKRECORDS C}
-{$ELSE}
- {$DEFINE cdecl attribute(cdecl)}
+
+{$IFDEF DARWIN}
+ {$linklib png}
{$ENDIF}
const
// Constants for libpng, they are not defined in png unit.
- // We actually don't need all of them.
+ // We actually do not need all of them.
// These describe the color_type field in png_info.
// color type masks
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/SDLh.pas
--- a/hedgewars/SDLh.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/SDLh.pas Tue Apr 02 21:00:57 2013 +0200
@@ -36,7 +36,10 @@
{$IFDEF UNIX}
{$IFNDEF DARWIN}
- {$linklib c}
+ {necessary for statically linking physfs (divdi3 undefined on 32 bit)}
+ {$IFDEF CPU32}
+ {$linklib stdc++}
+ {$ENDIF}
{$ENDIF}
{$IFDEF HAIKU}
{$linklib root}
@@ -315,6 +318,22 @@
IMG_INIT_PNG = $00000002;
IMG_INIT_TIF = $00000004;
+ {* SDL_keysym *}
+ SDLK_BACKSPACE = 8;
+ SDLK_RETURN = 13;
+ SDLK_ESCAPE = 27;
+ SDLK_q = 113;
+ SDLK_w = 119;
+ SDLK_DELETE = 127;
+ SDLK_UP = 273;
+ SDLK_DOWN = 274;
+ SDLK_RIGHT = 275;
+ SDLK_LEFT = 276;
+ SDLK_HOME = 278;
+ SDLK_END = 279;
+ SDLK_PAGEUP = 280;
+ SDLK_PAGEDOWN = 281;
+
/////////////////////////////////////////////////////////////////
/////////////////////// TYPE DEFINITIONS ///////////////////////
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/config.inc.in
--- a/hedgewars/config.inc.in Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/config.inc.in Tue Apr 02 21:00:57 2013 +0200
@@ -23,5 +23,7 @@
*)
const cNetProtoVersion = ${HEDGEWARS_PROTO_VER};
cVersionString = '${HEDGEWARS_VERSION}';
+ cRevisionString = '${HEDGEWARS_REVISION}';
+ cHashString = '${HEDGEWARS_HASH}';
cLuaLibrary = '${LUA_LIBRARY}';
- cDefaultPathPrefix = '${CMAKE_INSTALL_PREFIX}/${SHAREPATH}/Data';
+ cDefaultPathPrefix = '${HEDGEWARS_FULL_DATADIR}/Data';
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/hwengine.pas
--- a/hedgewars/hwengine.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/hwengine.pas Tue Apr 02 21:00:57 2013 +0200
@@ -196,8 +196,10 @@
{$IFDEF SDL13}
SDL_KEYDOWN:
if GameState = gsChat then
+ begin
// sdl on iphone supports only ashii keyboards and the unicode field is deprecated in sdl 1.3
- KeyPressChat(SDL_GetKeyFromScancode(event.key.keysym.sym))//TODO correct for keymodifiers
+ KeyPressChat(SDL_GetKeyFromScancode(event.key.keysym.sym, event.key.keysym.sym)//TODO correct for keymodifiers
+ end
else
ProcessKey(event.key);
SDL_KEYUP:
@@ -241,7 +243,7 @@
{$ELSE}
SDL_KEYDOWN:
if GameState = gsChat then
- KeyPressChat(event.key.keysym.unicode)
+ KeyPressChat(event.key.keysym.unicode, event.key.keysym.sym)
else
ProcessKey(event.key);
SDL_KEYUP:
@@ -384,8 +386,11 @@
parseCommandLine(argc, argv);
{$ENDIF}
initEverything(true);
- WriteLnToConsole('Hedgewars ' + cVersionString + ' engine (network protocol: ' + inttostr(cNetProtoVersion) + ')');
-
+ WriteLnToConsole('Hedgewars engine ' + cVersionString + '-r' + cRevisionString +
+ ' (' + cHashString + ') with protocol #' + inttostr(cNetProtoVersion));
+ AddFileLog('Prefix: "' + PathPrefix +'"');
+ AddFileLog('UserPrefix: "' + UserPathPrefix +'"');
+
for i:= 0 to ParamCount do
AddFileLog(inttostr(i) + ': ' + ParamStr(i));
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uAI.pas
--- a/hedgewars/uAI.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uAI.pas Tue Apr 02 21:00:57 2013 +0200
@@ -434,7 +434,7 @@
// find another hog in team
repeat
itHedgehog:= Succ(itHedgehog) mod CurrentTeam^.HedgehogsNumber;
- until (itHedgehog = currHedgehogIndex) or (CurrentTeam^.Hedgehogs[itHedgehog].Gear <> nil);
+ until (itHedgehog = currHedgehogIndex) or ((CurrentTeam^.Hedgehogs[itHedgehog].Gear <> nil) and (CurrentTeam^.Hedgehogs[itHedgehog].Effects[heFrozen]=0));
inc(switchesNum);
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uAIAmmoTests.pas
--- a/hedgewars/uAIAmmoTests.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uAIAmmoTests.pas Tue Apr 02 21:00:57 2013 +0200
@@ -197,7 +197,11 @@
x, y, dX, dY: real;
t: LongInt;
value: LongInt;
+ t2: real;
+ timer: Longint;
begin
+ if (Level > 3) then exit(BadTurn);
+
mX:= hwFloat2Float(Me^.X);
mY:= hwFloat2Float(Me^.Y);
ap.Time:= 0;
@@ -225,13 +229,29 @@
until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 5)) or
((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, trunc(x), trunc(y), 5))) or (y > cWaterLine);
+ if TestCollWithLand(trunc(x), trunc(y), 5) and (Abs(Targ.X - trunc(x)) + Abs(Targ.Y - trunc(y)) > 21) then
+ begin
+ timer := 500;
+ t2 := 0.5 / sqrt(sqr(dX) + sqr(dY));
+ dX := dX * t2;
+ dY := dY * t2;
+ repeat
+ x:= x + dX;
+ y:= y + dY;
+ dec(timer);
+ until (Abs(Targ.X - trunc(x)) + Abs(Targ.Y - trunc(y)) < 22)
+ or (x < 0)
+ or (y < 0)
+ or (trunc(x) > LAND_WIDTH)
+ or (trunc(y) > LAND_HEIGHT)
+ or not TestCollWithLand(trunc(x), trunc(y), 5)
+ or (timer = 0)
+ end;
EX:= trunc(x);
EY:= trunc(y);
if Level = 1 then
value:= RateExplosion(Me, EX, EY, 101, afTrackFall or afErasesLand)
else value:= RateExplosion(Me, EX, EY, 101);
- if value = 0 then
- value:= 1024 - Metric(Targ.X, Targ.Y, EX, EY) div 64;
if valueResult <= value then
begin
ap.Angle:= DxDy2AttackAnglef(Vx, Vy) + AIrndSign(random((Level - 1) * 9));
@@ -239,7 +259,7 @@
ap.ExplR:= 100;
ap.ExplX:= EX;
ap.ExplY:= EY;
- valueResult:= value
+ valueResult:= value-2500 // trying to make it slightly less attractive than a bazooka, to prevent waste. AI could use awareness of weapon count
end;
end
until rTime > 4250;
@@ -1171,7 +1191,7 @@
//FillChar(cake, sizeof(cake), 0);
cake.Radius:= 7;
- cake.CollisionMask:= $FF7F;
+ cake.CollisionMask:= lfNotCurrentMask;
cake.Hedgehog:= Me^.Hedgehog;
// check left direction
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uAIMisc.pas
--- a/hedgewars/uAIMisc.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uAIMisc.pas Tue Apr 02 21:00:57 2013 +0200
@@ -74,6 +74,7 @@
function TestCollExcludingObjects(x, y, r: LongInt): boolean; inline;
function TestCollExcludingMe(Me: PGear; x, y, r: LongInt): boolean; inline;
function TraceShoveFall(x, y, dX, dY: Real): LongInt;
+function TestCollWithLand(x, y, r: LongInt): boolean; inline;
function RateExplosion(Me: PGear; x, y, r: LongInt): LongInt; inline;
function RateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt;
@@ -269,7 +270,7 @@
MeX:= hwRound(Me^.X);
MeY:= hwRound(Me^.Y);
// We are still inside the hog. Skip radius test
- if ((((x-MeX)*(x-MeX)) + ((y-MeY)*(y-MeY))) < 256) and ((Land[y, x] and $FF00) = 0) then
+ if ((((x-MeX)*(x-MeX)) + ((y-MeY)*(y-MeY))) < 256) and (Land[y, x] <= lfAllObjMask) and ((Land[y, x] and lfObjMask) < 2) then
exit(false);
end;
TestCollExcludingMe:= TestColl(x, y, r)
@@ -278,19 +279,19 @@
function TestCollExcludingObjects(x, y, r: LongInt): boolean; inline;
var b: boolean;
begin
- b:= (((x-r) and LAND_WIDTH_MASK) = 0) and (((y-r) and LAND_HEIGHT_MASK) = 0) and (Land[y-r, x-r] and $FF00 <> 0);
+ b:= (((x-r) and LAND_WIDTH_MASK) = 0) and (((y-r) and LAND_HEIGHT_MASK) = 0) and (Land[y-r, x-r] > lfAllObjMask);
if b then
exit(true);
- b:= (((x-r) and LAND_WIDTH_MASK) = 0) and (((y+r) and LAND_HEIGHT_MASK) = 0) and (Land[y+r, x-r] and $FF00 <> 0);
+ b:= (((x-r) and LAND_WIDTH_MASK) = 0) and (((y+r) and LAND_HEIGHT_MASK) = 0) and (Land[y+r, x-r] > lfAllObjMask);
if b then
exit(true);
- b:= (((x+r) and LAND_WIDTH_MASK) = 0) and (((y-r) and LAND_HEIGHT_MASK) = 0) and (Land[y-r, x+r] and $FF00 <> 0);
+ b:= (((x+r) and LAND_WIDTH_MASK) = 0) and (((y-r) and LAND_HEIGHT_MASK) = 0) and (Land[y-r, x+r] > lfAllObjMask);
if b then
exit(true);
- b:= (((x+r) and LAND_WIDTH_MASK) = 0) and (((y+r) and LAND_HEIGHT_MASK) = 0) and (Land[y+r, x+r] and $FF00 <> 0);
+ b:= (((x+r) and LAND_WIDTH_MASK) = 0) and (((y+r) and LAND_HEIGHT_MASK) = 0) and (Land[y+r, x+r] > lfAllObjMask);
if b then
exit(true);
@@ -300,19 +301,19 @@
function TestColl(x, y, r: LongInt): boolean; inline;
var b: boolean;
begin
- b:= (((x-r) and LAND_WIDTH_MASK) = 0) and (((y-r) and LAND_HEIGHT_MASK) = 0) and (Land[y-r, x-r] and $FF7F <> 0);
+ b:= (((x-r) and LAND_WIDTH_MASK) = 0) and (((y-r) and LAND_HEIGHT_MASK) = 0) and (Land[y-r, x-r] and lfNotCurrentMask <> 0);
if b then
exit(true);
- b:= (((x-r) and LAND_WIDTH_MASK) = 0) and (((y+r) and LAND_HEIGHT_MASK) = 0) and (Land[y+r, x-r] and $FF7F <> 0);
+ b:= (((x-r) and LAND_WIDTH_MASK) = 0) and (((y+r) and LAND_HEIGHT_MASK) = 0) and (Land[y+r, x-r] and lfNotCurrentMask <> 0);
if b then
exit(true);
- b:= (((x+r) and LAND_WIDTH_MASK) = 0) and (((y-r) and LAND_HEIGHT_MASK) = 0) and (Land[y-r, x+r] and $FF7F <> 0);
+ b:= (((x+r) and LAND_WIDTH_MASK) = 0) and (((y-r) and LAND_HEIGHT_MASK) = 0) and (Land[y-r, x+r] and lfNotCurrentMask <> 0);
if b then
exit(true);
- b:= (((x+r) and LAND_WIDTH_MASK) = 0) and (((y+r) and LAND_HEIGHT_MASK) = 0) and (Land[y+r, x+r] and $FF7F <> 0);
+ b:= (((x+r) and LAND_WIDTH_MASK) = 0) and (((y+r) and LAND_HEIGHT_MASK) = 0) and (Land[y+r, x+r] and lfNotCurrentMask <> 0);
if b then
exit(true);
@@ -322,19 +323,19 @@
function TestCollWithLand(x, y, r: LongInt): boolean; inline;
var b: boolean;
begin
- b:= (((x-r) and LAND_WIDTH_MASK) = 0) and (((y-r) and LAND_HEIGHT_MASK) = 0) and (Land[y-r, x-r] > 255);
+ b:= (((x-r) and LAND_WIDTH_MASK) = 0) and (((y-r) and LAND_HEIGHT_MASK) = 0) and (Land[y-r, x-r] > lfAllObjMask);
if b then
exit(true);
- b:= (((x-r) and LAND_WIDTH_MASK) = 0) and (((y+r) and LAND_HEIGHT_MASK) = 0) and (Land[y+r, x-r] > 255);
+ b:= (((x-r) and LAND_WIDTH_MASK) = 0) and (((y+r) and LAND_HEIGHT_MASK) = 0) and (Land[y+r, x-r] > lfAllObjMask);
if b then
exit(true);
- b:= (((x+r) and LAND_WIDTH_MASK) = 0) and (((y-r) and LAND_HEIGHT_MASK) = 0) and (Land[y-r, x+r] > 255);
+ b:= (((x+r) and LAND_WIDTH_MASK) = 0) and (((y-r) and LAND_HEIGHT_MASK) = 0) and (Land[y-r, x+r] > lfAllObjMask);
if b then
exit(true);
- b:= (((x+r) and LAND_WIDTH_MASK) = 0) and (((y+r) and LAND_HEIGHT_MASK) = 0) and (Land[y+r, x+r] > 255);
+ b:= (((x+r) and LAND_WIDTH_MASK) = 0) and (((y+r) and LAND_HEIGHT_MASK) = 0) and (Land[y+r, x+r] > lfAllObjMask);
if b then
exit(true);
@@ -716,7 +717,7 @@
var pX, pY, tY: LongInt;
begin
HHGo:= false;
-Gear^.CollisionMask:= $FF7F;
+Gear^.CollisionMask:= lfNotCurrentMask;
AltGear^:= Gear^;
GoInfo.Ticks:= 0;
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uChat.pas
--- a/hedgewars/uChat.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uChat.pas Tue Apr 02 21:00:57 2013 +0200
@@ -25,10 +25,10 @@
procedure initModule;
procedure freeModule;
procedure ReloadLines;
-
+procedure CleanupInput;
procedure AddChatString(s: shortstring);
procedure DrawChat;
-procedure KeyPressChat(Key: Longword);
+procedure KeyPressChat(Key, Sym: Longword);
implementation
uses SDLh, uInputHandler, uTypes, uVariables, uCommands, uUtils, uTextures, uRender, uIO;
@@ -45,8 +45,11 @@
var Strs: array[0 .. MaxStrIndex] of TChatLine;
MStrs: array[0 .. MaxStrIndex] of shortstring;
+ LocalStrs: array[0 .. MaxStrIndex] of shortstring;
missedCount: LongWord;
lastStr: LongWord;
+ localLastStr: LongWord;
+ history: LongWord;
visibleCount: LongWord;
InputStr: TChatLine;
InputStrL: array[0..260] of char; // for full str + 4-byte utf-8 char
@@ -291,41 +294,66 @@
ParseCommand('/say ' + s, true);
end;
-procedure KeyPressChat(Key: Longword);
-const firstByteMark: array[0..3] of byte = (0, $C0, $E0, $F0);
-var i, btw: integer;
- utf8: shortstring;
+procedure CleanupInput;
begin
-if Key <> 0 then
- case Key of
- {Backspace}
- 8, 127: if Length(InputStr.s) > 0 then
+ FreezeEnterKey;
+ history:= 0;
+ SDL_EnableKeyRepeat(0,0);
+ GameState:= gsGame;
+ ResetKbd;
+end;
+
+procedure KeyPressChat(Key, Sym: Longword);
+const firstByteMark: array[0..3] of byte = (0, $C0, $E0, $F0);
+var i, btw, index: integer;
+ utf8: shortstring;
+ action: boolean;
+begin
+ action:= true;
+ case Sym of
+ SDLK_BACKSPACE:
+ begin
+ if Length(InputStr.s) > 0 then
begin
InputStr.s[0]:= InputStrL[byte(InputStr.s[0])];
SetLine(InputStr, InputStr.s, true)
- end;
- {Esc}
- 27: if Length(InputStr.s) > 0 then SetLine(InputStr, '', true)
- else
- begin
- FreezeEnterKey;
- SDL_EnableKeyRepeat(0,0);
- GameState:= gsGame;
- ResetKbd;
- end;
- {Return}
- 3, 13, 271: begin
+ end
+ end;
+ SDLK_ESCAPE:
+ begin
+ if Length(InputStr.s) > 0 then
+ SetLine(InputStr, '', true)
+ else CleanupInput
+ end;
+ SDLK_RETURN:
+ begin
if Length(InputStr.s) > 0 then
begin
AcceptChatString(InputStr.s);
SetLine(InputStr, '', false)
end;
- FreezeEnterKey;
- SDL_EnableKeyRepeat(0,0);
- GameState:= gsGame;
- ResetKbd;
+ CleanupInput
+ end;
+ SDLK_UP, SDLK_DOWN:
+ begin
+ if (Sym = SDLK_UP) and (history < localLastStr) then inc(history);
+ if (Sym = SDLK_DOWN) and (history > 0) then dec(history);
+ index:= localLastStr - history + 1;
+ if (index > localLastStr) then
+ SetLine(InputStr, '', true)
+ else SetLine(InputStr, LocalStrs[index], true)
end;
- else
+ SDLK_RIGHT, SDLK_LEFT, SDLK_DELETE,
+ SDLK_HOME, SDLK_END,
+ SDLK_PAGEUP, SDLK_PAGEDOWN:
+ begin
+ // ignore me!!!
+ end;
+ else
+ action:= false;
+ end;
+ if not action and (Key <> 0) then
+ begin
if (Key < $80) then
btw:= 1
else if (Key < $800) then
@@ -335,22 +363,22 @@
else
btw:= 4;
- utf8:= '';
+ utf8:= '';
- for i:= btw downto 2 do
- begin
- utf8:= char((Key or $80) and $BF) + utf8;
- Key:= Key shr 6
- end;
+ for i:= btw downto 2 do
+ begin
+ utf8:= char((Key or $80) and $BF) + utf8;
+ Key:= Key shr 6
+ end;
- utf8:= char(Key or firstByteMark[Pred(btw)]) + utf8;
+ utf8:= char(Key or firstByteMark[Pred(btw)]) + utf8;
- if byte(InputStr.s[0]) + btw > 240 then
- exit;
+ if byte(InputStr.s[0]) + btw > 240 then
+ exit;
- InputStrL[byte(InputStr.s[0]) + btw]:= InputStr.s[0];
- SetLine(InputStr, InputStr.s + utf8, true)
- end
+ InputStrL[byte(InputStr.s[0]) + btw]:= InputStr.s[0];
+ SetLine(InputStr, InputStr.s + utf8, true)
+ end
end;
procedure chChatMessage(var s: shortstring);
@@ -365,7 +393,11 @@
if copy(s, 1, 4) = '/me ' then
s:= #2 + '* ' + UserNick + ' ' + copy(s, 5, Length(s) - 4)
else
+ begin
+ localLastStr:= (localLastStr + 1) mod MaxStrIndex;
+ LocalStrs[localLastStr]:= s;
s:= #1 + UserNick + ': ' + s;
+ end;
AddChatString(s)
end;
@@ -393,17 +425,7 @@
if length(s) = 0 then
SetLine(InputStr, '', true)
else
- begin
- // err, does anyone have any documentation on this sequence?
- // ^^ isn't it obvious? 27 is esc, 32 is space, inbetween is "/team"
- KeyPressChat(27);
- KeyPressChat(47);
- KeyPressChat(116);
- KeyPressChat(101);
- KeyPressChat(97);
- KeyPressChat(109);
- KeyPressChat(32)
- end
+ SetLine(InputStr, '/team ', true)
end;
procedure initModule;
@@ -416,6 +438,8 @@
RegisterVariable('chat', @chChat, true );
lastStr:= 0;
+ localLastStr:= 0;
+ history:= 0;
visibleCount:= 0;
showAll:= false;
ChatReady:= false;
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uCollisions.pas
--- a/hedgewars/uCollisions.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uCollisions.pas Tue Apr 02 21:00:57 2013 +0200
@@ -139,7 +139,7 @@
var x, y, i: LongInt;
begin
// Special case to emulate the old intersect gear clearing, but with a bit of slop for pixel overlap
-if (Gear^.CollisionMask = $FF7F) and (Gear^.Kind <> gtHedgehog) and (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.Gear <> nil) and
+if (Gear^.CollisionMask = lfNotCurrentMask) and (Gear^.Kind <> gtHedgehog) and (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.Gear <> nil) and
((hwRound(Gear^.Hedgehog^.Gear^.X) + Gear^.Hedgehog^.Gear^.Radius + 16 < hwRound(Gear^.X) - Gear^.Radius) or
(hwRound(Gear^.Hedgehog^.Gear^.X) - Gear^.Hedgehog^.Gear^.Radius - 16 > hwRound(Gear^.X) + Gear^.Radius)) then
Gear^.CollisionMask:= $FFFF;
@@ -169,7 +169,7 @@
var x, y, i: LongInt;
begin
// Special case to emulate the old intersect gear clearing, but with a bit of slop for pixel overlap
-if (Gear^.CollisionMask = $FF7F) and (Gear^.Kind <> gtHedgehog) and (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.Gear <> nil) and
+if (Gear^.CollisionMask = lfNotCurrentMask) and (Gear^.Kind <> gtHedgehog) and (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.Gear <> nil) and
((hwRound(Gear^.Hedgehog^.Gear^.Y) + Gear^.Hedgehog^.Gear^.Radius + 16 < hwRound(Gear^.Y) - Gear^.Radius) or
(hwRound(Gear^.Hedgehog^.Gear^.Y) - Gear^.Hedgehog^.Gear^.Radius - 16 > hwRound(Gear^.Y) + Gear^.Radius)) then
Gear^.CollisionMask:= $FFFF;
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uCommandHandlers.pas
--- a/hedgewars/uCommandHandlers.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uCommandHandlers.pas Tue Apr 02 21:00:57 2013 +0200
@@ -595,7 +595,6 @@
if bShowAmmoMenu then
bShowAmmoMenu:= false
else if not(CurrentTeam^.Extdriven) and (((Gear^.State and (gstAttacking or gstAttacked)) <> 0)
- or ((MultiShootAttacks > 0) and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NoRoundEnd) = 0))
or ((Gear^.State and gstHHDriven) = 0)) then
begin
end
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uCommands.pas
--- a/hedgewars/uCommands.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uCommands.pas Tue Apr 02 21:00:57 2013 +0200
@@ -88,12 +88,14 @@
//WriteLnToConsole(CmdStr);
if CmdStr[0]=#0 then
exit;
+
+AddFileLog('[Cmd] ' + sanitizeForLog(CmdStr));
+
c:= CmdStr[1];
if (c = '/') or (c = '$') then
Delete(CmdStr, 1, 1);
s:= '';
SplitBySpace(CmdStr, s);
-AddFileLog('[Cmd] ' + CmdStr + ' (' + inttostr(length(s)) + ')');
t:= Variables;
while t <> nil do
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uConsts.pas
--- a/hedgewars/uConsts.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uConsts.pas Tue Apr 02 21:00:57 2013 +0200
@@ -97,6 +97,16 @@
lfDamaged = $1000; //
lfIce = $0800; // blue
lfBouncy = $0400; // green
+ lfLandMask = $FF00; // upper byte is used for terrain, not objects.
+
+ lfCurrentHog = $0080; // CurrentHog. It is also used to flag crates, for convenience of AI. Since an active hog would instantly collect the crate, this doesn't impact play
+ lfNotCurrentMask = $FF7F; // inverse of above. frequently used
+ lfObjMask = $007F; // lower 7 bits used for hogs
+ lfNotObjMask = $FF80; // inverse of above.
+ // lower byte is for objects.
+ // consists of 0-127 counted for object checkins and $80 as a bit flag for current hog.
+ lfAllObjMask = $00FF; // lfCurrentHog or lfObjMask
+
cMaxPower = 1500;
cMaxAngle = 2048;
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uGame.pas
--- a/hedgewars/uGame.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uGame.pas Tue Apr 02 21:00:57 2013 +0200
@@ -27,20 +27,24 @@
implementation
////////////////////
uses uInputHandler, uTeams, uIO, uAI, uGears, uSound,
+ uLocale, uCaptions,
uVisualGears, uTypes, uVariables, uCommands, uConsts
{$IFDEF USE_TOUCH_INTERFACE}, uTouch{$ENDIF};
procedure DoGameTick(Lag: LongInt);
-var i: LongInt;
+var i,j : LongInt;
+ s: shortstring;
begin
if isPaused then
exit;
+
if (not CurrentTeam^.ExtDriven) then
begin
NetGetNextCmd; // its for the case of receiving "/say" message
isInLag:= false;
- SendKeepAliveMessage(Lag)
+ FlushMessages(Lag)
end;
+
if GameType <> gmtRecord then
begin
if Lag > 100 then
@@ -61,6 +65,23 @@
else if cOnlyStats then
Lag:= High(LongInt)
end;
+inc(SoundTimerTicks, Lag);
+if SoundTimerTicks >= 50 then
+ begin
+ SoundTimerTicks:= 0;
+ if cVolumeDelta <> 0 then
+ begin
+ j:= Volume;
+ i:= ChangeVolume(cVolumeDelta);
+ if isAudioMuted and (j<>i) then
+ AddCaption(trmsg[sidMute], cWhiteColor, capgrpVolume)
+ else if not isAudioMuted then
+ begin
+ str(i, s);
+ AddCaption(Format(trmsg[sidVolume], s), cWhiteColor, capgrpVolume)
+ end
+ end;
+ end;
PlayNextVoice;
i:= 1;
while (GameState <> gsExit) and (i <= Lag) do
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uGears.pas
--- a/hedgewars/uGears.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uGears.pas Tue Apr 02 21:00:57 2013 +0200
@@ -46,7 +46,8 @@
procedure ProcessGears;
procedure EndTurnCleanup;
procedure SetAllToActive;
-procedure SetAllHHToActive;
+procedure SetAllHHToActive; inline;
+procedure SetAllHHToActive(Ice: boolean);
procedure DrawGears;
procedure FreeGearsList;
procedure AddMiscGears;
@@ -441,8 +442,8 @@
if TurnTimeLeft > 0 then
if CurrentHedgehog^.Gear <> nil then
- if ((CurrentHedgehog^.Gear^.State and gstAttacking) = 0)
- and (not isInMultiShoot) then
+ if ((CurrentHedgehog^.Gear^.State and gstAttacking) = 0) and
+ not(isInMultiShoot and (CurrentHedgehog^.CurAmmoType in [amShotgun, amDEagle, amSniperRifle])) then
begin
if (TurnTimeLeft = 5000)
and (cHedgehogTurnTime >= 10000)
@@ -561,7 +562,12 @@
end
end;
-procedure SetAllHHToActive;
+procedure SetAllHHToActive; inline;
+begin
+SetAllHHToActive(true)
+end;
+
+procedure SetAllHHToActive(Ice: boolean);
var t: PGear;
begin
AllInactive:= false;
@@ -569,12 +575,14 @@
while t <> nil do
begin
if (t^.Kind = gtHedgehog) or (t^.Kind = gtExplosives) then
- t^.Active:= true;
+ begin
+ if (t^.Kind = gtHedgehog) and Ice then CheckIce(t);
+ t^.Active:= true
+ end;
t:= t^.NextGear
end
end;
-
procedure DrawGears;
var Gear: PGear;
x, y: LongInt;
@@ -766,6 +774,8 @@
begin
dec(i);
Gear:= t^.ar[i];
+ if (Ammo^.Kind = gtFlame) and (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog^.Effects[heFrozen] > 255) then
+ Gear^.Hedgehog^.Effects[heFrozen]:= max(255,Gear^.Hedgehog^.Effects[heFrozen]-10000);
tmpDmg:= ModifyDamage(Damage, Gear);
if (Gear^.State and gstNoDamage) = 0 then
begin
@@ -780,6 +790,7 @@
if (Gear^.Kind = gtHedgehog) and (Ammo^.State and gsttmpFlag <> 0) and (Ammo^.Kind = gtShover) then
Gear^.FlightTime:= 1;
+
case Gear^.Kind of
gtHedgehog,
gtMine,
@@ -827,7 +838,7 @@
ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg * 100, dsUnknown); // crank up damage for explosives + blowtorch
end;
- if (Gear^.Kind = gtHedgehog) and Gear^.Hedgehog^.King then
+ if (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog^.King or (Gear^.Hedgehog^.Effects[heFrozen] > 0)) then
begin
Gear^.dX:= Ammo^.dX * Power * _0_005;
Gear^.dY:= Ammo^.dY * Power * _0_005
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uGearsHandlersRope.pas
--- a/hedgewars/uGearsHandlersRope.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uGearsHandlersRope.pas Tue Apr 02 21:00:57 2013 +0200
@@ -33,6 +33,14 @@
HHGear: PGear;
begin
HHGear := Gear^.Hedgehog^.Gear;
+ if (HHGear^.Hedgehog^.CurAmmoType = amParachute) and (HHGear^.dY > _0_39) then
+ begin
+ DeleteGear(Gear);
+ ApplyAmmoChanges(HHGear^.Hedgehog^);
+ HHGear^.Message:= HHGear^.Message or gmLJump;
+ exit
+ end;
+
if ((HHGear^.State and gstHHDriven) = 0)
or (CheckGearDrowning(HHGear))
or (TestCollisionYwithGear(HHGear, 1) <> 0) then
@@ -102,7 +110,7 @@
lx, ly, cd: LongInt;
haveCollision,
haveDivided: boolean;
-
+ wrongSide: boolean;
begin
if GameTicks mod 4 <> 0 then exit;
@@ -165,12 +173,12 @@
if ((Gear^.Message and gmDown) <> 0) and (Gear^.Elasticity < Gear^.Friction) then
if not (TestCollisionXwithGear(HHGear, hwSign(ropeDx))
- or (TestCollisionYwithGear(HHGear, hwSign(ropeDy)) <> 0)) then
+ or ((ropeDy.QWordValue <> 0) and TestCollisionYwithXYShift(HHGear, 0, 1, hwSign(ropeDy)))) then
Gear^.Elasticity := Gear^.Elasticity + _1_2;
if ((Gear^.Message and gmUp) <> 0) and (Gear^.Elasticity > _30) then
if not (TestCollisionXwithGear(HHGear, -hwSign(ropeDx))
- or (TestCollisionYwithGear(HHGear, -hwSign(ropeDy)) <> 0)) then
+ or ((ropeDy.QWordValue <> 0) and TestCollisionYwithXYShift(HHGear, 0, 1, -hwSign(ropeDy)))) then
Gear^.Elasticity := Gear^.Elasticity - _1_2;
HHGear^.X := Gear^.X + mdX * Gear^.Elasticity;
@@ -194,7 +202,7 @@
begin
lx := hwRound(nx);
ly := hwRound(ny);
- if ((ly and LAND_HEIGHT_MASK) = 0) and ((lx and LAND_WIDTH_MASK) = 0) and ((Land[ly, lx] and $FF00) <> 0) then
+ if ((ly and LAND_HEIGHT_MASK) = 0) and ((lx and LAND_WIDTH_MASK) = 0) and (Land[ly, lx] > lfAllObjMask) then
begin
tx := _1 / Distance(ropeDx, ropeDy);
// old rope pos
@@ -208,6 +216,9 @@
if RopePoints.Count = 0 then
RopePoints.HookAngle := DxDy2Angle(Gear^.dY, Gear^.dX);
b := (nx * HHGear^.dY) > (ny * HHGear^.dX);
+ sx:= Gear^.dX.isNegative;
+ sy:= Gear^.dY.isNegative;
+ sb:= Gear^.dX.QWordValue < Gear^.dY.QWordValue;
dLen := len
end;
@@ -240,21 +251,45 @@
ty := RopePoints.ar[Pred(RopePoints.Count)].Y;
mdX := tx - Gear^.X;
mdY := ty - Gear^.Y;
- if RopePoints.ar[Pred(RopePoints.Count)].b xor (mdX * (ty - HHGear^.Y) > (tx - HHGear^.X) * mdY) then
+ ropeDx:= tx - HHGear^.X;
+ ropeDy:= ty - HHGear^.Y;
+ if RopePoints.ar[Pred(RopePoints.Count)].b xor (mdX * ropeDy > ropeDx * mdY) then
begin
dec(RopePoints.Count);
- Gear^.X := RopePoints.ar[RopePoints.Count].X;
- Gear^.Y := RopePoints.ar[RopePoints.Count].Y;
- Gear^.Elasticity := Gear^.Elasticity + RopePoints.ar[RopePoints.Count].dLen;
- Gear^.Friction := Gear^.Friction + RopePoints.ar[RopePoints.Count].dLen;
+ Gear^.X := tx;
+ Gear^.Y := ty;
+
+ // oops, opposite quadrant, don't restore hog position in such case, just remove the point
+ wrongSide:= (ropeDx.isNegative = RopePoints.ar[RopePoints.Count].sx)
+ and (ropeDy.isNegative = RopePoints.ar[RopePoints.Count].sy);
+
+ // previous check could be inaccurate in vertical/horizontal rope positions,
+ // so perform this check also, even though odds are 1 to 415927 to hit this
+ if (not wrongSide)
+ and ((ropeDx.isNegative = RopePoints.ar[RopePoints.Count].sx)
+ <> (ropeDy.isNegative = RopePoints.ar[RopePoints.Count].sy)) then
+ if RopePoints.ar[RopePoints.Count].sb then
+ wrongSide:= ropeDy.isNegative = RopePoints.ar[RopePoints.Count].sy
+ else
+ wrongSide:= ropeDx.isNegative = RopePoints.ar[RopePoints.Count].sx;
- // restore hog position
- len := _1 / Distance(mdX, mdY);
- mdX := mdX * len;
- mdY := mdY * len;
+ if wrongSide then
+ begin
+ Gear^.Elasticity := Gear^.Elasticity - RopePoints.ar[RopePoints.Count].dLen;
+ Gear^.Friction := Gear^.Friction - RopePoints.ar[RopePoints.Count].dLen;
+ end else
+ begin
+ Gear^.Elasticity := Gear^.Elasticity + RopePoints.ar[RopePoints.Count].dLen;
+ Gear^.Friction := Gear^.Friction + RopePoints.ar[RopePoints.Count].dLen;
- HHGear^.X := Gear^.X - mdX * Gear^.Elasticity;
- HHGear^.Y := Gear^.Y - mdY * Gear^.Elasticity;
+ // restore hog position
+ len := _1 / Distance(mdX, mdY);
+ mdX := mdX * len;
+ mdY := mdY * len;
+
+ HHGear^.X := Gear^.X - mdX * Gear^.Elasticity;
+ HHGear^.Y := Gear^.Y - mdY * Gear^.Elasticity;
+ end;
end
end;
@@ -264,7 +299,7 @@
HHGear^.dX := -_0_6 * HHGear^.dX;
haveCollision := true
end;
- if TestCollisionYwithGear(HHGear, hwSign(HHGear^.dY)) <> 0 then
+ if TestCollisionYwithXYShift(HHGear, 0, 1, hwSign(HHGear^.dY)) then
begin
HHGear^.dY := -_0_6 * HHGear^.dY;
haveCollision := true
@@ -390,7 +425,7 @@
ty := _0;
while tt > _20 do
begin
- if ((hwRound(Gear^.Y+ty) and LAND_HEIGHT_MASK) = 0) and ((hwRound(Gear^.X+tx) and LAND_WIDTH_MASK) = 0) and ((Land[hwRound(Gear^.Y+ty), hwRound(Gear^.X+tx)] and $FF00) <> 0) then
+ if ((hwRound(Gear^.Y+ty) and LAND_HEIGHT_MASK) = 0) and ((hwRound(Gear^.X+tx) and LAND_WIDTH_MASK) = 0) and (Land[hwRound(Gear^.Y+ty), hwRound(Gear^.X+tx)] > lfAllObjMask) then
begin
Gear^.X := Gear^.X + tx;
Gear^.Y := Gear^.Y + ty;
@@ -414,8 +449,8 @@
end;
end;
- if Gear^.Elasticity < _20 then Gear^.CollisionMask:= $FF00
- else Gear^.CollisionMask:= $FF7F;
+ if Gear^.Elasticity < _20 then Gear^.CollisionMask:= lfLandMask
+ else Gear^.CollisionMask:= lfNotCurrentMask;
CheckCollision(Gear);
if (Gear^.State and gstCollision) <> 0 then
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uGearsHedgehog.pas
--- a/hedgewars/uGearsHedgehog.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uGearsHedgehog.pas Tue Apr 02 21:00:57 2013 +0200
@@ -29,6 +29,7 @@
procedure HedgehogChAngle(HHGear: PGear);
procedure PickUp(HH, Gear: PGear);
procedure AddPickup(HH: THedgehog; ammo: TAmmoType; cnt, X, Y: LongWord);
+procedure CheckIce(Gear: PGear); inline;
implementation
uses uConsts, uVariables, uFloat, uAmmos, uSound, uCaptions,
@@ -53,7 +54,6 @@
prevAmmo:= CurAmmoType;
ammoidx:= 0;
if ((HHGear^.State and (gstAttacking or gstAttacked)) <> 0)
- or ((MultiShootAttacks > 0) and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NoRoundEnd) = 0))
or ((HHGear^.State and gstHHDriven) = 0) then
exit;
ChangeAmmo:= true;
@@ -61,8 +61,17 @@
while (ammoidx < cMaxSlotAmmoIndex) and (Ammo^[slot, ammoidx].AmmoType <> CurAmmoType) do
inc(ammoidx);
- if ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NoRoundEnd) <> 0) and (MultiShootAttacks > 0) then
- OnUsedAmmo(HHGear^.Hedgehog^);
+ if (MultiShootAttacks > 0) then
+ begin
+ if (CurAmmoType = amSniperRifle) and ((GameFlags and gfArtillery) = 0) then
+ cArtillery := false;
+ if (Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NoRoundEnd) = 0 then
+ begin
+ MultiShootAttacks:= Ammoz[CurAmmoType].Ammo.NumPerTurn;
+ AfterAttack
+ end
+ else OnUsedAmmo(HHGear^.Hedgehog^)
+ end;
MultiShootAttacks:= 0;
HHGear^.Message:= HHGear^.Message and (not (gmLJump or gmHJump));
@@ -211,9 +220,7 @@
and ((TargetPoint.X <> NoPointX) or ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NeedTarget) = 0)) then
begin
State:= State or gstAttacking;
- if Power = cMaxPower then
- Message:= Message and (not gmAttack)
- else if (Ammoz[CurAmmoType].Ammo.Propz and ammoprop_Power) = 0 then
+ if (Power = cMaxPower) or ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_Power) = 0) then
Message:= Message and (not gmAttack)
else
begin
@@ -224,44 +231,44 @@
end;
inc(Power)
end;
- if ((Message and gmAttack) <> 0) then
- exit;
+ if ((Message and gmAttack) <> 0) then
+ exit;
- if (Ammoz[CurAmmoType].Ammo.Propz and ammoprop_Power) <> 0 then
- begin
- StopSound(sndThrowPowerUp);
- PlaySound(sndThrowRelease);
- end;
+ if (Ammoz[CurAmmoType].Ammo.Propz and ammoprop_Power) <> 0 then
+ begin
+ StopSound(sndThrowPowerUp);
+ PlaySound(sndThrowRelease);
+ end;
- xx:= SignAs(AngleSin(Angle), dX);
- yy:= -AngleCos(Angle);
+ xx:= SignAs(AngleSin(Angle), dX);
+ yy:= -AngleCos(Angle);
- lx:= X + int2hwfloat(round(GetLaunchX(CurAmmoType, hwSign(dX), Angle)));
- ly:= Y + int2hwfloat(round(GetLaunchY(CurAmmoType, Angle)));
+ lx:= X + int2hwfloat(round(GetLaunchX(CurAmmoType, hwSign(dX), Angle)));
+ ly:= Y + int2hwfloat(round(GetLaunchY(CurAmmoType, Angle)));
- if ((Gear^.State and gstHHHJump) <> 0) and (not cArtillery) then
- xx:= - xx;
- if Ammoz[CurAmmoType].Ammo.AttackVoice <> sndNone then
- AddVoice(Ammoz[CurAmmoType].Ammo.AttackVoice, CurrentTeam^.voicepack);
+ if ((Gear^.State and gstHHHJump) <> 0) and (not cArtillery) then
+ xx:= - xx;
+ if Ammoz[CurAmmoType].Ammo.AttackVoice <> sndNone then
+ AddVoice(Ammoz[CurAmmoType].Ammo.AttackVoice, CurrentTeam^.voicepack);
// Initiating alt attack
- if (CurAmmoGear <> nil)
- and ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0)
- and ((Gear^.Message and gmLJump) <> 0)
- and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AltUse) <> 0) then
- begin
- newDx:= dX;
- newDy:= dY;
- altUse:= true
- end
- else
- begin
- newDx:= xx*Power/cPowerDivisor;
- newDy:= yy*Power/cPowerDivisor;
- altUse:= false
- end;
+ if (CurAmmoGear <> nil)
+ and ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0)
+ and ((Gear^.Message and gmLJump) <> 0)
+ and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AltUse) <> 0) then
+ begin
+ newDx:= dX;
+ newDy:= dY;
+ altUse:= true
+ end
+ else
+ begin
+ newDx:= xx*Power/cPowerDivisor;
+ newDy:= yy*Power/cPowerDivisor;
+ altUse:= false
+ end;
- case CurAmmoType of
+ case CurAmmoType of
amGrenade: newGear:= AddGear(hwRound(lx), hwRound(ly), gtGrenade, 0, newDx, newDy, CurWeapon^.Timer);
amMolotov: newGear:= AddGear(hwRound(lx), hwRound(ly), gtMolotov, 0, newDx, newDy, 0);
amClusterBomb: newGear:= AddGear(hwRound(lx), hwRound(ly), gtClusterBomb, 0, newDx, newDy, CurWeapon^.Timer);
@@ -281,7 +288,7 @@
amKnife: begin
newGear:= AddGear(hwRound(lx), hwRound(ly), gtKnife, 0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, 0);
newGear^.State:= newGear^.State or gstMoving;
- newGear^.Radius:= 6 // temporarily shrink so it doesn't instantly embed in the ground
+ newGear^.Radius:= 4 // temporarily shrink so it doesn't instantly embed in the ground
end;
amDEagle: newGear:= AddGear(hwRound(lx + xx * cHHRadius), hwRound(ly + yy * cHHRadius), gtDEagleShot, 0, xx * _0_5, yy * _0_5, 0);
amSineGun: newGear:= AddGear(hwRound(lx + xx * cHHRadius), hwRound(ly + yy * cHHRadius), gtSineGunShot, 0, xx * _0_5, yy * _0_5, 0);
@@ -377,56 +384,56 @@
//amStructure: newGear:= AddGear(hwRound(lx) + hwSign(dX) * 7, hwRound(ly), gtStructure, gstWait, SignAs(_0_02, dX), _0, 3000);
amTardis: newGear:= AddGear(hwRound(X), hwRound(Y), gtTardis, 0, _0, _0, 5000);
amIceGun: newGear:= AddGear(hwRound(X), hwRound(Y), gtIceGun, 0, _0, _0, 0);
- end;
- if altUse and (newGear <> nil) then
- begin
- newGear^.dX:= newDx / newGear^.Density;
- newGear^.dY:= newDY / newGear^.Density
- end;
+ end;
+ if altUse and (newGear <> nil) then
+ begin
+ newGear^.dX:= newDx / newGear^.Density;
+ newGear^.dY:= newDY / newGear^.Density
+ end;
- case CurAmmoType of
- amGrenade, amMolotov,
- amClusterBomb, amGasBomb,
- amBazooka, amSnowball,
- amBee, amSMine,
- amMortar, amWatermelon,
- amHellishBomb, amDrill: FollowGear:= newGear;
+ case CurAmmoType of
+ amGrenade, amMolotov,
+ amClusterBomb, amGasBomb,
+ amBazooka, amSnowball,
+ amBee, amSMine,
+ amMortar, amWatermelon,
+ amHellishBomb, amDrill: FollowGear:= newGear;
- amShotgun, amPickHammer,
- amRope, amDEagle,
- amSineGun, amSniperRifle,
- amFirePunch, amWhip,
- amHammer, amBaseballBat,
- amParachute, amBlowTorch,
- amGirder, amTeleport,
- amSwitch, amRCPlane,
- amKamikaze, amCake,
- amSeduction, amBallgun,
- amJetpack, amBirdy,
- amFlamethrower, amLandGun,
- amResurrector, //amStructure,
- amTardis, amPiano,
- amIceGun: CurAmmoGear:= newGear;
- end;
+ amShotgun, amPickHammer,
+ amRope, amDEagle,
+ amSineGun, amSniperRifle,
+ amFirePunch, amWhip,
+ amHammer, amBaseballBat,
+ amParachute, amBlowTorch,
+ amGirder, amTeleport,
+ amSwitch, amRCPlane,
+ amKamikaze, amCake,
+ amSeduction, amBallgun,
+ amJetpack, amBirdy,
+ amFlamethrower, amLandGun,
+ amResurrector, //amStructure,
+ amTardis, amPiano,
+ amIceGun: CurAmmoGear:= newGear;
+ end;
if ((CurAmmoType = amMine) or (CurAmmoType = amSMine)) and (GameFlags and gfInfAttack <> 0) then
newGear^.FlightTime:= GameTicks + 1000
else if CurAmmoType = amDrill then
newGear^.FlightTime:= GameTicks + 250;
- if Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NeedTarget <> 0 then
- begin
- newGear^.Target.X:= TargetPoint.X;
- newGear^.Target.Y:= TargetPoint.Y
- end;
- if (newGear <> nil) and (newGear^.CollisionMask and $80 <> 0) then newGear^.CollisionMask:= newGear^.CollisionMask and (not $80);
+ if Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NeedTarget <> 0 then
+ begin
+ newGear^.Target.X:= TargetPoint.X;
+ newGear^.Target.Y:= TargetPoint.Y
+ end;
+ if (newGear <> nil) and (newGear^.CollisionMask and lfCurrentHog <> 0) then newGear^.CollisionMask:= newGear^.CollisionMask and (not lfCurrentHog);
- // Clear FollowGear if using on a rope/parachute/saucer etc so focus stays with the hog's movement
- if altUse then
- FollowGear:= nil;
+ // Clear FollowGear if using on a rope/parachute/saucer etc so focus stays with the hog's movement
+ if altUse then
+ FollowGear:= nil;
- if (newGear <> nil) and ((Ammoz[newGear^.AmmoType].Ammo.Propz and ammoprop_SetBounce) <> 0) then
- begin
- elastic:= int2hwfloat(CurWeapon^.Bounciness) / _1000;
+ if (newGear <> nil) and ((Ammoz[newGear^.AmmoType].Ammo.Propz and ammoprop_SetBounce) <> 0) then
+ begin
+ elastic:= int2hwfloat(CurWeapon^.Bounciness) / _1000;
if elastic < _1 then
newGear^.Elasticity:= newGear^.Elasticity * elastic
@@ -439,37 +446,36 @@
end;
- uStats.AmmoUsed(CurAmmoType);
+ uStats.AmmoUsed(CurAmmoType);
- if not (SpeechText = '') then
- begin
- speech:= AddVisualGear(0, 0, vgtSpeechBubble);
- if speech <> nil then
+ if not (SpeechText = '') then
begin
- speech^.Text:= SpeechText;
- speech^.Hedgehog:= Gear^.Hedgehog;
- speech^.FrameTicks:= SpeechType;
+ speech:= AddVisualGear(0, 0, vgtSpeechBubble);
+ if speech <> nil then
+ begin
+ speech^.Text:= SpeechText;
+ speech^.Hedgehog:= Gear^.Hedgehog;
+ speech^.FrameTicks:= SpeechType;
+ end;
+ SpeechText:= ''
end;
- SpeechText:= ''
- end;
- Power:= 0;
- if (CurAmmoGear <> nil)
- and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AltUse) = 0){check for dropping ammo from rope} then
- begin
- Message:= Message or gmAttack;
- CurAmmoGear^.Message:= Message
+ Power:= 0;
+ if (CurAmmoGear <> nil) and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AltUse) = 0){check for dropping ammo from rope} then
+ begin
+ if CurAmmoType in [amRope,amResurrector] then
+ Message:= Message or gmAttack;
+ CurAmmoGear^.Message:= Message
+ end
+ else
+ begin
+ if (not CurrentTeam^.ExtDriven) and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_Power) <> 0) then
+ SendIPC(_S'a');
+ AfterAttack;
+ end
end
else
- begin
- if not CurrentTeam^.ExtDriven
- and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_Power) <> 0) then
- SendIPC(_S'a');
- AfterAttack;
- end
- end
- else
- Message:= Message and (not gmAttack);
+ Message:= Message and (not gmAttack);
end;
TargetPoint.X := NoPointX;
ScriptCall('onHogAttack');
@@ -777,7 +783,7 @@
if (not cArtillery) and ((Gear^.Message and gmPrecise) = 0) then
MakeHedgehogsStep(Gear);
- SetAllHHToActive;
+ SetAllHHToActive(false);
AddGearCI(Gear)
end
end;
@@ -786,7 +792,7 @@
var da: LongWord;
begin
with HHGear^.Hedgehog^ do
- if ((CurAmmoType = amRope) and ((HHGear^.State and (gstMoving or gstHHJumping)) = gstMoving))
+ if ((CurAmmoGear <> nil) and (CurAmmoGear^.AmmoType = amRope) and ((HHGear^.State and (gstMoving or gstHHJumping)) = gstMoving))
or ((CurAmmoType = amPortalGun) and ((HHGear^.State and gstMoving) <> 0)) then
da:= 2
else da:= 1;
@@ -887,35 +893,40 @@
if TestCollisionXKick(Gear, hwSign(Gear^.dX)) then
if not isFalling then
if hwAbs(Gear^.dX) > _0_01 then
- if not TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -1, hwSign(Gear^.dX)) then
+ if not (TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -1, hwSign(Gear^.dX)) or
+ (TestCollisionYwithXYShift(Gear, hwSign(Gear^.dX) - hwRound(Gear^.dX), -1, -1))) then
begin
Gear^.X:= Gear^.X + Gear^.dX;
Gear^.dX:= Gear^.dX * _0_96;
Gear^.Y:= Gear^.Y - _1
end
else
- if not TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -2, hwSign(Gear^.dX)) then
+ if not (TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -2, hwSign(Gear^.dX)) or
+ (TestCollisionYwithXYShift(Gear, hwSign(Gear^.dX) - hwRound(Gear^.dX), -1, -1))) then
begin
Gear^.X:= Gear^.X + Gear^.dX;
Gear^.dX:= Gear^.dX * _0_93;
Gear^.Y:= Gear^.Y - _2
end
else
- if not TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -3, hwSign(Gear^.dX)) then
+ if not (TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -3, hwSign(Gear^.dX)) or
+ (TestCollisionYwithXYShift(Gear, hwSign(Gear^.dX) - hwRound(Gear^.dX), -1, -1))) then
begin
Gear^.X:= Gear^.X + Gear^.dX;
Gear^.dX:= Gear^.dX * _0_9 ;
Gear^.Y:= Gear^.Y - _3
end
else
- if not TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -4, hwSign(Gear^.dX)) then
+ if not (TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -4, hwSign(Gear^.dX)) or
+ (TestCollisionYwithXYShift(Gear, hwSign(Gear^.dX) - hwRound(Gear^.dX), -1, -1))) then
begin
Gear^.X:= Gear^.X + Gear^.dX;
Gear^.dX:= Gear^.dX * _0_87;
Gear^.Y:= Gear^.Y - _4
end
else
- if not TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -5, hwSign(Gear^.dX)) then
+ if not (TestCollisionXwithXYShift(Gear, int2hwFloat(hwSign(Gear^.dX)) - Gear^.dX, -5, hwSign(Gear^.dX)) or
+ (TestCollisionYwithXYShift(Gear, hwSign(Gear^.dX) - hwRound(Gear^.dX), -1, -1))) then
begin
Gear^.X:= Gear^.X + Gear^.dX;
Gear^.dX:= Gear^.dX * _0_84;
@@ -1000,7 +1011,9 @@
Hedgehog: PHedgehog;
begin
Hedgehog:= HHGear^.Hedgehog;
-if isInMultiShoot then
+if not isInMultiShoot then
+ AllInactive:= false
+else if Hedgehog^.CurAmmoType in [amShotgun, amDEagle, amSniperRifle] then
HHGear^.Message:= 0;
if ((Ammoz[CurrentHedgehog^.CurAmmoType].Ammo.Propz and ammoprop_Utility) <> 0) and isInMultiShoot then
@@ -1010,6 +1023,8 @@
if (TurnTimeLeft = 0) or (HHGear^.Damage > 0) then
begin
+ if (Hedgehog^.CurAmmoType = amKnife) then
+ LoadHedgehogHat(Hedgehog^, Hedgehog^.Hat);
if TagTurnTimeLeft = 0 then
TagTurnTimeLeft:= TurnTimeLeft;
TurnTimeLeft:= 0;
@@ -1086,7 +1101,6 @@
exit
end;
-if not isInMultiShoot then
HedgehogChAngle(HHGear);
if (HHGear^.State and gstMoving) <> 0 then
@@ -1122,7 +1136,7 @@
exit
end;
- if (not isInMultiShoot) and (Hedgehog^.Gear <> nil) then
+ if not(isInMultiShoot and (Hedgehog^.CurAmmoType in [amShotgun, amDEagle, amSniperRifle])) and (Hedgehog^.Gear <> nil) then
begin
if GHStepTicks > 0 then
dec(GHStepTicks);
@@ -1194,7 +1208,7 @@
if Gear^.Timer = 0 then
begin
Gear^.State:= Gear^.State and (not (gstWait or gstLoser or gstWinner or gstAttacked or gstNotKickable or gstHHChooseTarget));
- Gear^.Active:= false;
+ if Gear^.Hedgehog^.Effects[heFrozen] = 0 then Gear^.Active:= false;
AddGearCI(Gear);
exit
end
@@ -1204,40 +1218,25 @@
AllInactive:= false
end;
-////////////////////////////////////////////////////////////////////////////////
-procedure doStepHedgehog(Gear: PGear);
+procedure CheckIce(Gear: PGear); inline;
(*
var x,y,tx,ty: LongInt;
tdX, tdY, slope: hwFloat;
land: Word; *)
var slope: hwFloat;
begin
-CheckSum:= CheckSum xor Gear^.Hedgehog^.BotLevel;
-if (Gear^.Message and gmDestroy) <> 0 then
- begin
- DeleteGear(Gear);
- exit
- end;
-
-if (Gear^.State and gstHHDriven) = 0 then
- doStepHedgehogFree(Gear)
-else
- begin
- with Gear^.Hedgehog^ do
- if Team^.hasGone then
- TeamGoneEffect(Team^)
- else
- doStepHedgehogDriven(Gear)
- end;
-if (Gear^.Message and (gmAllStoppable or gmLJump or gmHJump) = 0)
-and (Gear^.State and (gstHHJumping or gstHHHJump or gstAttacking) = 0)
-and (not Gear^.dY.isNegative) and (GameTicks mod (100*LongWOrd(hwRound(cMaxWindSpeed*2/cGravity))) = 0)
-and (TestCollisionYwithGear(Gear, 1) and lfIce <> 0) then
- begin
- slope:= CalcSlopeBelowGear(Gear);
- Gear^.dX:=Gear^.dX+slope*_0_07;
- if slope.QWordValue <> 0 then
- Gear^.State:= Gear^.State or gstMoving;
+ if (Gear^.Message and (gmAllStoppable or gmLJump or gmHJump) = 0)
+ and (Gear^.State and (gstHHJumping or gstHHHJump or gstAttacking) = 0)
+ and ((Gear^.Hedgehog = nil) or ((Gear^.Hedgehog^.Effects[heFrozen] = 0) or (Gear^.Hedgehog^.Effects[heFrozen] > 255)))
+ and (not Gear^.dY.isNegative) and (TurnTimeLeft > 0) and (TestCollisionYwithGear(Gear, 1) and lfIce <> 0) then
+ begin
+ slope:= CalcSlopeBelowGear(Gear);
+ if slope.QWordValue > 730144440 then // ignore mild slopes
+ begin
+ Gear^.dX:=Gear^.dX+slope*cGravity*_256;
+ Gear^.State:= Gear^.State or gstMoving
+ end
+ end;
(*
x:= hwRound(Gear^.X);
y:= hwRound(Gear^.Y);
@@ -1252,7 +1251,39 @@
AddVisualGear(x + hwRound(_40 * slope), y - hwRound(_40 * slope), vgtSmokeTrace);
AddVisualGear(x - hwRound(_50 * slope), y + hwRound(_50 * slope), vgtSmokeTrace);
AddVisualGear(x + hwRound(_50 * slope), y - hwRound(_50 * slope), vgtSmokeTrace); *)
- end
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepHedgehog(Gear: PGear);
+begin
+CheckSum:= CheckSum xor Gear^.Hedgehog^.BotLevel;
+if (Gear^.Message and gmDestroy) <> 0 then
+ begin
+ DeleteGear(Gear);
+ exit
+ end;
+if GameTicks mod 100 = 0 then CheckIce(Gear);
+(*
+if Gear^.Hedgehog^.Effects[heFrozen] > 0 then
+ begin
+ if (Gear^.Hedgehog^.Effects[heFrozen] > 256) and (CurrentHedgehog^.Team^.Clan <> Gear^.Hedgehog^.Team^.Clan) then
+ dec(Gear^.Hedgehog^.Effects[heFrozen])
+ else if GameTicks mod 10 = 0 then
+ dec(Gear^.Hedgehog^.Effects[heFrozen])
+ end;
+*)
+if (GameTicks mod 10 = 0) and (Gear^.Hedgehog^.Effects[heFrozen] > 0) and (Gear^.Hedgehog^.Effects[heFrozen] < 256) then
+ dec(Gear^.Hedgehog^.Effects[heFrozen]);
+if (Gear^.State and gstHHDriven) = 0 then
+ doStepHedgehogFree(Gear)
+else
+ begin
+ with Gear^.Hedgehog^ do
+ if Team^.hasGone then
+ TeamGoneEffect(Team^)
+ else
+ doStepHedgehogDriven(Gear)
+ end;
end;
end.
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uGearsList.pas
--- a/hedgewars/uGearsList.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uGearsList.pas Tue Apr 02 21:00:57 2013 +0200
@@ -187,7 +187,7 @@
begin
gear^.Hedgehog:= CurrentHedgehog;
if (CurrentHedgehog^.Gear <> nil) and (hwRound(CurrentHedgehog^.Gear^.X) = X) and (hwRound(CurrentHedgehog^.Gear^.Y) = Y) then
- gear^.CollisionMask:= $FF7F
+ gear^.CollisionMask:= lfNotCurrentMask
end;
if (Ammoz[Gear^.AmmoType].Ammo.Propz and ammoprop_NeedTarget <> 0) then
@@ -329,7 +329,7 @@
end;
gtKnife: begin
gear^.Density:= _4;
- gear^.Radius:= 16
+ gear^.Radius:= 7
end;
gtCase: begin
gear^.ImpactSound:= sndGraveImpact;
@@ -550,7 +550,10 @@
gear^.Pos:= 1;
end;
}
- gtIceGun: gear^.Health:= 1000;
+ gtIceGun: begin
+ gear^.Health:= 1000;
+ gear^.Radius:= 8;
+ end;
gtGenericFaller:begin
gear^.AdvBounce:= 1;
gear^.Radius:= 1;
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uGearsRender.pas
--- a/hedgewars/uGearsRender.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uGearsRender.pas Tue Apr 02 21:00:57 2013 +0200
@@ -37,7 +37,17 @@
end;
procedure RenderGear(Gear: PGear; x, y: LongInt);
-var RopePoints: TRopePoints;
+var RopePoints: record
+ Count: Longword;
+ HookAngle: GLfloat;
+ ar: array[0..MAXROPEPOINTS] of record
+ X, Y: hwFloat;
+ dLen: hwFloat;
+ b: boolean;
+ sx, sy, sb: boolean;
+ end;
+ rounded: array[0..MAXROPEPOINTS + 2] of TVertex2f;
+ end;
implementation
uses uRender, uUtils, uVariables, uAmmos, Math, uVisualGears;
@@ -215,6 +225,8 @@
defaultPos, HatVisible: boolean;
HH: PHedgehog;
CurWeapon: PAmmo;
+ iceOffset:Longint;
+ r:TSDL_Rect;
begin
HH:= Gear^.Hedgehog;
if HH^.Unplaced then
@@ -243,6 +255,30 @@
defaultPos:= true;
HatVisible:= false;
+ if HH^.Effects[heFrozen] > 0 then
+ if HH^.Effects[heFrozen] < 150000 then
+ begin
+ DrawHedgehog(sx, sy,
+ sign,
+ 0,
+ 0,
+ 0);
+ defaultPos:= false;
+ if HH^.Effects[heFrozen] < 256 then
+ HatVisible:= true
+ else HatVisible:= false
+ end
+ else
+ begin
+ DrawHedgehog(sx, sy,
+ sign,
+ 2,
+ 4,
+ 0);
+ defaultPos:= false;
+ HatVisible:= false
+ end;
+
if HH^.Effects[hePoisoned] <> 0 then
begin
@@ -251,6 +287,7 @@
Tint($FF, $FF, $FF, $FF)
end;
+
if ((Gear^.State and gstWinner) <> 0) and
((CurAmmoGear = nil) or (CurAmmoGear^.Kind <> gtPickHammer)) then
begin
@@ -542,7 +579,7 @@
DrawTextureCentered(sx, sy - 40, CurAmmoGear^.Tex)
end;
gtIceGun:
- begin DrawSpriteRotated(sprHandBallgun, hx, hy, sign, aangle);
+ begin DrawSpriteRotated(sprIceGun, hx, hy, sign, aangle);
if CurAmmoGear^.Tex <> nil then
DrawTextureCentered(sx, sy - 40, CurAmmoGear^.Tex)
end;
@@ -673,7 +710,7 @@
amBee: DrawSpriteRotatedF(sprHandBee, hx, hy, (RealTicks div 125) mod 4, sign, aangle);
amFlamethrower: DrawSpriteRotatedF(sprHandFlamethrower, hx, hy, (RealTicks div 125) mod 4, sign, aangle);
amLandGun: DrawSpriteRotated(sprHandBallgun, hx, hy, sign, aangle);
- amIceGun: DrawSpriteRotated(sprHandBallgun, hx, hy, sign, aangle);
+ amIceGun: DrawSpriteRotated(sprIceGun, hx, hy, sign, aangle);
amResurrector: DrawCircle(ox, oy, 98, 4, $F5, $DB, $35, $AA); // I'd rather not like to hardcode 100 here
end;
@@ -736,7 +773,7 @@
end else // not gstHHDriven
begin
- if (Gear^.Damage > 0)
+ if (Gear^.Damage > 0) and (HH^.Effects[heFrozen] = 0)
and (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) > _0_003) then
begin
DrawHedgehog(sx, sy,
@@ -921,6 +958,28 @@
Tint($FF, $FF, $FF, max($40, round($FF * abs(1 - ((RealTicks div 2 + Gear^.uid * 491) mod 1500) / 750))));
DrawSprite(sprInvulnerable, sx - 24, sy - 24, 0);
end;
+
+ if HH^.Effects[heFrozen] < 150000 then
+ begin
+ if HH^.Effects[heFrozen] < 150000 then
+ Tint($FF, $FF, $FF, min(255,127+HH^.Effects[heFrozen] div 800));
+
+ iceOffset:= min(32, HH^.Effects[heFrozen] div 8);
+ r.x := 128;
+ r.y := 96 - iceOffset;
+ r.w := 32;
+ r.h := iceOffset;
+ if sign = -1 then
+ DrawTextureFromRectDir(sx + sign*2, sy+16-iceoffset, r.w, r.h, @r, HHTexture, sign)
+ else
+ DrawTextureFromRectDir(sx-16 + sign*2, sy+16-iceoffset, r.w, r.h, @r, HHTexture, sign);
+
+
+ if HH^.Effects[heFrozen] < 150000 then
+ Tint($FF, $FF, $FF, $FF);
+ end;
+
+
if cVampiric and
(CurrentHedgehog^.Gear <> nil) and
(CurrentHedgehog^.Gear = Gear) then
@@ -1232,8 +1291,13 @@
begin
i:= random(100)+100;
if Gear^.Target.X <> NoPointX then
- DrawLine(Gear^.Target.X, Gear^.Target.Y, hwRound(HHGear^.X), hwRound(HHGear^.Y), 4.0, i, i, $FF, $40)
- else DrawLine(hwRound(HHGear^.X), hwRound(HHGear^.Y), hwRound(Gear^.X), hwRound(Gear^.Y), 4.0, i, i, $FF, $40);
+ begin
+ DrawLine(Gear^.Target.X, Gear^.Target.Y, hwRound(HHGear^.X), hwRound(HHGear^.Y), 4.0, i, i, $FF, $40);
+ end
+ else
+ begin
+ DrawLine(hwRound(HHGear^.X), hwRound(HHGear^.Y), hwRound(Gear^.X), hwRound(Gear^.Y), 4.0, i, i, $FF, $40);
+ end;
end
end
end;
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uGearsUtils.pas
--- a/hedgewars/uGearsUtils.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uGearsUtils.pas Tue Apr 02 21:00:57 2013 +0200
@@ -137,7 +137,7 @@
Gear^.Active:= true;
if Gear^.Kind <> gtFlame then FollowGear:= Gear
end;
- if ((Mask and EXPLPoisoned) <> 0) and (Gear^.Kind = gtHedgehog) and (not Gear^.Invulnerable) then
+ if ((Mask and EXPLPoisoned) <> 0) and (Gear^.Kind = gtHedgehog) and (not Gear^.Invulnerable) and ((Gear^.State and gstHHDeath) = 0) then
Gear^.Hedgehog^.Effects[hePoisoned] := 1;
end;
@@ -182,7 +182,7 @@
i:= _1;
if (CurrentHedgehog <> nil) and CurrentHedgehog^.King then
i:= _1_5;
-if (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.King) then
+if (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.King or (Gear^.Hedgehog^.Effects[heFrozen] > 0)) then
ModifyDamage:= hwRound(_0_01 * cDamageModifier * dmg * i * cDamagePercent * _0_5)
else
ModifyDamage:= hwRound(_0_01 * cDamageModifier * dmg * i * cDamagePercent)
@@ -580,16 +580,16 @@
repeat
inc(y, 2);
until (y >= cWaterLine) or
- ((not ignoreOverlap) and (CountNonZeroz(x, y, Gear^.Radius - 1, 1, $FFFF) = 0)) or
- (ignoreOverlap and (CountNonZeroz(x, y, Gear^.Radius - 1, 1, $FF00) = 0));
+ ((not ignoreOverlap) and (CountNonZeroz(x, y, Gear^.Radius - 1, 1, $FFFF) = 0)) or
+ (ignoreOverlap and (CountNonZeroz(x, y, Gear^.Radius - 1, 1, lfLandMask) = 0));
sy:= y;
repeat
inc(y);
until (y >= cWaterLine) or
- ((not ignoreOverlap) and (CountNonZeroz(x, y, Gear^.Radius - 1, 1, $FFFF) <> 0)) or
- (ignoreOverlap and (CountNonZeroz(x, y, Gear^.Radius - 1, 1, $FF00) <> 0));
+ ((not ignoreOverlap) and (CountNonZeroz(x, y, Gear^.Radius - 1, 1, $FFFF) <> 0)) or
+ (ignoreOverlap and (CountNonZeroz(x, y, Gear^.Radius - 1, 1, lfLandMask) <> 0));
if (y - sy > Gear^.Radius * 2)
and (((Gear^.Kind = gtExplosives)
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uIO.pas
--- a/hedgewars/uIO.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uIO.pas Tue Apr 02 21:00:57 2013 +0200
@@ -30,7 +30,7 @@
procedure SendIPCXY(cmd: char; X, Y: LongInt);
procedure SendIPCRaw(p: pointer; len: Longword);
procedure SendIPCAndWaitReply(s: shortstring);
-procedure SendKeepAliveMessage(Lag: Longword);
+procedure FlushMessages(Lag: Longword);
procedure LoadRecordFromFile(fileName: shortstring);
procedure SendStat(sit: TStatInfoType; s: shortstring);
procedure IPCWaitPongEvent;
@@ -43,6 +43,7 @@
const
cSendEmptyPacketTime = 1000;
+ cSendBufferSize = 1024;
type PCmd = ^TCmd;
TCmd = packed record
@@ -63,7 +64,11 @@
headcmd: PCmd;
lastcmd: PCmd;
- SendEmptyPacketTicks: LongWord;
+ flushDelayTicks: LongWord;
+ sendBuffer: record
+ buf: array[0..Pred(cSendBufferSize)] of byte;
+ count: Word;
+ end;
function AddCmd(Time: Word; str: shortstring): PCmd;
var command: PCmd;
@@ -140,7 +145,7 @@
else
loTicks:= SDLNet_Read16(@s[byte(s[0]) - 1]);
AddCmd(loTicks, s);
- AddFileLog('[IPC in] '+s[1]+' ticks '+IntToStr(lastcmd^.loTime));
+ AddFileLog('[IPC in] ' + sanitizeCharForLog(s[1]) + ' ticks ' + IntToStr(lastcmd^.loTime));
end
end;
@@ -215,20 +220,45 @@
SendIPCRaw(@buf[0], length(buf) + 1)
end;
+function isSyncedCommand(c: char): boolean;
+begin
+ isSyncedCommand:= (c in ['+', '#', 'L', 'l', 'R', 'r', 'U', 'u', 'D', 'd', 'Z', 'z', 'A', 'a', 'S', 'j', 'J', ',', 'c', 'N', 'p', 'P', 'w', 't', '1', '2', '3', '4', '5']) or ((c >= #128) and (c <= char(128 + cMaxSlotIndex)))
+end;
+
+procedure flushBuffer();
+begin
+ if IPCSock <> nil then
+ begin
+ SDLNet_TCP_Send(IPCSock, @sendBuffer.buf, sendBuffer.count);
+ flushDelayTicks:= 0;
+ sendBuffer.count:= 0
+ end
+end;
procedure SendIPC(s: shortstring);
begin
if IPCSock <> nil then
begin
- SendEmptyPacketTicks:= 0;
- if s[0]>#251 then
+ if s[0] > #251 then
s[0]:= #251;
SDLNet_Write16(GameTicks, @s[Succ(byte(s[0]))]);
- AddFileLog('[IPC out] '+ s[1]);
+
+ AddFileLog('[IPC out] '+ sanitizeCharForLog(s[1]));
inc(s[0], 2);
- SDLNet_TCP_Send(IPCSock, @s, Succ(byte(s[0])));
- //log('SendIPC');
+
+ if isSyncedCommand(s[1]) then
+ begin
+ if sendBuffer.count + byte(s[0]) >= cSendBufferSize then
+ flushBuffer();
+
+ Move(s, sendBuffer.buf[sendBuffer.count], byte(s[0]) + 1);
+ inc(sendBuffer.count, byte(s[0]) + 1);
+
+ if (s[1] = 'N') or (s[1] = '#') then
+ flushBuffer();
+ end else
+ SDLNet_TCP_Send(IPCSock, @s, Succ(byte(s[0])))
end
end;
@@ -266,11 +296,16 @@
IPCWaitPongEvent
end;
-procedure SendKeepAliveMessage(Lag: Longword);
+procedure FlushMessages(Lag: Longword);
begin
-inc(SendEmptyPacketTicks, Lag);
-if (SendEmptyPacketTicks >= cSendEmptyPacketTime) then
- SendIPC(_S'+')
+inc(flushDelayTicks, Lag);
+if (flushDelayTicks >= cSendEmptyPacketTime) then
+ begin
+ if sendBuffer.count = 0 then
+ SendIPC(_S'+');
+
+ flushBuffer()
+ end
end;
procedure NetGetNextCmd;
@@ -436,8 +471,8 @@
SocketString:= '';
hiTicks:= 0;
- SendEmptyPacketTicks:= 0;
-
+ flushDelayTicks:= 0;
+ sendBuffer.count:= 0;
end;
procedure freeModule;
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uInputHandler.pas
--- a/hedgewars/uInputHandler.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uInputHandler.pas Tue Apr 02 21:00:57 2013 +0200
@@ -58,7 +58,6 @@
RCTRL = $4000;
var tkbd: array[0..cKbdMaxIndex] of boolean;
- quitKeyCode, closeKeyCode: Byte;
KeyNames: array [0..cKeyMaxIndex] of string[15];
CurrentBinds: TBinds;
ControllerNumControllers: Integer;
@@ -138,7 +137,7 @@
and (CurrentHedgehog^.BotLevel = 0);
// ctrl/cmd + q to close engine and frontend
-if(KeyDown and (code = quitKeyCode)) then
+if(KeyDown and (code = SDLK_q)) then
begin
{$IFDEF DARWIN}
if tkbd[KeyNameToCode('left_meta')] or tkbd[KeyNameToCode('right_meta')] then
@@ -149,7 +148,7 @@
end;
// ctrl/cmd + w to close engine
-if(KeyDown and (code = closeKeyCode)) then
+if(KeyDown and (code = SDLK_w)) then
begin
{$IFDEF DARWIN}
// on OS X it this is expected behaviour
@@ -159,7 +158,7 @@
if tkbd[KeyNameToCode('left_ctrl')] or tkbd[KeyNameToCode('right_ctrl')] then
if ((CurrentBinds[KeyNameToCode('left_ctrl')] = '') or
(CurrentBinds[KeyNameToCode('right_ctrl')] = '')) and
- (CurrentBinds[closeKeyCode] = '') then
+ (CurrentBinds[SDLK_w] = '') then
{$ENDIF}
ParseCommand('forcequit', true);
end;
@@ -242,8 +241,6 @@
end;
end;
-quitKeyCode:= KeyNameToCode(_S'q');
-closeKeyCode:= KeyNameToCode(_S'w');
// get the size of keyboard array
SDL_GetKeyState(@k);
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uLandGraphics.pas
--- a/hedgewars/uLandGraphics.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uLandGraphics.pas Tue Apr 02 21:00:57 2013 +0200
@@ -22,10 +22,14 @@
interface
uses uFloat, uConsts, uTypes;
+type
+ fillType = (nullPixel, backgroundPixel, ebcPixel, icePixel, setNotCurrentMask, changePixelSetNotCurrent, setCurrentHog, changePixelNotSetNotCurrent);
+
type TRangeArray = array[0..31] of record
Left, Right: LongInt;
end;
PRangeArray = ^TRangeArray;
+TLandCircleProcedure = procedure (landX, landY, pixelX, pixelY: Longint);
function addBgColor(OldColor, NewColor: LongWord): LongWord;
function SweepDirty: boolean;
@@ -36,17 +40,230 @@
procedure DrawHLinesExplosions(ar: PRangeArray; Radius: LongInt; y, dY: LongInt; Count: Byte);
procedure DrawTunnel(X, Y, dX, dY: hwFloat; ticks, HalfWidth: LongInt);
procedure FillRoundInLand(X, Y, Radius: LongInt; Value: Longword);
+function FillRoundInLand(X, Y, Radius: LongInt; fill: fillType): LongWord;
procedure ChangeRoundInLand(X, Y, Radius: LongInt; doSet, isCurrent: boolean);
function LandBackPixel(x, y: LongInt): LongWord;
procedure DrawLine(X1, Y1, X2, Y2: LongInt; Color: Longword);
procedure DrawThickLine(X1, Y1, X2, Y2, radius: LongInt; color: Longword);
procedure DumpLandToLog(x, y, r: LongInt);
-
+procedure DrawIceBreak(x, y, iceRadius, iceHeight: Longint);
function TryPlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace: boolean; indestructible: boolean): boolean;
implementation
uses SDLh, uLandTexture, uVariables, uUtils, uDebug;
+
+procedure calculatePixelsCoordinates(landX, landY: Longint; var pixelX, pixelY: Longint); inline;
+begin
+if (cReducedQuality and rqBlurryLand) = 0 then
+ begin
+ pixelX := landX;
+ pixelY := landY;
+ end
+else
+ begin
+ pixelX := LandX div 2;
+ pixelY := LandY div 2;
+ end;
+end;
+
+function drawPixelBG(landX, landY, pixelX, pixelY: Longint): Longword; inline;
+begin
+drawPixelBG := 0;
+if (Land[LandY, landX] and lfIndestructible) = 0 then
+ begin
+ if ((Land[landY, landX] and lfBasic) <> 0) and (((LandPixels[pixelY, pixelX] and AMask) shr AShift) = 255) and (not disableLandBack) then
+ begin
+ LandPixels[pixelY, pixelX]:= LandBackPixel(landX, landY);
+ inc(drawPixelBG);
+ end
+ else if ((Land[landY, landX] and lfObject) <> 0) or (((LandPixels[pixelY, pixelX] and AMask) shr AShift) < 255) then
+ LandPixels[pixelY, pixelX]:= 0
+ end;
+end;
+
+procedure drawPixelEBC(landX, landY, pixelX, pixelY: Longint); inline;
+begin
+if ((Land[landY, landX] and lfBasic) <> 0) or ((Land[landY, landX] and lfObject) <> 0) then
+ begin
+ LandPixels[pixelY, pixelX]:= ExplosionBorderColor;
+ Land[landY, landX]:= (Land[landY, landX] or lfDamaged) and not lfIce;
+ LandDirty[landY div 32, landX div 32]:= 1;
+ end;
+end;
+
+function isLandscapeEdge(weight:Longint):boolean; inline;
+begin
+result := (weight < 8) and (weight >= 2);
+end;
+
+function getPixelWeight(x, y:Longint): Longint;
+var
+ i, j:Longint;
+begin
+result := 0;
+for i := x - 1 to x + 1 do
+ for j := y - 1 to y + 1 do
+ begin
+ if (i < 0) or
+ (i > LAND_WIDTH - 1) or
+ (j < 0) or
+ (j > LAND_HEIGHT -1) then
+ begin
+ result := 9;
+ exit;
+ end;
+ if Land[j, i] and lfLandMask and not lfIce = 0 then
+ result := result + 1;
+ end;
+end;
+
+
+procedure fillPixelFromIceSprite(pixelX, pixelY:Longint); inline;
+var
+ iceSurface: PSDL_Surface;
+ icePixels: PLongwordArray;
+ w: LongWord;
+begin
+ // So. 3 parameters here. Ice colour, Ice opacity, and a bias on the greyscaled pixel towards lightness
+ iceSurface:= SpritesData[sprIceTexture].Surface;
+ icePixels := iceSurface^.pixels;
+ w:= LandPixels[pixelY, pixelX];
+ if w > 0 then
+ begin
+ w:= round(((w shr RShift and $FF) * RGB_LUMINANCE_RED +
+ (w shr BShift and $FF) * RGB_LUMINANCE_GREEN +
+ (w shr GShift and $FF) * RGB_LUMINANCE_BLUE));
+ if w < 128 then w:= w+128;
+ if w > 255 then w:= 255;
+ w:= (w shl RShift) or (w shl BShift) or (w shl GShift) or (LandPixels[pixelY, pixelX] and AMask);
+ LandPixels[pixelY, pixelX]:= addBgColor(w, IceColor);
+ LandPixels[pixelY, pixelX]:= addBgColor(LandPixels[pixelY, pixelX], icePixels^[iceSurface^.w * (pixelY mod iceSurface^.h) + (pixelX mod iceSurface^.w)])
+ end
+ else
+ begin
+ LandPixels[pixelY, pixelX]:= IceColor and not AMask or $E8 shl AShift;
+ LandPixels[pixelY, pixelX]:= addBgColor(LandPixels[pixelY, pixelX], icePixels^[iceSurface^.w * (pixelY mod iceSurface^.h) + (pixelX mod iceSurface^.w)]);
+ // silly workaround to avoid having to make background erasure a tadb it smarter about sea ice
+ if LandPixels[pixelY, pixelX] and AMask shr AShift = 255 then
+ LandPixels[pixelY, pixelX]:= LandPixels[pixelY, pixelX] and not AMask or 254 shl AShift;
+ end;
+end;
+
+
+procedure DrawPixelIce(landX, landY, pixelX, pixelY: Longint); inline;
+begin
+if ((Land[landY, landX] and lfIce) <> 0) then exit;
+if isLandscapeEdge(getPixelWeight(landX, landY)) then
+ begin
+ if (LandPixels[pixelY, pixelX] and AMask < 255) and (LandPixels[pixelY, pixelX] and AMask > 0) then
+ LandPixels[pixelY, pixelX] := (IceEdgeColor and not AMask) or (LandPixels[pixelY, pixelX] and AMask)
+ else if (LandPixels[pixelY, pixelX] and AMask < 255) or (Land[landY, landX] > 255) then
+ LandPixels[pixelY, pixelX] := IceEdgeColor
+ end
+else if Land[landY, landX] > 255 then
+ begin
+ fillPixelFromIceSprite(pixelX, pixelY);
+ end;
+if Land[landY, landX] > 255 then Land[landY, landX] := Land[landY, landX] or lfIce and not lfDamaged;
+end;
+
+
+function FillLandCircleLine(y, fromPix, toPix: LongInt; fill : fillType): Longword;
+var px, py, i: LongInt;
+begin
+//get rid of compiler warning
+ px := 0;
+ py := 0;
+ FillLandCircleLine := 0;
+ case fill of
+ backgroundPixel:
+ for i:= fromPix to toPix do
+ begin
+ calculatePixelsCoordinates(i, y, px, py);
+ inc(FillLandCircleLine, drawPixelBG(i, y, px, py));
+ end;
+ ebcPixel:
+ for i:= fromPix to toPix do
+ begin
+ calculatePixelsCoordinates(i, y, px, py);
+ drawPixelEBC(i, y, px, py);
+ end;
+ nullPixel:
+ for i:= fromPix to toPix do
+ begin
+ calculatePixelsCoordinates(i, y, px, py);
+ if ((Land[y, i] and lfIndestructible) = 0) and (not disableLandBack or (Land[y, i] > 255)) then
+ LandPixels[py, px]:= 0
+ end;
+ icePixel:
+ for i:= fromPix to toPix do
+ begin
+ calculatePixelsCoordinates(i, y, px, py);
+ DrawPixelIce(i, y, px, py);
+ end;
+ setNotCurrentMask:
+ for i:= fromPix to toPix do
+ begin
+ Land[y, i]:= Land[y, i] and lfNotCurrentMask;
+ end;
+ changePixelSetNotCurrent:
+ for i:= fromPix to toPix do
+ begin
+ if Land[y, i] and lfObjMask > 0 then
+ Land[y, i]:= (Land[y, i] and lfNotObjMask) or ((Land[y, i] and lfObjMask) - 1);
+ end;
+ setCurrentHog:
+ for i:= fromPix to toPix do
+ begin
+ Land[y, i]:= Land[y, i] or lfCurrentHog
+ end;
+ changePixelNotSetNotCurrent:
+ for i:= fromPix to toPix do
+ begin
+ if Land[y, i] and lfObjMask < lfObjMask then
+ Land[y, i]:= (Land[y, i] and lfNotObjMask) or ((Land[y, i] and lfObjMask) + 1)
+ end;
+ end;
+end;
+
+function FillLandCircleSegment(x, y, dx, dy: LongInt; fill : fillType): Longword; inline;
+begin
+ FillLandCircleSegment := 0;
+if ((y + dy) and LAND_HEIGHT_MASK) = 0 then
+ inc(FillLandCircleSegment, FillLandCircleLine(y + dy, Max(x - dx, 0), Min(x + dx, LAND_WIDTH - 1), fill));
+if ((y - dy) and LAND_HEIGHT_MASK) = 0 then
+ inc(FillLandCircleSegment, FillLandCircleLine(y - dy, Max(x - dx, 0), Min(x + dx, LAND_WIDTH - 1), fill));
+if ((y + dx) and LAND_HEIGHT_MASK) = 0 then
+ inc(FillLandCircleSegment, FillLandCircleLine(y + dx, Max(x - dy, 0), Min(x + dy, LAND_WIDTH - 1), fill));
+if ((y - dx) and LAND_HEIGHT_MASK) = 0 then
+ inc(FillLandCircleSegment, FillLandCircleLine(y - dx, Max(x - dy, 0), Min(x + dy, LAND_WIDTH - 1), fill));
+end;
+
+function FillRoundInLand(X, Y, Radius: LongInt; fill: fillType): Longword; inline;
+var dx, dy, d: LongInt;
+begin
+dx:= 0;
+dy:= Radius;
+d:= 3 - 2 * Radius;
+FillRoundInLand := 0;
+while (dx < dy) do
+ begin
+ inc(FillRoundInLand, FillLandCircleSegment(x, y, dx, dy, fill));
+ if (d < 0) then
+ d:= d + 4 * dx + 6
+ else
+ begin
+ d:= d + 4 * (dx - dy) + 10;
+ dec(dy)
+ end;
+ inc(dx)
+ end;
+if (dx = dy) then
+ inc (FillRoundInLand, FillLandCircleSegment(x, y, dx, dy, fill));
+end;
+
+
function addBgColor(OldColor, NewColor: LongWord): LongWord;
// Factor ranges from 0 to 100% NewColor
var
@@ -99,65 +316,6 @@
Land[y - dx, i]:= Value;
end;
-procedure ChangeCircleLines(x, y, dx, dy: LongInt; doSet, isCurrent: boolean);
-var i: LongInt;
-begin
-if not doSet then
- begin
- if ((y + dy) and LAND_HEIGHT_MASK) = 0 then
- for i:= Max(x - dx, 0) to Min(x + dx, LAND_WIDTH - 1) do
- if isCurrent then
- Land[y + dy, i]:= Land[y + dy, i] and $FF7F
- else if Land[y + dy, i] and $007F > 0 then
- Land[y + dy, i]:= (Land[y + dy, i] and $FF80) or ((Land[y + dy, i] and $7F) - 1);
- if ((y - dy) and LAND_HEIGHT_MASK) = 0 then
- for i:= Max(x - dx, 0) to Min(x + dx, LAND_WIDTH - 1) do
- if isCurrent then
- Land[y - dy, i]:= Land[y - dy, i] and $FF7F
- else if Land[y - dy, i] and $007F > 0 then
- Land[y - dy, i]:= (Land[y - dy, i] and $FF80) or ((Land[y - dy, i] and $7F) - 1);
- if ((y + dx) and LAND_HEIGHT_MASK) = 0 then
- for i:= Max(x - dy, 0) to Min(x + dy, LAND_WIDTH - 1) do
- if isCurrent then
- Land[y + dx, i]:= Land[y + dx, i] and $FF7F
- else if Land[y + dx, i] and $007F > 0 then
- Land[y + dx, i]:= (Land[y + dx, i] and $FF80) or ((Land[y + dx, i] and $7F) - 1);
- if ((y - dx) and LAND_HEIGHT_MASK) = 0 then
- for i:= Max(x - dy, 0) to Min(x + dy, LAND_WIDTH - 1) do
- if isCurrent then
- Land[y - dx, i]:= Land[y - dx, i] and $FF7F
- else if Land[y - dx, i] and $007F > 0 then
- Land[y - dx, i]:= (Land[y - dx, i] and $FF80) or ((Land[y - dx, i] and $7F) - 1)
- end
-else
- begin
- if ((y + dy) and LAND_HEIGHT_MASK) = 0 then
- for i:= Max(x - dx, 0) to Min(x + dx, LAND_WIDTH - 1) do
- if isCurrent then
- Land[y + dy, i]:= Land[y + dy, i] or $80
- else if Land[y + dy, i] and $007F < 127 then
- Land[y + dy, i]:= (Land[y + dy, i] and $FF80) or ((Land[y + dy, i] and $7F) + 1);
- if ((y - dy) and LAND_HEIGHT_MASK) = 0 then
- for i:= Max(x - dx, 0) to Min(x + dx, LAND_WIDTH - 1) do
- if isCurrent then
- Land[y - dy, i]:= Land[y - dy, i] or $80
- else if Land[y - dy, i] and $007F < 127 then
- Land[y - dy, i]:= (Land[y - dy, i] and $FF80) or ((Land[y - dy, i] and $7F) + 1);
- if ((y + dx) and LAND_HEIGHT_MASK) = 0 then
- for i:= Max(x - dy, 0) to Min(x + dy, LAND_WIDTH - 1) do
- if isCurrent then
- Land[y + dx, i]:= Land[y + dx, i] or $80
- else if Land[y + dx, i] and $007F < 127 then
- Land[y + dx, i]:= (Land[y + dx, i] and $FF80) or ((Land[y + dx, i] and $7F) + 1);
- if ((y - dx) and LAND_HEIGHT_MASK) = 0 then
- for i:= Max(x - dy, 0) to Min(x + dy, LAND_WIDTH - 1) do
- if isCurrent then
- Land[y - dx, i]:= Land[y - dx, i] or $80
- else if Land[y - dx, i] and $007F < 127 then
- Land[y - dx, i]:= (Land[y - dx, i] and $FF80) or ((Land[y - dx, i] and $7F) + 1)
- end
-end;
-
procedure FillRoundInLand(X, Y, Radius: LongInt; Value: Longword);
var dx, dy, d: LongInt;
begin
@@ -181,307 +339,54 @@
end;
procedure ChangeRoundInLand(X, Y, Radius: LongInt; doSet, isCurrent: boolean);
-var dx, dy, d: LongInt;
begin
-dx:= 0;
-dy:= Radius;
-d:= 3 - 2 * Radius;
-while (dx < dy) do
- begin
- ChangeCircleLines(x, y, dx, dy, doSet, isCurrent);
- if (d < 0) then
- d:= d + 4 * dx + 6
- else
- begin
- d:= d + 4 * (dx - dy) + 10;
- dec(dy)
- end;
- inc(dx)
- end;
-if (dx = dy) then
- ChangeCircleLines(x, y, dx, dy, doSet, isCurrent)
-end;
-
-procedure FillLandCircleLines0(x, y, dx, dy: LongInt);
-var i, t: LongInt;
-begin
-t:= y + dy;
-if (t and LAND_HEIGHT_MASK) = 0 then
- for i:= Max(x - dx, 0) to Min(x + dx, LAND_WIDTH - 1) do
- if ((Land[t, i] and lfIndestructible) = 0) and ((not disableLandBack) or (Land[t, i] > 255)) then
- if (cReducedQuality and rqBlurryLand) = 0 then
- LandPixels[t, i]:= 0
- else
- LandPixels[t div 2, i div 2]:= 0;
-
-t:= y - dy;
-if (t and LAND_HEIGHT_MASK) = 0 then
- for i:= Max(x - dx, 0) to Min(x + dx, LAND_WIDTH - 1) do
- if ((Land[t, i] and lfIndestructible) = 0) and ((not disableLandBack) or (Land[t, i] > 255)) then
- if (cReducedQuality and rqBlurryLand) = 0 then
- LandPixels[t, i]:= 0
- else
- LandPixels[t div 2, i div 2]:= 0;
-
-t:= y + dx;
-if (t and LAND_HEIGHT_MASK) = 0 then
- for i:= Max(x - dy, 0) to Min(x + dy, LAND_WIDTH - 1) do
- if ((Land[t, i] and lfIndestructible) = 0) and ((not disableLandBack) or (Land[t, i] > 255)) then
- if (cReducedQuality and rqBlurryLand) = 0 then
- LandPixels[t, i]:= 0
- else
- LandPixels[t div 2, i div 2]:= 0;
-
-t:= y - dx;
-if (t and LAND_HEIGHT_MASK) = 0 then
- for i:= Max(x - dy, 0) to Min(x + dy, LAND_WIDTH - 1) do
- if ((Land[t, i] and lfIndestructible) = 0) and ((not disableLandBack) or (Land[t, i] > 255)) then
- if (cReducedQuality and rqBlurryLand) = 0 then
- LandPixels[t, i]:= 0
- else
- LandPixels[t div 2, i div 2]:= 0;
-
+if not doSet and isCurrent then
+ FillRoundInLand(X, Y, Radius, setNotCurrentMask)
+else if not doSet and not IsCurrent then
+ FillRoundInLand(X, Y, Radius, changePixelSetNotCurrent)
+else if doSet and IsCurrent then
+ FillRoundInLand(X, Y, Radius, setCurrentHog)
+else if doSet and not IsCurrent then
+ FillRoundInLand(X, Y, Radius, changePixelNotSetNotCurrent);
end;
-function FillLandCircleLinesBG(x, y, dx, dy: LongInt): Longword;
-var i, t, by, bx: LongInt;
- cnt: Longword;
+procedure DrawIceBreak(x, y, iceRadius, iceHeight: Longint);
+var
+ i, j: integer;
+ landRect: TSDL_Rect;
begin
-cnt:= 0;
-t:= y + dy;
-if (t and LAND_HEIGHT_MASK) = 0 then
- for i:= Max(x - dx, 0) to Min(x + dx, LAND_WIDTH - 1) do
- if (Land[t, i] and lfIndestructible) = 0 then
- begin
- if (cReducedQuality and rqBlurryLand) = 0 then
- begin
- by:= t; bx:= i;
- end
- else
- begin
- by:= t div 2; bx:= i div 2;
- end;
- if ((Land[t, i] and lfBasic) <> 0) and (((LandPixels[by,bx] and AMask) shr AShift) = 255) and (not disableLandBack) then
- begin
- inc(cnt);
- LandPixels[by, bx]:= LandBackPixel(i, t)
- end
- else if ((Land[t, i] and lfObject) <> 0) or (((LandPixels[by,bx] and AMask) shr AShift) < 255) then
- LandPixels[by, bx]:= 0
- end;
-
-t:= y - dy;
-if (t and LAND_HEIGHT_MASK) = 0 then
- for i:= Max(x - dx, 0) to Min(x + dx, LAND_WIDTH - 1) do
- if (Land[t, i] and lfIndestructible) = 0 then
- begin
- if (cReducedQuality and rqBlurryLand) = 0 then
- begin
- by:= t; bx:= i;
- end
- else
- begin
- by:= t div 2; bx:= i div 2;
- end;
- if ((Land[t, i] and lfBasic) <> 0) and (((LandPixels[by,bx] and AMask) shr AShift) = 255) and (not disableLandBack) then
- begin
- inc(cnt);
- LandPixels[by, bx]:= LandBackPixel(i, t)
- end
- else if ((Land[t, i] and lfObject) <> 0) or (((LandPixels[by,bx] and AMask) shr AShift) < 255) then
- LandPixels[by, bx]:= 0
- end;
-
-t:= y + dx;
-if (t and LAND_HEIGHT_MASK) = 0 then
- for i:= Max(x - dy, 0) to Min(x + dy, LAND_WIDTH - 1) do
- if (Land[t, i] and lfIndestructible) = 0 then
- begin
- if (cReducedQuality and rqBlurryLand) = 0 then
- begin
- by:= t; bx:= i;
- end
- else
- begin
- by:= t div 2; bx:= i div 2;
- end;
- if ((Land[t, i] and lfBasic) <> 0) and (((LandPixels[by,bx] and AMask) shr AShift) = 255) and (not disableLandBack) then
- begin
- inc(cnt);
- LandPixels[by, bx]:= LandBackPixel(i, t)
- end
- else if ((Land[t, i] and lfObject) <> 0) or (((LandPixels[by,bx] and AMask) shr AShift) < 255) then
- LandPixels[by, bx]:= 0
- end;
-t:= y - dx;
-if (t and LAND_HEIGHT_MASK) = 0 then
- for i:= Max(x - dy, 0) to Min(x + dy, LAND_WIDTH - 1) do
- if (Land[t, i] and lfIndestructible) = 0 then
+for i := min(max(x - iceRadius, 0), LAND_WIDTH - 1) to min(max(x + iceRadius, 0), LAND_WIDTH - 1) do
+ begin
+ for j := min(max(y, 0), LAND_HEIGHT - 1) to min(max(y + iceHeight, 0), LAND_HEIGHT - 1) do
+ begin
+ if Land[j, i] = 0 then
begin
- if (cReducedQuality and rqBlurryLand) = 0 then
- begin
- by:= t; bx:= i;
- end
- else
- begin
- by:= t div 2; bx:= i div 2;
- end;
- if ((Land[t, i] and lfBasic) <> 0) and (((LandPixels[by,bx] and AMask) shr AShift) = 255) and (not disableLandBack) then
- begin
- inc(cnt);
- LandPixels[by, bx]:= LandBackPixel(i, t)
- end
- else if ((Land[t, i] and lfObject) <> 0) or (((LandPixels[by,bx] and AMask) shr AShift) < 255) then
- LandPixels[by, bx]:= 0
- end;
-FillLandCircleLinesBG:= cnt;
-end;
-
-procedure FillLandCircleLinesEBC(x, y, dx, dy: LongInt);
-var i, t: LongInt;
-begin
-t:= y + dy;
-if (t and LAND_HEIGHT_MASK) = 0 then
- for i:= Max(x - dx, 0) to Min(x + dx, LAND_WIDTH - 1) do
- if ((Land[t, i] and lfBasic) <> 0) or ((Land[t, i] and lfObject) <> 0) then
- begin
- if (cReducedQuality and rqBlurryLand) = 0 then
- LandPixels[t, i]:= ExplosionBorderColor
- else
- LandPixels[t div 2, i div 2]:= ExplosionBorderColor;
-
- Land[t, i]:= Land[t, i] or lfDamaged;
- //Despeckle(i, t);
- LandDirty[t div 32, i div 32]:= 1;
+ Land[j, i] := lfIce;
+ fillPixelFromIceSprite(i, j);
end;
-
-t:= y - dy;
-if (t and LAND_HEIGHT_MASK) = 0 then
- for i:= Max(x - dx, 0) to Min(x + dx, LAND_WIDTH - 1) do
- if ((Land[t, i] and lfBasic) <> 0) or ((Land[t, i] and lfObject) <> 0) then
- begin
- if (cReducedQuality and rqBlurryLand) = 0 then
- LandPixels[t, i]:= ExplosionBorderColor
- else
- LandPixels[t div 2, i div 2]:= ExplosionBorderColor;
- Land[t, i]:= Land[t, i] or lfDamaged;
- //Despeckle(i, t);
- LandDirty[t div 32, i div 32]:= 1;
- end;
-
-t:= y + dx;
-if (t and LAND_HEIGHT_MASK) = 0 then
- for i:= Max(x - dy, 0) to Min(x + dy, LAND_WIDTH - 1) do
- if ((Land[t, i] and lfBasic) <> 0) or ((Land[t, i] and lfObject) <> 0) then
- begin
- if (cReducedQuality and rqBlurryLand) = 0 then
- LandPixels[t, i]:= ExplosionBorderColor
- else
- LandPixels[t div 2, i div 2]:= ExplosionBorderColor;
-
- Land[t, i]:= Land[t, i] or lfDamaged;
- //Despeckle(i, t);
- LandDirty[t div 32, i div 32]:= 1;
- end;
-
-t:= y - dx;
-if (t and LAND_HEIGHT_MASK) = 0 then
- for i:= Max(x - dy, 0) to Min(x + dy, LAND_WIDTH - 1) do
- if ((Land[t, i] and lfBasic) <> 0) or ((Land[t, i] and lfObject) <> 0) then
- begin
- if (cReducedQuality and rqBlurryLand) = 0 then
- LandPixels[t, i]:= ExplosionBorderColor
- else
- LandPixels[t div 2, i div 2]:= ExplosionBorderColor;
-
- Land[t, i]:= Land[t, i] or lfDamaged;
- //Despeckle(i, y - dy);
- LandDirty[t div 32, i div 32]:= 1;
- end;
+ end;
+ end;
+landRect.x := min(max(x - iceRadius, 0), LAND_WIDTH - 1);
+landRect.y := min(max(y, 0), LAND_HEIGHT - 1);
+landRect.w := min(2*iceRadius, LAND_WIDTH - landRect.x - 1);
+landRect.h := min(iceHeight, LAND_HEIGHT - landRect.y - 1);
+UpdateLandTexture(landRect.x, landRect.w, landRect.y, landRect.h, true);
end;
function DrawExplosion(X, Y, Radius: LongInt): Longword;
-var dx, dy, ty, tx, d: LongInt;
- cnt: Longword;
+var
+ tx, ty, dx, dy: Longint;
begin
-
-// draw background land texture
- begin
- cnt:= 0;
- dx:= 0;
- dy:= Radius;
- d:= 3 - 2 * Radius;
-
- while (dx < dy) do
- begin
- inc(cnt, FillLandCircleLinesBG(x, y, dx, dy));
- if (d < 0) then
- d:= d + 4 * dx + 6
- else
- begin
- d:= d + 4 * (dx - dy) + 10;
- dec(dy)
- end;
- inc(dx)
- end;
- if (dx = dy) then
- inc(cnt, FillLandCircleLinesBG(x, y, dx, dy));
- end;
-
-// draw a hole in land
-if Radius > 20 then
- begin
- dx:= 0;
- dy:= Radius - 15;
- d:= 3 - 2 * dy;
-
- while (dx < dy) do
- begin
- FillLandCircleLines0(x, y, dx, dy);
- if (d < 0) then
- d:= d + 4 * dx + 6
- else
- begin
- d:= d + 4 * (dx - dy) + 10;
- dec(dy)
- end;
- inc(dx)
- end;
- if (dx = dy) then
- FillLandCircleLines0(x, y, dx, dy);
- end;
-
- // FillRoundInLand after erasing land pixels to allow Land 0 check for mask.png to function
+ DrawExplosion := FillRoundInLand(x, y, Radius, backgroundPixel);
+ if Radius > 20 then
+ FillRoundInLand(x, y, Radius - 15, nullPixel);
FillRoundInLand(X, Y, Radius, 0);
-
-// draw explosion border
- begin
- inc(Radius, 4);
- dx:= 0;
- dy:= Radius;
- d:= 3 - 2 * Radius;
- while (dx < dy) do
- begin
- FillLandCircleLinesEBC(x, y, dx, dy);
- if (d < 0) then
- d:= d + 4 * dx + 6
- else
- begin
- d:= d + 4 * (dx - dy) + 10;
- dec(dy)
- end;
- inc(dx)
- end;
- if (dx = dy) then
- FillLandCircleLinesEBC(x, y, dx, dy);
- end;
-
-tx:= Max(X - Radius - 1, 0);
-dx:= Min(X + Radius + 1, LAND_WIDTH) - tx;
-ty:= Max(Y - Radius - 1, 0);
-dy:= Min(Y + Radius + 1, LAND_HEIGHT) - ty;
-UpdateLandTexture(tx, dx, ty, dy, false);
-DrawExplosion:= cnt
+ FillRoundInLand(x, y, Radius + 4, ebcPixel);
+ tx:= Max(X - Radius - 5, 0);
+ dx:= Min(X + Radius + 5, LAND_WIDTH) - tx;
+ ty:= Max(Y - Radius - 5, 0);
+ dy:= Min(Y + Radius + 5, LAND_HEIGHT) - ty;
+ UpdateLandTexture(tx, dx, ty, dy, false);
end;
procedure DrawHLinesExplosions(ar: PRangeArray; Radius: LongInt; y, dY: LongInt; Count: Byte);
@@ -525,7 +430,7 @@
else
LandPixels[ty div 2, tx div 2]:= ExplosionBorderColor;
- Land[ty, tx]:= Land[ty, tx] or lfDamaged;
+ Land[ty, tx]:= (Land[ty, tx] or lfDamaged) and not lfIce;
LandDirty[ty div 32, tx div 32]:= 1;
end;
inc(y, dY)
@@ -535,6 +440,33 @@
UpdateLandTexture(0, LAND_WIDTH, 0, LAND_HEIGHT, false)
end;
+
+
+procedure DrawExplosionBorder(X, Y, dx, dy:hwFloat; despeckle : Boolean);
+var
+ t, tx, ty :Longint;
+begin
+for t:= 0 to 7 do
+ begin
+ X:= X + dX;
+ Y:= Y + dY;
+ tx:= hwRound(X);
+ ty:= hwRound(Y);
+ if ((ty and LAND_HEIGHT_MASK) = 0) and ((tx and LAND_WIDTH_MASK) = 0) and (((Land[ty, tx] and lfBasic) <> 0)
+ or ((Land[ty, tx] and lfObject) <> 0)) then
+ begin
+ Land[ty, tx]:= (Land[ty, tx] or lfDamaged) and not lfIce;
+ if despeckle then
+ LandDirty[ty div 32, tx div 32]:= 1;
+ if (cReducedQuality and rqBlurryLand) = 0 then
+ LandPixels[ty, tx]:= ExplosionBorderColor
+ else
+ LandPixels[ty div 2, tx div 2]:= ExplosionBorderColor
+ end
+ end;
+end;
+
+
//
// - (dX, dY) - direction, vector of length = 0.5
//
@@ -567,6 +499,7 @@
and ((tx and LAND_WIDTH_MASK) = 0)
and (((Land[ty, tx] and lfBasic) <> 0) or ((Land[ty, tx] and lfObject) <> 0)) then
begin
+ Land[ty, tx]:= Land[ty, tx] and not lfIce;
if despeckle then
begin
Land[ty, tx]:= Land[ty, tx] or lfDamaged;
@@ -586,24 +519,7 @@
begin
X:= nx - dX8;
Y:= ny - dY8;
- for t:= 0 to 7 do
- begin
- X:= X + dX;
- Y:= Y + dY;
- tx:= hwRound(X);
- ty:= hwRound(Y);
- if ((ty and LAND_HEIGHT_MASK) = 0) and ((tx and LAND_WIDTH_MASK) = 0) and (((Land[ty, tx] and lfBasic) <> 0)
- or ((Land[ty, tx] and lfObject) <> 0)) then
- begin
- Land[ty, tx]:= Land[ty, tx] or lfDamaged;
- if despeckle then
- LandDirty[ty div 32, tx div 32]:= 1;
- if (cReducedQuality and rqBlurryLand) = 0 then
- LandPixels[ty, tx]:= ExplosionBorderColor
- else
- LandPixels[ty div 2, tx div 2]:= ExplosionBorderColor
- end
- end;
+ DrawExplosionBorder(X, Y, dx, dy, despeckle);
X:= nx;
Y:= ny;
for t:= 0 to ticks do
@@ -629,24 +545,7 @@
Land[ty, tx]:= 0;
end
end;
- for t:= 0 to 7 do
- begin
- X:= X + dX;
- Y:= Y + dY;
- tx:= hwRound(X);
- ty:= hwRound(Y);
- if ((ty and LAND_HEIGHT_MASK) = 0) and ((tx and LAND_WIDTH_MASK) = 0) and (((Land[ty, tx] and lfBasic) <> 0)
- or ((Land[ty, tx] and lfObject) <> 0)) then
- begin
- Land[ty, tx]:= Land[ty, tx] or lfDamaged;
- if despeckle then
- LandDirty[ty div 32, tx div 32]:= 1;
- if (cReducedQuality and rqBlurryLand) = 0 then
- LandPixels[ty, tx]:= ExplosionBorderColor
- else
- LandPixels[ty div 2, tx div 2]:= ExplosionBorderColor
- end
- end;
+ DrawExplosionBorder(X, Y, dx, dy, despeckle);
nx:= nx - dY;
ny:= ny + dX;
end;
@@ -664,7 +563,7 @@
if ((ty and LAND_HEIGHT_MASK) = 0) and ((tx and LAND_WIDTH_MASK) = 0) and (((Land[ty, tx] and lfBasic) <> 0)
or ((Land[ty, tx] and lfObject) <> 0)) then
begin
- Land[ty, tx]:= Land[ty, tx] or lfDamaged;
+ Land[ty, tx]:= (Land[ty, tx] or lfDamaged) and not lfIce;
if despeckle then
LandDirty[ty div 32, tx div 32]:= 1;
if (cReducedQuality and rqBlurryLand) = 0 then
@@ -790,7 +689,7 @@
yy:= Y div 2;
end;
- pixelsweep:= ((Land[Y, X] and $FF00) = 0) and (LandPixels[yy, xx] <> 0);
+ pixelsweep:= (Land[Y, X] <= lfAllObjMask) and (LandPixels[yy, xx] <> 0);
if (((Land[Y, X] and lfDamaged) <> 0) and ((Land[Y, X] and lfIndestructible) = 0)) or pixelsweep then
begin
c:= 0;
@@ -891,7 +790,7 @@
end
end
else if ((cReducedQuality and rqBlurryLand) = 0) and (LandPixels[Y, X] and AMask = 255)
-and ((Land[Y, X] and (lfDamaged or lfBasic) = lfBasic) or (Land[Y, X] and (lfDamaged or lfBasic) = lfBasic))
+and (Land[Y, X] and (lfDamaged or lfBasic) = lfBasic)
and (Y > LongInt(topY) + 1) and (Y < LAND_HEIGHT-2) and (X > LongInt(leftX) + 1) and (X < LongInt(rightX) - 1) then
begin
if ((((Land[y, x-1] and lfDamaged) <> 0) and (((Land[y+1,x] and lfDamaged) <> 0)) or ((Land[y-1,x] and lfDamaged) <> 0))
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uLandObjects.pas
--- a/hedgewars/uLandObjects.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uLandObjects.pas Tue Apr 02 21:00:57 2013 +0200
@@ -107,7 +107,7 @@
if LandPixels[(cpY + y) div 2, (cpX + x) div 2] = 0 then
LandPixels[(cpY + y) div 2, (cpX + x) div 2]:= p^[x];
- if ((Land[cpY + y, cpX + x] and $FF00) = 0) and ((p^[x] and AMask) <> 0) then
+ if (Land[cpY + y, cpX + x] <= lfAllObjMask) and ((p^[x] and AMask) <> 0) then
begin
Land[cpY + y, cpX + x]:= lfObject;
Land[cpY + y, cpX + x]:= Land[cpY + y, cpX + x] or extraFlags
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uPhysFSLayer.pas
--- a/hedgewars/uPhysFSLayer.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uPhysFSLayer.pas Tue Apr 02 21:00:57 2013 +0200
@@ -3,21 +3,17 @@
interface
uses SDLh, LuaPas;
-{$IFDEF ANDROID}
+const PhysfsLibName = {$IFDEF PHYSFS_INTERNAL}'libhw_physfs'{$ELSE}'libphysfs'{$ENDIF};
+const PhyslayerLibName = 'libphyslayer';
+
+{$IFNDEF WIN32}
{$linklib physfs}
-{$ELSE}
+ {$linklib physlayer}
{$IFDEF DARWIN}
- {$LINKFRAMEWORK IOKit}
+ {$linkframework IOKit}
{$ENDIF}
{$ENDIF}
-const
-{$IFDEF WIN32}
- PhysfsLibName = 'libphysfs';
-{$ELSE}
- PhysfsLibName = 'physfs';
-{$ENDIF}
-
procedure initModule;
procedure freeModule;
@@ -36,8 +32,8 @@
function pfsExists(fname: shortstring): boolean;
-function physfsReader(L: Plua_State; f: PFSFile; sz: Psize_t) : PChar; cdecl; external PhysfsLibName;
-procedure physfsReaderSetBuffer(buf: pointer); cdecl; external PhysfsLibName;
+function physfsReader(L: Plua_State; f: PFSFile; sz: Psize_t) : PChar; cdecl; external PhyslayerLibName;
+procedure physfsReaderSetBuffer(buf: pointer); cdecl; external PhyslayerLibName;
{$IFNDEF PAS2C}
//apparently pas2c doesn't render the functions below if it finds 'implementation' first
@@ -45,10 +41,10 @@
uses uUtils, uVariables, sysutils;
{$ENDIF}
-function PHYSFS_init(argv: PChar): LongInt; cdecl; external PhysfsLibName;
-function PHYSFS_deinit: LongInt; cdecl; external PhysfsLibName;
-function PHYSFSRWOPS_openRead(fname: PChar): PSDL_RWops; cdecl; external PhysfsLibName;
-function PHYSFSRWOPS_openWrite(fname: PChar): PSDL_RWops; cdecl; external PhysfsLibName;
+function PHYSFS_init(argv0: PChar) : LongInt; cdecl; external PhysfsLibName;
+function PHYSFS_deinit() : LongInt; cdecl; external PhysfsLibName;
+function PHYSFSRWOPS_openRead(fname: PChar): PSDL_RWops; cdecl ; external PhyslayerLibName;
+function PHYSFSRWOPS_openWrite(fname: PChar): PSDL_RWops; cdecl; external PhyslayerLibName;
function PHYSFS_mount(newDir, mountPoint: PChar; appendToPath: LongBool) : LongInt; cdecl; external PhysfsLibName;
function PHYSFS_openRead(fname: PChar): PFSFile; cdecl; external PhysfsLibName;
@@ -57,7 +53,7 @@
function PHYSFS_close(f: PFSFile): LongBool; cdecl; external PhysfsLibName;
function PHYSFS_exists(fname: PChar): LongBool; cdecl; external PhysfsLibName;
-procedure hedgewarsMountPackages; cdecl; external PhysfsLibName;
+procedure hedgewarsMountPackages(); cdecl; external PhyslayerLibName;
{$IFDEF PAS2C}
implementation
@@ -157,9 +153,9 @@
i:= PHYSFS_init(Str2PChar(cPhysfsId));
AddFileLog('[PhysFS] init: ' + inttostr(i));
- i:= PHYSFS_mount(Str2PChar(PathPrefix), nil, true);
+ i:= PHYSFS_mount(Str2PChar(PathPrefix), nil, false);
AddFileLog('[PhysFS] mount ' + PathPrefix + ': ' + inttostr(i));
- i:= PHYSFS_mount(Str2PChar(UserPathPrefix + '/Data'), nil, true);
+ i:= PHYSFS_mount(Str2PChar(UserPathPrefix + '/Data'), nil, false);
AddFileLog('[PhysFS] mount ' + UserPathPrefix + '/Data: ' + inttostr(i));
hedgewarsMountPackages;
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uRender.pas
--- a/hedgewars/uRender.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uRender.pas Tue Apr 02 21:00:57 2013 +0200
@@ -27,15 +27,16 @@
procedure DrawSprite (Sprite: TSprite; X, Y, Frame: LongInt);
procedure DrawSprite (Sprite: TSprite; X, Y, FrameX, FrameY: LongInt);
-procedure DrawSpriteFromRect (Sprite: TSprite; r: TSDL_Rect; X, Y, Height, Position: LongInt);
+procedure DrawSpriteFromRect (Sprite: TSprite; r: TSDL_Rect; X, Y, Height, Position: LongInt); inline;
procedure DrawSpriteClipped (Sprite: TSprite; X, Y, TopY, RightX, BottomY, LeftX: LongInt);
procedure DrawSpriteRotated (Sprite: TSprite; X, Y, Dir: LongInt; Angle: real);
procedure DrawSpriteRotatedF (Sprite: TSprite; X, Y, Frame, Dir: LongInt; Angle: real);
procedure DrawTexture (X, Y: LongInt; Texture: PTexture); inline;
procedure DrawTexture (X, Y: LongInt; Texture: PTexture; Scale: GLfloat);
-procedure DrawTextureFromRect (X, Y: LongInt; r: PSDL_Rect; SourceTexture: PTexture);
-procedure DrawTextureFromRect (X, Y, W, H: LongInt; r: PSDL_Rect; SourceTexture: PTexture);
+procedure DrawTextureFromRect (X, Y: LongInt; r: PSDL_Rect; SourceTexture: PTexture); inline;
+procedure DrawTextureFromRect (X, Y, W, H: LongInt; r: PSDL_Rect; SourceTexture: PTexture); inline;
+procedure DrawTextureFromRectDir(X, Y, W, H: LongInt; r: PSDL_Rect; SourceTexture: PTexture; Dir: LongInt);
procedure DrawTextureCentered (X, Top: LongInt; Source: PTexture);
procedure DrawTextureF (Texture: PTexture; Scale: GLfloat; X, Y, Frame, Dir, w, h: LongInt);
procedure DrawTextureRotated (Texture: PTexture; hw, hh, X, Y, Dir: LongInt; Angle: real);
@@ -63,19 +64,24 @@
var LastTint: LongWord = 0;
-procedure DrawSpriteFromRect(Sprite: TSprite; r: TSDL_Rect; X, Y, Height, Position: LongInt);
+procedure DrawSpriteFromRect(Sprite: TSprite; r: TSDL_Rect; X, Y, Height, Position: LongInt); inline;
begin
r.y:= r.y + Height * Position;
r.h:= Height;
DrawTextureFromRect(X, Y, @r, SpritesData[Sprite].Texture)
end;
-procedure DrawTextureFromRect(X, Y: LongInt; r: PSDL_Rect; SourceTexture: PTexture);
+procedure DrawTextureFromRect(X, Y: LongInt; r: PSDL_Rect; SourceTexture: PTexture); inline;
begin
-DrawTextureFromRect(X, Y, r^.w, r^.h, r, SourceTexture)
+DrawTextureFromRectDir(X, Y, r^.w, r^.h, r, SourceTexture, 1)
end;
-{
-procedure DrawTextureFromRect(X, Y, W, H: LongInt; r: PSDL_Rect; SourceTexture: PTexture);
+
+procedure DrawTextureFromRect(X, Y, W, H: LongInt; r: PSDL_Rect; SourceTexture: PTexture); inline;
+begin
+DrawTextureFromRectDir(X, Y, W, H, r, SourceTexture, 1)
+end;
+
+procedure DrawTextureFromRectDir(X, Y, W, H: LongInt; r: PSDL_Rect; SourceTexture: PTexture; Dir: LongInt);
var rr: TSDL_Rect;
_l, _r, _t, _b: real;
VertexBuffer, TextureBuffer: array [0..3] of TVertex2f;
@@ -101,14 +107,28 @@
glBindTexture(GL_TEXTURE_2D, SourceTexture^.id);
-VertexBuffer[0].X:= X;
-VertexBuffer[0].Y:= Y;
-VertexBuffer[1].X:= rr.w + X;
-VertexBuffer[1].Y:= Y;
-VertexBuffer[2].X:= rr.w + X;
-VertexBuffer[2].Y:= rr.h + Y;
-VertexBuffer[3].X:= X;
-VertexBuffer[3].Y:= rr.h + Y;
+if Dir < 0 then
+ begin
+ VertexBuffer[0].X:= X + rr.w/2;
+ VertexBuffer[0].Y:= Y;
+ VertexBuffer[1].X:= X - rr.w/2;
+ VertexBuffer[1].Y:= Y;
+ VertexBuffer[2].X:= X - rr.w/2;
+ VertexBuffer[2].Y:= rr.h + Y;
+ VertexBuffer[3].X:= X + rr.w/2;
+ VertexBuffer[3].Y:= rr.h + Y;
+ end
+else
+ begin
+ VertexBuffer[0].X:= X;
+ VertexBuffer[0].Y:= Y;
+ VertexBuffer[1].X:= rr.w + X;
+ VertexBuffer[1].Y:= Y;
+ VertexBuffer[2].X:= rr.w + X;
+ VertexBuffer[2].Y:= rr.h + Y;
+ VertexBuffer[3].X:= X;
+ VertexBuffer[3].Y:= rr.h + Y;
+ end;
TextureBuffer[0].X:= _l;
TextureBuffer[0].Y:= _t;
@@ -123,9 +143,9 @@
glTexCoordPointer(2, GL_FLOAT, 0, @TextureBuffer[0]);
glDrawArrays(GL_TRIANGLE_FAN, 0, High(VertexBuffer) - Low(VertexBuffer) + 1);
end;
-}
+
-procedure DrawTextureFromRect(X, Y, W, H: LongInt; r: PSDL_Rect; SourceTexture: PTexture);
+procedure DrawTextureFromRectDir(X, Y, W, H: LongInt; r: PSDL_Rect; SourceTexture: PTexture);
var
rr: TSDL_Rect;
VertexBuffer, TextureBuffer: array [0..3] of TVertex2f;
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uScript.pas
--- a/hedgewars/uScript.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uScript.pas Tue Apr 02 21:00:57 2013 +0200
@@ -1280,10 +1280,8 @@
function lc_endgame(L : Plua_State) : LongInt; Cdecl;
begin
- {$IFNDEF PAS2C}
L:= L; // avoid compiler hint
- {$ENDIF}
- GameState:= gsExit;
+ AddGear(0, 0, gtATFinishGame, 0, _0, _0, 3000);
lc_endgame:= 0
end;
@@ -2048,7 +2046,6 @@
begin
ScriptSetInteger('TurnTimeLeft', TurnTimeLeft);
ScriptSetInteger('GameTime', GameTicks);
-ScriptSetInteger('RealTime', RealTicks);
ScriptSetInteger('TotalRounds', TotalRounds);
ScriptSetInteger('WaterLine', cWaterLine);
if GameTicks = 0 then
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uSound.pas
--- a/hedgewars/uSound.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uSound.pas Tue Apr 02 21:00:57 2013 +0200
@@ -105,12 +105,13 @@
function AskForVoicepack(name: shortstring): Pointer;
+var Volume: LongInt;
+ SoundTimerTicks: Longword;
implementation
uses uVariables, uConsole, uCommands, uDebug, uPhysFSLayer;
const chanTPU = 32;
-var Volume: LongInt;
- cInitVolume: LongInt;
+var cInitVolume: LongInt;
previousVolume: LongInt; // cached volume value
lastChan: array [TSound] of LongInt;
voicepacks: array[0..cMaxTeams] of TVoicepack;
@@ -262,14 +263,14 @@
begin
locName:= name+'_'+cLocale;
path:= cPathz[ptVoices] + '/' + locName;
- if DirectoryExists(path) then
+ if pfsExists(path) then
name:= locName
else
if Length(cLocale) > 3 then
begin
locName:= name+'_'+Copy(cLocale,1,2);
path:= cPathz[ptVoices] + '/' + locName;
- if DirectoryExists(path) then
+ if pfsExists(path) then
name:= locName
end
end;
@@ -712,6 +713,7 @@
isAudioMuted:= false;
isSEBackup:= isSoundEnabled;
Volume:= 0;
+ SoundTimerTicks:= 0;
defVoicepack:= AskForVoicepack('Default');
for i:= Low(TSound) to High(TSound) do
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uStats.pas
--- a/hedgewars/uStats.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uStats.pas Tue Apr 02 21:00:57 2013 +0200
@@ -40,6 +40,7 @@
var DamageClan : Longword = 0;
DamageTotal : Longword = 0;
+ DamageTurn : Longword = 0;
KillsClan : LongWord = 0;
Kills : LongWord = 0;
KillsTotal : LongWord = 0;
@@ -82,7 +83,8 @@
inc(KillsClan);
end;
-inc(DamageTotal, Damage)
+inc(DamageTotal, Damage);
+inc(DamageTurn, Damage)
end;
procedure Skipped;
@@ -112,7 +114,7 @@
end
else if DamageClan <> 0 then
- if DamageTotal > DamageClan then
+ if DamageTurn > DamageClan then
if random(2) = 0 then
AddVoice(sndNutter, CurrentTeam^.voicepack)
else
@@ -170,6 +172,7 @@
Kills:= 0;
KillsClan:= 0;
DamageClan:= 0;
+DamageTurn:= 0;
AmmoUsedCount:= 0;
AmmoDamagingUsed:= false;
isTurnSkipped:= false
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uTeams.pas
--- a/hedgewars/uTeams.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uTeams.pas Tue Apr 02 21:00:57 2013 +0200
@@ -110,7 +110,7 @@
end;
procedure SwitchHedgehog;
-var c: LongWord;
+var c, i, j: LongWord;
PrevHH, PrevTeam : LongWord;
begin
TargetPoint.X:= NoPointX;
@@ -173,7 +173,15 @@
if c = ClansCount then
begin
if not PlacingHogs then
+ begin
inc(TotalRounds);
+ for i:= 0 to Pred(TeamsCount) do
+ with TeamsArray[i]^ do
+ for j:= 0 to Pred(HedgehogsNumber) do
+ with Hedgehogs[j] do
+ if Effects[heFrozen] > 255 then
+ Effects[heFrozen]:= max(255,Effects[heFrozen]-50000)
+ end;
c:= 0
end;
@@ -188,11 +196,11 @@
PrevHH:= CurrHedgehog mod HedgehogsNumber; // prevent infinite loop when CurrHedgehog = 7, but HedgehogsNumber < 8 (team is destroyed before its first turn)
repeat
CurrHedgehog:= Succ(CurrHedgehog) mod HedgehogsNumber;
- until (Hedgehogs[CurrHedgehog].Gear <> nil) or (CurrHedgehog = PrevHH)
+ until ((Hedgehogs[CurrHedgehog].Gear <> nil) and (Hedgehogs[CurrHedgehog].Effects[heFrozen] = 0)) or (CurrHedgehog = PrevHH)
end
until (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Gear <> nil) or (PrevTeam = CurrTeam) or ((CurrTeam = TagTeamIndex) and ((GameFlags and gfTagTeam) <> 0));
end
-until (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Gear <> nil);
+until (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Gear <> nil) and (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Effects[heFrozen] = 0);
SwitchCurrentHedgehog(@(CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog]));
{$IFDEF USE_TOUCH_INTERFACE}
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uTypes.pas
--- a/hedgewars/uTypes.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uTypes.pas Tue Apr 02 21:00:57 2013 +0200
@@ -87,7 +87,7 @@
sprHandResurrector, sprCross, sprAirDrill, sprNapalmBomb,
sprBulletHit, sprSnowball, sprHandSnowball, sprSnow,
sprSDFlake, sprSDWater, sprSDCloud, sprSDSplash, sprSDDroplet, sprTardis,
- sprSlider, sprBotlevels, sprHandKnife, sprKnife, sprStar
+ sprSlider, sprBotlevels, sprHandKnife, sprKnife, sprStar, sprIceTexture, sprIceGun, sprFrozenHog
);
// Gears that interact with other Gears and/or Land
@@ -223,46 +223,56 @@
PClan = ^TClan;
TGearStepProcedure = procedure (Gear: PGear);
+// So, you're here looking for variables you can (ab)use to store some gear state?
+// Not all members of this structure are created equal. Comments below are my take on what can be used for what in the gear structure.
TGear = record
- NextGear, PrevGear: PGear;
- Active: Boolean;
- AdvBounce: Longword;
- Invulnerable: Boolean;
- RenderTimer: Boolean;
- AmmoType : TAmmoType;
- State : Longword;
- X : hwFloat;
+// Don't ever override these.
+ NextGear, PrevGear: PGear; // Linked list
+ Z: Longword; // Z index. For rendering. Sets order in list
+ Active: Boolean; // Is gear Active (running step code)
+ Kind: TGearType;
+ doStep: TGearStepProcedure; // Code the gear is running
+ AmmoType : TAmmoType; // Ammo type associated with this kind of gear
+ RenderTimer: Boolean; // Will visually display Timer if true
+ Target : TPoint; // Gear target. Will render in uGearsRender unless a special case is added
+ AIHints: LongWord; // hints for ai.
+ LastDamage: PHedgehog; // Used to track damage source for stats
+ CollisionIndex: LongInt; // Position in collision array
+ Message: LongWord; // Game messages are stored here. See gm bitmasks in uConsts
+ uid: Longword; // Lua use this to reference gears
+// Strongly recommended not to override these. Will mess up generic operations like portaling
+ X : hwFloat; // X/Y/dX/dY are position/velocity. People count on these having semi-normal values
Y : hwFloat;
dX: hwFloat;
dY: hwFloat;
- Target : TPoint;
- Kind: TGearType;
- Pos: Longword;
- doStep: TGearStepProcedure;
- Radius: LongInt;
- Angle, Power : Longword;
- DirAngle: real;
- Timer : LongWord;
+ State : Longword; // See gst bitmask values in uConsts
+ PortalCounter: LongWord; // Necessary to interrupt portal loops. Not possible to avoid infinite loops without it.
+// Don't use these if you're using generic movement like doStepFallingGear and explosion shoves. Generally recommended not to use.
+ Radius: LongInt; // Radius. If not using uCollisions, is usually used to indicate area of effect
+ CollisionMask: Word; // Masking off Land impact FF7F for example ignores current hog and crates
+ AdvBounce: Longword; // Triggers 45° bounces. Is a counter to avoid edge cases
Elasticity: hwFloat;
Friction : hwFloat;
- Density : hwFloat;
- Message, MsgParam : Longword;
- Hedgehog: PHedgehog;
+ Density : hwFloat; // Density is kind of a mix of size and density. Impacts distance thrown, wind.
+ ImpactSound: TSound; // first sound, others have to be after it in the sounds def.
+ nImpactSounds: Word; // count of ImpactSounds.
+// Don't use these if you want to take damage normally, otherwise health/damage are commonly used for other purposes
+ Invulnerable: Boolean;
Health, Damage, Karma: LongInt;
- CollisionIndex: LongInt;
- Tag: LongInt;
- Tex: PTexture;
- Z: Longword;
- CollisionMask: Word;
- LinkedGear: PGear;
- FlightTime: Longword;
- uid: Longword;
- ImpactSound: TSound; // first sound, others have to be after it in the sounds def.
- nImpactSounds: Word; // count of ImpactSounds
- SoundChannel: LongInt;
- PortalCounter: LongWord; // Hopefully temporary, but avoids infinite portal loops in a guaranteed fashion.
- AIHints: LongWord; // hints for ai. haha ^^^^^^ temporary, sure
- LastDamage: PHedgehog;
+// DirAngle is a "real" - if you don't need it for rotation of sprite in uGearsRender, you can use it for any visual-only value
+ DirAngle: real;
+// These are frequently overridden to serve some other purpose
+ Pos: Longword; // Commonly overridden. Example use is posCase values in uConsts.
+ Angle, Power : Longword; // Used for hog aiming/firing. Angle is rarely used as an Angle otherwise.
+ Timer : LongWord; // Typically used for some sort of gear timer. Time to explosion, remaining fuel...
+ Tag: LongInt; // Quite generic. Variety of uses.
+ FlightTime: Longword; // Initially added for batting of hogs to determine homerun. Used for some firing delays
+ MsgParam: LongWord; // Initially stored a set of messages. So usually gm values like Message. Frequently overriden
+// These are not used generically, but should probably be used for purpose intended. Definitely shouldn't override pointer type
+ Tex: PTexture; // A texture created by the gear. Shouldn't use for anything but textures
+ LinkedGear: PGear; // Used to track a related gear. Portal pairs for example.
+ Hedgehog: PHedgehog; // set to CurrentHedgehog on gear creation
+ SoundChannel: LongInt; // Used to track a sound the gear started
end;
TPGearArray = array of PGear;
PGearArrayS = record
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uUtils.pas
--- a/hedgewars/uUtils.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uUtils.pas Tue Apr 02 21:00:57 2013 +0200
@@ -87,6 +87,9 @@
procedure AudioServicesPlaySystemSound(num: LongInt); cdecl; external;
{$ENDIF}
+function sanitizeForLog(s: shortstring): shortstring;
+function sanitizeCharForLog(c: char): shortstring;
+
procedure initModule(isNotPreview: boolean);
procedure freeModule;
@@ -375,15 +378,15 @@
if (#$1100 <= u) and (
(u <= #$11FF ) or // Hangul Jamo
((#$2E80 <= u) and (u <= #$2FDF)) or // CJK Radicals Supplement / Kangxi Radicals
- ((#$2FF0 <= u) and (u <= #$303F)) or // Ideographic Description Characters / CJK Radicals Supplement
- ((#$3130 <= u) and (u <= #$318F)) or // Hangul Compatibility Jamo
+ ((#$2FF0 <= u) and (u <= #$31FF)) or // Ideographic Description Characters / CJK Radicals Supplement / Hiragana / Hangul Compatibility Jamo / Katakana
((#$31C0 <= u) and (u <= #$31EF)) or // CJK Strokes
- ((#$3200 <= u) and (u <= #$4DBF)) or // Enclosed CJK Letters and Months / CJK Compatibility / CJK Unified Ideographs Extension A
+ ((#$3200 <= u) and (u <= #$4DBF)) or // Enclosed CJK Letters and Months / CJK Compatibility / CJK Unified Ideographs Extension A / Circled Katakana
((#$4E00 <= u) and (u <= #$9FFF)) or // CJK Unified Ideographs
((#$AC00 <= u) and (u <= #$D7AF)) or // Hangul Syllables
((#$F900 <= u) and (u <= #$FAFF)) or // CJK Compatibility Ideographs
- ((#$FE30 <= u) and (u <= #$FE4F))) // CJK Compatibility Forms
- then
+ ((#$FE30 <= u) and (u <= #$FE4F)) or // CJK Compatibility Forms
+ ((#$FF66 <= u) and (u <= #$FF9D))) // halfwidth katakana
+ then
begin
CheckCJKFont:= THWFont( ord(font) + ((ord(High(THWFont))+1) div 2) );
exit;
@@ -458,6 +461,31 @@
{$ENDIF}
end;
+function sanitizeForLog(s: shortstring): shortstring;
+var i: byte;
+ r: shortstring;
+begin
+ r[0]:= s[0];
+ for i:= 1 to length(s) do
+ if (s[i] < #32) or (s[i] > #127) then
+ r[i]:= '?'
+ else
+ r[i]:= s[i];
+
+ sanitizeForLog:= r
+end;
+
+function sanitizeCharForLog(c: char): shortstring;
+var r: shortstring;
+begin
+ if (c < #32) or (c > #127) then
+ r:= '#' + inttostr(byte(c))
+ else
+ r:= c;
+
+ sanitizeCharForLog:= r
+end;
+
procedure initModule(isNotPreview: boolean);
{$IFDEF DEBUGFILE}
var logfileBase: shortstring;
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uVariables.pas
--- a/hedgewars/uVariables.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uVariables.pas Tue Apr 02 21:00:57 2013 +0200
@@ -115,6 +115,8 @@
// originally typed consts
ExplosionBorderColor: LongWord;
+ IceColor : LongWord;
+ IceEdgeColor : LongWord;
WaterOpacity: byte;
SDWaterOpacity: byte;
GrayScale: Boolean;
@@ -656,16 +658,18 @@
Width: 3; Height: 17; imageWidth: 3; imageHeight: 17; saveSurf: false; priority: tpLow; getDimensions: false; getImageDimensions: false), // sprSlider
(FileName: 'botlevels'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil;
Width: 22; Height: 15; imageWidth: 22; imageHeight: 15; saveSurf: true; priority: tpLow; getDimensions: false; getImageDimensions: false), // sprBotlevels
- (* (FileName: 'amKnife'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil;
- Width: 64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandKnife*)
(FileName: 'amCleaver'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil;
Width: 64; Height: 64; imageWidth: 64; imageHeight: 64; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: false),// sprHandKnife
- (*(FileName: 'knife'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil;
- Width: 29; Height: 14; imageWidth: 64; imageHeight: 64; saveSurf: true; priority: tpLow; getDimensions: false; getImageDimensions: false) // sprKnife*)
(FileName: 'cleaver'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil;
Width: 64; Height: 64; imageWidth: 64; imageHeight: 128; saveSurf: false; priority: tpLow; getDimensions: false; getImageDimensions: false), // sprKnife
(FileName: 'star'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil;
- Width: 12; Height: 12; imageWidth: 12; imageHeight: 12; saveSurf: false; priority: tpLow; getDimensions: false; getImageDimensions: false) // sprStar
+ Width: 12; Height: 12; imageWidth: 12; imageHeight: 12; saveSurf: false; priority: tpLow; getDimensions: false; getImageDimensions: false), // sprStar
+ (FileName: 'icetexture'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil;
+ Width: 128; Height: 128; imageWidth: 128; imageHeight: 128; saveSurf: true; priority: tpLow; getDimensions: false; getImageDimensions: true), // sprIceTexture
+ (FileName: 'amIceGun'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil;
+ Width: 32; Height: 32; imageWidth: 32; imageHeight: 32; saveSurf: false; priority: tpLow; getDimensions: false; getImageDimensions: false), // sprIceGun
+ (FileName: 'amFrozenHog'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil;
+ Width: 64; Height: 64; imageWidth: 64; imageHeight: 64; saveSurf: false; priority: tpLow; getDimensions: false; getImageDimensions: false) // sprFrozenHog
);
const
@@ -1196,8 +1200,8 @@
Bounciness: 1000);
Slot: 6;
TimeAfterTurn: 3000;
- minAngle: 768;
- maxAngle: 1280;
+ minAngle: 804;
+ maxAngle: 1327;
isDamaging: false;
SkipTurns: 0;
PosCount: 1;
@@ -2427,6 +2431,9 @@
SDWaterOpacity:= $80;
SDTint:= $80;
ExplosionBorderColor:= $FF808080;
+ IceColor:= ($44 shl RShift) or ($97 shl GShift) or ($A9 shl BShift) or ($A0 shl AShift);
+ IceEdgeColor:= ($8A shl RShift) or ($AF shl GShift) or ($B2 shl BShift) or ($FF shl AShift);
+
WaterOpacity:= $80;
cDrownSpeed.QWordValue := 257698038; // 0.06
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uVideoRec.pas
--- a/hedgewars/uVideoRec.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uVideoRec.pas Tue Apr 02 21:00:57 2013 +0200
@@ -28,7 +28,10 @@
{$ELSE}
{$IFNDEF WIN32}
- {$LINKLIB ../bin/libavwrapper.a}
+ {$linklib avcodec}
+ {$linklib avformat}
+ {$linklib avutil}
+ {$linklib avwrapper}
{$ENDIF}
interface
@@ -48,17 +51,17 @@
procedure freeModule;
implementation
-
uses uVariables, uUtils, GLunit, SDLh, SysUtils, uIO, uMisc, uTypes;
type TAddFileLogRaw = procedure (s: pchar); cdecl;
+const AvwrapperLibName = 'libavwrapper';
procedure AVWrapper_Init(
AddLog: TAddFileLogRaw;
filename, desc, soundFile, format, vcodec, acodec: PChar;
- width, height, framerateNum, framerateDen, vquality: LongInt); cdecl; external {$IFDEF WIN32}'libavwrapper.dll'{$ENDIF};
-procedure AVWrapper_Close; cdecl; external {$IFDEF WIN32}'libavwrapper.dll'{$ENDIF};
-procedure AVWrapper_WriteFrame( pY, pCb, pCr: PByte ); cdecl; external {$IFDEF WIN32}'libavwrapper.dll'{$ENDIF};
+ width, height, framerateNum, framerateDen, vquality: LongInt); cdecl; external AvwrapperLibName;
+procedure AVWrapper_Close; cdecl; external AvwrapperLibName;
+procedure AVWrapper_WriteFrame( pY, pCb, pCr: PByte ); cdecl; external AvwrapperLibName;
type TFrame = record
realTicks: LongWord;
diff -r 404ddce27b23 -r c13ebed437cb hedgewars/uWorld.pas
--- a/hedgewars/uWorld.pas Wed Feb 20 02:21:58 2013 +0100
+++ b/hedgewars/uWorld.pas Tue Apr 02 21:00:57 2013 +0200
@@ -77,8 +77,7 @@
timeTexture: PTexture;
FPS: Longword;
CountTicks: Longword;
- SoundTimerTicks: Longword;
- prevPoint, prevTargetPoint: TPoint;
+ prevPoint{, prevTargetPoint}: TPoint;
amSel: TAmmoType = amNothing;
missionTex: PTexture;
missionTimer: LongInt;
@@ -225,8 +224,8 @@
uCursor.init();
prevPoint.X:= 0;
prevPoint.Y:= cScreenHeight div 2;
-prevTargetPoint.X:= 0;
-prevTargetPoint.Y:= 0;
+//prevTargetPoint.X:= 0;
+//prevTargetPoint.Y:= 0;
WorldDx:= -(LAND_WIDTH div 2) + cScreenWidth div 2;
WorldDy:= -(LAND_HEIGHT - (playHeight div 2)) + (cScreenHeight div 2);
@@ -646,7 +645,7 @@
AMShiftX:= AMShiftTargetX;
AMShiftY:= AMShiftTargetY;
prevPoint:= CursorPoint;
- prevTargetPoint:= TargetCursorPoint;
+ //prevTargetPoint:= TargetCursorPoint;
AMState:= AMHidden;
end;
end;
@@ -1582,25 +1581,11 @@
if fpsTexture <> nil then
DrawTexture((cScreenWidth shr 1) - 60 - offsetY, offsetX, fpsTexture);
end;
-
- // lag warning (?)
- inc(SoundTimerTicks, Lag);
end;
-if SoundTimerTicks >= 50 then
-begin
- SoundTimerTicks:= 0;
- if cVolumeDelta <> 0 then
- begin
- str(ChangeVolume(cVolumeDelta), s);
- AddCaption(Format(trmsg[sidVolume], s), cWhiteColor, capgrpVolume);
- end;
- if isAudioMuted then
- AddCaption(trmsg[sidMute], cWhiteColor, capgrpVolume)
-end;
if GameState = gsConfirm then
- DrawTextureCentered(0, (cScreenHeight shr 1), ConfirmTexture);
+ DrawTextureCentered(0, (cScreenHeight shr 1)-40, ConfirmTexture);
if ScreenFade <> sfNone then
begin
diff -r 404ddce27b23 -r c13ebed437cb misc/Android.mk
--- a/misc/Android.mk Wed Feb 20 02:21:58 2013 +0100
+++ b/misc/Android.mk Tue Apr 02 21:00:57 2013 +0200
@@ -4,4 +4,6 @@
include $(MISC_DIR)/libfreetype/Android.mk
include $(MISC_DIR)/liblua/Android.mk
include $(MISC_DIR)/libtremor/Android.mk
-include $(MISC_DIR)/physfs/Android.mk
+include $(MISC_DIR)/libphysfs/Android.mk
+include $(MISC_DIR)/libphyslayer/Android.mk
+
diff -r 404ddce27b23 -r c13ebed437cb misc/hedgewars.desktop
--- a/misc/hedgewars.desktop Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-[Desktop Entry]
-Type=Application
-Version=1.0
-Encoding=UTF-8
-Name=Hedgewars
-GenericName=Fighting Hedgehogs
-GenericName[de]=Kämpfende Igel
-GenericName[es]=Batallas entre erizos
-GenericName[fr]=Bataille de hérissons
-GenericName[ko]=고슴도치 싸우기
-GenericName[ja]=ファイチングハリネズミ
-GenericName[it]=Ricci combattenti
-GenericName[pl]=Walczące jeże
-GenericName[pt]=Batalhas entre ouriços
-GenericName[ru]=Битвы ежей
-GenericName[sk]=Bojujúci ježkovia
-GenericName[cs]=Bojující ježci
-GenericName[sv]=Stridande igelkottar
-Icon=hedgewars.png
-Exec=hedgewars
-Terminal=false
-StartupNotify=false
-Categories=Application;Game;StrategyGame;
diff -r 404ddce27b23 -r c13ebed437cb misc/libphysfs/Android.mk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/Android.mk Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,27 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := physfs
+
+LOCAL_CFLAGS := -O2 -DPHYSFS_NO_CDROM_SUPPORT
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)
+
+LOCAL_SRC_FILES := physfs.c \
+ physfs_byteorder.c \
+ physfs_unicode.c \
+ platform_posix.c \
+ platform_unix.c \
+ platform_macosx.c \
+ platform_windows.c \
+ archiver_dir.c \
+ archiver_grp.c \
+ archiver_hog.c \
+ archiver_lzma.c \
+ archiver_mvl.c \
+ archiver_qpak.c \
+ archiver_wad.c \
+ archiver_zip.c \
+
+include $(BUILD_SHARED_LIBRARY)
diff -r 404ddce27b23 -r c13ebed437cb misc/libphysfs/CMakeLists.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/CMakeLists.txt Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,290 @@
+# PhysicsFS; a portable, flexible file i/o abstraction.
+# Copyright (C) 2007 Ryan C. Gordon.
+#
+# Please see the file LICENSE.txt in the source's root directory.
+
+## lines starting with '##' are lines overridden/modified/added by Hedgewars configuration
+##CMAKE_MINIMUM_REQUIRED(VERSION 2.4)
+##PROJECT(PhysicsFS)
+set(PHYSFS_VERSION 2.1.0)
+
+# Increment this if/when we break backwards compatibility.
+set(PHYSFS_SOVERSION 1)
+
+# I hate that they define "WIN32" ... we're about to move to Win64...I hope!
+if(WIN32 AND NOT WINDOWS)
+ set(WINDOWS TRUE)
+endif(WIN32 AND NOT WINDOWS)
+
+# Bleh, let's do it for "APPLE" too.
+if(APPLE AND NOT MACOSX)
+ set(MACOSX TRUE)
+endif(APPLE AND NOT MACOSX)
+
+# For now, Haiku and BeOS are the same, as far as the build system cares.
+if(HAIKU AND NOT BEOS)
+ set(BEOS TRUE)
+endif(HAIKU AND NOT BEOS)
+
+if(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
+ set(SOLARIS TRUE)
+endif(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
+
+include(CheckIncludeFile)
+include(CheckLibraryExists)
+include(CheckCSourceCompiles)
+
+
+if(MACOSX)
+ # Fallback to older OS X on PowerPC to support wider range of systems...
+ if(CMAKE_OSX_ARCHITECTURES MATCHES ppc)
+ add_definitions(-DMAC_OS_X_VERSION_MIN_REQUIRED=1020)
+ set(OTHER_LDFLAGS ${OTHER_LDFLAGS} " -mmacosx-version-min=10.2")
+ endif(CMAKE_OSX_ARCHITECTURES MATCHES ppc)
+
+ # Need these everywhere...
+ add_definitions(-fno-common)
+ find_library(iokit_framework NAMES IOKit)
+ list(APPEND OTHER_LDFLAGS ${iokit_framework})
+endif(MACOSX)
+
+# Add some gcc-specific command lines.
+if(CMAKE_COMPILER_IS_GNUCC)
+ # Always build with debug symbols...you can strip it later.
+ add_definitions(-g -pipe -Werror -fsigned-char)
+
+ # Stupid BeOS generates warnings in the system headers.
+ if(NOT BEOS)
+ add_definitions(-Wall)
+ endif(NOT BEOS)
+
+ CHECK_C_SOURCE_COMPILES("
+ #if ((defined(__GNUC__)) && (__GNUC__ >= 4))
+ int main(int argc, char **argv) { int is_gcc4 = 1; return 0; }
+ #else
+ #error This is not gcc4.
+ #endif
+ " PHYSFS_IS_GCC4)
+
+ if(PHYSFS_IS_GCC4)
+ # Not supported on several operating systems at this time.
+ if(NOT SOLARIS AND NOT WINDOWS)
+ add_definitions(-fvisibility=hidden)
+ endif(NOT SOLARIS AND NOT WINDOWS)
+ endif(PHYSFS_IS_GCC4)
+
+ # Don't use -rpath.
+ set(CMAKE_SKIP_RPATH ON CACHE BOOL "Skip RPATH" FORCE)
+endif(CMAKE_COMPILER_IS_GNUCC)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "SunPro")
+ add_definitions(-erroff=E_EMPTY_TRANSLATION_UNIT)
+ add_definitions(-xldscope=hidden)
+endif(CMAKE_C_COMPILER_ID STREQUAL "SunPro")
+
+if(MSVC)
+ # VS.NET 8.0 got really really anal about strcpy, etc, which even if we
+ # cleaned up our code, zlib, etc still use...so disable the warning.
+ add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
+endif(MSVC)
+
+
+if(BEOS)
+ # We add this explicitly, since we don't want CMake to think this
+ # is a C++ project unless we're on BeOS.
+ set(PHYSFS_BEOS_SRCS src/platform_beos.cpp)
+ find_library(BE_LIBRARY be)
+ find_library(ROOT_LIBRARY root)
+ set(optional_library_libs ${optional_library_libs} ${BE_LIBRARY} ${ROOT_LIBRARY})
+endif(BEOS)
+
+
+# Almost everything is "compiled" here, but things that don't apply to the
+# build are #ifdef'd out. This is to make it easy to embed PhysicsFS into
+# another project or bring up a new build system: just compile all the source
+# code and #define the things you want.
+set(PHYSFS_SRCS
+ physfs.c
+ physfs_byteorder.c
+ physfs_unicode.c
+ platform_posix.c
+ platform_unix.c
+ platform_macosx.c
+ platform_windows.c
+ archiver_dir.c
+ archiver_unpacked.c
+ archiver_grp.c
+ archiver_hog.c
+ archiver_lzma.c
+ archiver_mvl.c
+ archiver_qpak.c
+ archiver_wad.c
+ archiver_zip.c
+ archiver_iso9660.c
+ ${PHYSFS_BEOS_SRCS}
+)
+
+
+# platform layers ...
+
+if(UNIX)
+ if(BEOS)
+ set(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
+ set(PHYSFS_HAVE_THREAD_SUPPORT TRUE)
+ set(HAVE_PTHREAD_H TRUE)
+ else(BEOS)
+ CHECK_INCLUDE_FILE(sys/ucred.h HAVE_UCRED_H)
+ if(HAVE_UCRED_H)
+ add_definitions(-DPHYSFS_HAVE_SYS_UCRED_H=1)
+ set(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
+ endif(HAVE_UCRED_H)
+
+ CHECK_INCLUDE_FILE(mntent.h HAVE_MNTENT_H)
+ if(HAVE_MNTENT_H)
+ add_definitions(-DPHYSFS_HAVE_MNTENT_H=1)
+ set(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
+ endif(HAVE_MNTENT_H)
+
+ # !!! FIXME: Solaris fails this, because mnttab.h implicitly
+ # !!! FIXME: depends on other system headers. :(
+ #CHECK_INCLUDE_FILE(sys/mnttab.h HAVE_SYS_MNTTAB_H)
+ CHECK_C_SOURCE_COMPILES("
+ #include
+ #include
+ int main(int argc, char **argv) { return 0; }
+ " HAVE_SYS_MNTTAB_H)
+
+ if(HAVE_SYS_MNTTAB_H)
+ add_definitions(-DPHYSFS_HAVE_SYS_MNTTAB_H=1)
+ set(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
+ endif(HAVE_SYS_MNTTAB_H)
+
+ CHECK_INCLUDE_FILE(pthread.h HAVE_PTHREAD_H)
+ if(HAVE_PTHREAD_H)
+ set(PHYSFS_HAVE_THREAD_SUPPORT TRUE)
+ endif(HAVE_PTHREAD_H)
+ endif(BEOS)
+endif(UNIX)
+
+if(WINDOWS)
+ set(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
+ set(PHYSFS_HAVE_THREAD_SUPPORT TRUE)
+endif(WINDOWS)
+
+if(NOT PHYSFS_HAVE_CDROM_SUPPORT)
+ add_definitions(-DPHYSFS_NO_CDROM_SUPPORT=1)
+ message(WARNING " ***")
+ message(WARNING " *** There is no CD-ROM support in this build!")
+ message(WARNING " *** PhysicsFS will just pretend there are no discs.")
+ message(WARNING " *** This may be fine, depending on how PhysicsFS is used,")
+ message(WARNING " *** but is this what you REALLY wanted?")
+ message(WARNING " *** (Maybe fix CMakeLists.txt, or write a platform driver?)")
+ message(WARNING " ***")
+endif(NOT PHYSFS_HAVE_CDROM_SUPPORT)
+
+if(PHYSFS_HAVE_THREAD_SUPPORT)
+ add_definitions(-D_REENTRANT -D_THREAD_SAFE)
+else(PHYSFS_HAVE_THREAD_SUPPORT)
+ add_definitions(-DPHYSFS_NO_THREAD_SUPPORT=1)
+ message(WARNING " ***")
+ message(WARNING " *** There is no thread support in this build!")
+ message(WARNING " *** PhysicsFS will NOT be reentrant!")
+ message(WARNING " *** This may be fine, depending on how PhysicsFS is used,")
+ message(WARNING " *** but is this what you REALLY wanted?")
+ message(WARNING " *** (Maybe fix CMakeLists.txt, or write a platform driver?)")
+ message(WARNING " ***")
+endif(PHYSFS_HAVE_THREAD_SUPPORT)
+
+
+# Archivers ...
+
+option(PHYSFS_ARCHIVE_ZIP "Enable ZIP support" TRUE)
+if(PHYSFS_ARCHIVE_ZIP)
+ add_definitions(-DPHYSFS_SUPPORTS_ZIP=1)
+ set(PHYSFS_FEATURES "ZIP")
+endif(PHYSFS_ARCHIVE_ZIP)
+
+#option(PHYSFS_ARCHIVE_GRP "Enable Build Engine GRP support" TRUE)
+#if(PHYSFS_ARCHIVE_GRP)
+# add_definitions(-DPHYSFS_SUPPORTS_GRP=1)
+# set(PHYSFS_FEATURES "${PHYSFS_FEATURES} GRP")
+#endif(PHYSFS_ARCHIVE_GRP)
+
+#option(PHYSFS_ARCHIVE_WAD "Enable Doom WAD support" TRUE)
+#if(PHYSFS_ARCHIVE_WAD)
+# add_definitions(-DPHYSFS_SUPPORTS_WAD=1)
+# set(PHYSFS_FEATURES "${PHYSFS_FEATURES} WAD")
+#endif(PHYSFS_ARCHIVE_WAD)
+
+#option(PHYSFS_ARCHIVE_HOG "Enable Descent I/II HOG support" TRUE)
+#if(PHYSFS_ARCHIVE_HOG)
+# add_definitions(-DPHYSFS_SUPPORTS_HOG=1)
+# set(PHYSFS_FEATURES "${PHYSFS_FEATURES} HOG")
+#endif(PHYSFS_ARCHIVE_HOG)
+
+#option(PHYSFS_ARCHIVE_MVL "Enable Descent I/II MVL support" TRUE)
+#if(PHYSFS_ARCHIVE_MVL)
+# add_definitions(-DPHYSFS_SUPPORTS_MVL=1)
+# set(PHYSFS_FEATURES "${PHYSFS_FEATURES} MVL")
+#endif(PHYSFS_ARCHIVE_MVL)
+
+#option(PHYSFS_ARCHIVE_QPAK "Enable Quake I/II QPAK support" TRUE)
+#if(PHYSFS_ARCHIVE_QPAK)
+# add_definitions(-DPHYSFS_SUPPORTS_QPAK=1)
+# set(PHYSFS_FEATURES "${PHYSFS_FEATURES} QPAK")
+#endif(PHYSFS_ARCHIVE_QPAK)
+
+#option(PHYSFS_ARCHIVE_ISO9660 "Enable ISO9660 support" TRUE)
+#if(PHYSFS_ARCHIVE_ISO9660)
+# add_definitions(-DPHYSFS_SUPPORTS_ISO9660=1)
+# set(PHYSFS_FEATURES "${PHYSFS_FEATURES} CD-ROM")
+#endif(PHYSFS_ARCHIVE_ISO9660)
+
+
+##as needed by Hedgewars configuration
+if(WINDOWS)
+ option(PHYSFS_BUILD_STATIC "Build static library" FALSE)
+ option(PHYSFS_BUILD_SHARED "Build shared library" TRUE)
+ list(APPEND OTHER_LDFLAGS ${SDL_LIBRARY})
+else(WINDOWS)
+ option(PHYSFS_BUILD_STATIC "Build static library" TRUE)
+ option(PHYSFS_BUILD_SHARED "Build shared library" FALSE)
+endif(WINDOWS)
+
+if(PHYSFS_BUILD_STATIC)
+ add_library(physfs STATIC ${PHYSFS_SRCS})
+ set_target_properties(physfs PROPERTIES OUTPUT_NAME ${physfs_output_name}) ##
+ set(lib_prefix ${CMAKE_STATIC_LIBRARY_PREFIX}) ##
+ set(lib_suffix ${CMAKE_STATIC_LIBRARY_SUFFIX}) ##
+endif(PHYSFS_BUILD_STATIC)
+
+if(PHYSFS_BUILD_SHARED)
+ add_library(physfs SHARED ${PHYSFS_SRCS})
+ set_target_properties(physfs PROPERTIES VERSION ${PHYSFS_VERSION})
+ set_target_properties(physfs PROPERTIES SOVERSION ${PHYSFS_SOVERSION})
+ set_target_properties(physfs PROPERTIES OUTPUT_NAME ${physfs_output_name}) ##
+ target_link_libraries(physfs ${optional_library_libs} ${OTHER_LDFLAGS})
+ install(TARGETS physfs RUNTIME DESTINATION ${target_library_install_dir}) ##
+ set(lib_prefix ${CMAKE_SHARED_LIBRARY_PREFIX}) ##
+ set(lib_suffix ${CMAKE_SHARED_LIBRARY_SUFFIX}) ##
+endif(PHYSFS_BUILD_SHARED)
+
+if(NOT PHYSFS_BUILD_SHARED AND NOT PHYSFS_BUILD_STATIC)
+ message(FATAL "Both shared and static libraries are disabled!")
+endif(NOT PHYSFS_BUILD_SHARED AND NOT PHYSFS_BUILD_STATIC)
+
+# CMake FAQ says I need this...
+if(PHYSFS_BUILD_SHARED AND PHYSFS_BUILD_STATIC)
+ set_target_properties(physfs PROPERTIES CLEAN_DIRECT_OUTPUT 1)
+endif(PHYSFS_BUILD_SHARED AND PHYSFS_BUILD_STATIC)
+
+## added standard variables emulating the FindPhysFS.cmake ones (FORCE or cmake won't pick 'em)
+set(PHYSFS_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/misc/libphysfs/ CACHE STRING "" FORCE)
+set(PHYSFS_LIBRARY ${LIBRARY_OUTPUT_PATH}/${lib_prefix}${physfs_output_name}${lib_suffix} CACHE STRING "" FORCE)
+
+
+## removed install, language bindings and test program
+## simplified configuration output
+
+#message(STATUS "PhysFS will be built with ${PHYSFS_FEATURES} support")
+
diff -r 404ddce27b23 -r c13ebed437cb misc/libphysfs/Xcode/Physfs.xcodeproj/project.pbxproj
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/Xcode/Physfs.xcodeproj/project.pbxproj Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,326 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 45;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 617D78F916D932900091D4D6 /* archiver_dir.c in Sources */ = {isa = PBXBuildFile; fileRef = 617D78E816D932900091D4D6 /* archiver_dir.c */; };
+ 617D78FA16D932900091D4D6 /* archiver_grp.c in Sources */ = {isa = PBXBuildFile; fileRef = 617D78E916D932900091D4D6 /* archiver_grp.c */; };
+ 617D78FB16D932900091D4D6 /* archiver_hog.c in Sources */ = {isa = PBXBuildFile; fileRef = 617D78EA16D932900091D4D6 /* archiver_hog.c */; };
+ 617D78FC16D932900091D4D6 /* archiver_iso9660.c in Sources */ = {isa = PBXBuildFile; fileRef = 617D78EB16D932900091D4D6 /* archiver_iso9660.c */; };
+ 617D78FD16D932900091D4D6 /* archiver_lzma.c in Sources */ = {isa = PBXBuildFile; fileRef = 617D78EC16D932900091D4D6 /* archiver_lzma.c */; };
+ 617D78FE16D932900091D4D6 /* archiver_mvl.c in Sources */ = {isa = PBXBuildFile; fileRef = 617D78ED16D932900091D4D6 /* archiver_mvl.c */; };
+ 617D78FF16D932900091D4D6 /* archiver_qpak.c in Sources */ = {isa = PBXBuildFile; fileRef = 617D78EE16D932900091D4D6 /* archiver_qpak.c */; };
+ 617D790016D932900091D4D6 /* archiver_unpacked.c in Sources */ = {isa = PBXBuildFile; fileRef = 617D78EF16D932900091D4D6 /* archiver_unpacked.c */; };
+ 617D790116D932900091D4D6 /* archiver_wad.c in Sources */ = {isa = PBXBuildFile; fileRef = 617D78F016D932900091D4D6 /* archiver_wad.c */; };
+ 617D790216D932900091D4D6 /* archiver_zip.c in Sources */ = {isa = PBXBuildFile; fileRef = 617D78F116D932900091D4D6 /* archiver_zip.c */; };
+ 617D790316D932900091D4D6 /* physfs_byteorder.c in Sources */ = {isa = PBXBuildFile; fileRef = 617D78F216D932900091D4D6 /* physfs_byteorder.c */; };
+ 617D790416D932900091D4D6 /* physfs_unicode.c in Sources */ = {isa = PBXBuildFile; fileRef = 617D78F316D932900091D4D6 /* physfs_unicode.c */; };
+ 617D790516D932900091D4D6 /* physfs.c in Sources */ = {isa = PBXBuildFile; fileRef = 617D78F416D932900091D4D6 /* physfs.c */; };
+ 617D790616D932900091D4D6 /* platform_macosx.c in Sources */ = {isa = PBXBuildFile; fileRef = 617D78F516D932900091D4D6 /* platform_macosx.c */; };
+ 617D790716D932900091D4D6 /* platform_posix.c in Sources */ = {isa = PBXBuildFile; fileRef = 617D78F616D932900091D4D6 /* platform_posix.c */; };
+ 617D790816D932900091D4D6 /* platform_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 617D78F716D932900091D4D6 /* platform_unix.c */; };
+ 617D790916D932900091D4D6 /* platform_windows.c in Sources */ = {isa = PBXBuildFile; fileRef = 617D78F816D932900091D4D6 /* platform_windows.c */; };
+ 617D790F16D932BC0091D4D6 /* physfs_casefolding.h in Headers */ = {isa = PBXBuildFile; fileRef = 617D790A16D932BC0091D4D6 /* physfs_casefolding.h */; };
+ 617D791016D932BC0091D4D6 /* physfs_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 617D790B16D932BC0091D4D6 /* physfs_internal.h */; };
+ 617D791116D932BC0091D4D6 /* physfs_miniz.h in Headers */ = {isa = PBXBuildFile; fileRef = 617D790C16D932BC0091D4D6 /* physfs_miniz.h */; };
+ 617D791216D932BC0091D4D6 /* physfs_platforms.h in Headers */ = {isa = PBXBuildFile; fileRef = 617D790D16D932BC0091D4D6 /* physfs_platforms.h */; };
+ 617D791316D932BC0091D4D6 /* physfs.h in Headers */ = {isa = PBXBuildFile; fileRef = 617D790E16D932BC0091D4D6 /* physfs.h */; };
+ AA747D9F0F9514B9006C5449 /* Physfs_Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = AA747D9E0F9514B9006C5449 /* Physfs_Prefix.pch */; };
+ AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AACBBE490F95108600F1A2B1 /* Foundation.framework */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 617D78E716D932600091D4D6 /* libPhysfs.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPhysfs.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 617D78E816D932900091D4D6 /* archiver_dir.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_dir.c; path = ../archiver_dir.c; sourceTree = SOURCE_ROOT; };
+ 617D78E916D932900091D4D6 /* archiver_grp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_grp.c; path = ../archiver_grp.c; sourceTree = SOURCE_ROOT; };
+ 617D78EA16D932900091D4D6 /* archiver_hog.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_hog.c; path = ../archiver_hog.c; sourceTree = SOURCE_ROOT; };
+ 617D78EB16D932900091D4D6 /* archiver_iso9660.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_iso9660.c; path = ../archiver_iso9660.c; sourceTree = SOURCE_ROOT; };
+ 617D78EC16D932900091D4D6 /* archiver_lzma.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_lzma.c; path = ../archiver_lzma.c; sourceTree = SOURCE_ROOT; };
+ 617D78ED16D932900091D4D6 /* archiver_mvl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_mvl.c; path = ../archiver_mvl.c; sourceTree = SOURCE_ROOT; };
+ 617D78EE16D932900091D4D6 /* archiver_qpak.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_qpak.c; path = ../archiver_qpak.c; sourceTree = SOURCE_ROOT; };
+ 617D78EF16D932900091D4D6 /* archiver_unpacked.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_unpacked.c; path = ../archiver_unpacked.c; sourceTree = SOURCE_ROOT; };
+ 617D78F016D932900091D4D6 /* archiver_wad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_wad.c; path = ../archiver_wad.c; sourceTree = SOURCE_ROOT; };
+ 617D78F116D932900091D4D6 /* archiver_zip.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_zip.c; path = ../archiver_zip.c; sourceTree = SOURCE_ROOT; };
+ 617D78F216D932900091D4D6 /* physfs_byteorder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = physfs_byteorder.c; path = ../physfs_byteorder.c; sourceTree = SOURCE_ROOT; };
+ 617D78F316D932900091D4D6 /* physfs_unicode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = physfs_unicode.c; path = ../physfs_unicode.c; sourceTree = SOURCE_ROOT; };
+ 617D78F416D932900091D4D6 /* physfs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = physfs.c; path = ../physfs.c; sourceTree = SOURCE_ROOT; };
+ 617D78F516D932900091D4D6 /* platform_macosx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = platform_macosx.c; path = ../platform_macosx.c; sourceTree = SOURCE_ROOT; };
+ 617D78F616D932900091D4D6 /* platform_posix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = platform_posix.c; path = ../platform_posix.c; sourceTree = SOURCE_ROOT; };
+ 617D78F716D932900091D4D6 /* platform_unix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = platform_unix.c; path = ../platform_unix.c; sourceTree = SOURCE_ROOT; };
+ 617D78F816D932900091D4D6 /* platform_windows.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = platform_windows.c; path = ../platform_windows.c; sourceTree = SOURCE_ROOT; };
+ 617D790A16D932BC0091D4D6 /* physfs_casefolding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = physfs_casefolding.h; path = ../physfs_casefolding.h; sourceTree = SOURCE_ROOT; };
+ 617D790B16D932BC0091D4D6 /* physfs_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = physfs_internal.h; path = ../physfs_internal.h; sourceTree = SOURCE_ROOT; };
+ 617D790C16D932BC0091D4D6 /* physfs_miniz.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = physfs_miniz.h; path = ../physfs_miniz.h; sourceTree = SOURCE_ROOT; };
+ 617D790D16D932BC0091D4D6 /* physfs_platforms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = physfs_platforms.h; path = ../physfs_platforms.h; sourceTree = SOURCE_ROOT; };
+ 617D790E16D932BC0091D4D6 /* physfs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = physfs.h; path = ../physfs.h; sourceTree = SOURCE_ROOT; };
+ AA747D9E0F9514B9006C5449 /* Physfs_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Physfs_Prefix.pch; sourceTree = SOURCE_ROOT; };
+ AACBBE490F95108600F1A2B1 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ D2AAC07C0554694100DB518D /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 034768DFFF38A50411DB9C8B /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 617D78E716D932600091D4D6 /* libPhysfs.a */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 0867D691FE84028FC02AAC07 /* Physfs */ = {
+ isa = PBXGroup;
+ children = (
+ 08FB77AEFE84172EC02AAC07 /* Sources */,
+ 32C88DFF0371C24200C91783 /* Other Sources */,
+ 0867D69AFE84028FC02AAC07 /* Frameworks */,
+ 034768DFFF38A50411DB9C8B /* Products */,
+ );
+ name = Physfs;
+ sourceTree = "";
+ };
+ 0867D69AFE84028FC02AAC07 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ AACBBE490F95108600F1A2B1 /* Foundation.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "";
+ };
+ 08FB77AEFE84172EC02AAC07 /* Sources */ = {
+ isa = PBXGroup;
+ children = (
+ 617D790A16D932BC0091D4D6 /* physfs_casefolding.h */,
+ 617D790B16D932BC0091D4D6 /* physfs_internal.h */,
+ 617D790C16D932BC0091D4D6 /* physfs_miniz.h */,
+ 617D790D16D932BC0091D4D6 /* physfs_platforms.h */,
+ 617D790E16D932BC0091D4D6 /* physfs.h */,
+ 617D78E816D932900091D4D6 /* archiver_dir.c */,
+ 617D78E916D932900091D4D6 /* archiver_grp.c */,
+ 617D78EA16D932900091D4D6 /* archiver_hog.c */,
+ 617D78EB16D932900091D4D6 /* archiver_iso9660.c */,
+ 617D78EC16D932900091D4D6 /* archiver_lzma.c */,
+ 617D78ED16D932900091D4D6 /* archiver_mvl.c */,
+ 617D78EE16D932900091D4D6 /* archiver_qpak.c */,
+ 617D78EF16D932900091D4D6 /* archiver_unpacked.c */,
+ 617D78F016D932900091D4D6 /* archiver_wad.c */,
+ 617D78F116D932900091D4D6 /* archiver_zip.c */,
+ 617D78F216D932900091D4D6 /* physfs_byteorder.c */,
+ 617D78F316D932900091D4D6 /* physfs_unicode.c */,
+ 617D78F416D932900091D4D6 /* physfs.c */,
+ 617D78F516D932900091D4D6 /* platform_macosx.c */,
+ 617D78F616D932900091D4D6 /* platform_posix.c */,
+ 617D78F716D932900091D4D6 /* platform_unix.c */,
+ 617D78F816D932900091D4D6 /* platform_windows.c */,
+ );
+ name = Sources;
+ sourceTree = "";
+ };
+ 32C88DFF0371C24200C91783 /* Other Sources */ = {
+ isa = PBXGroup;
+ children = (
+ AA747D9E0F9514B9006C5449 /* Physfs_Prefix.pch */,
+ );
+ name = "Other Sources";
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ D2AAC07A0554694100DB518D /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ AA747D9F0F9514B9006C5449 /* Physfs_Prefix.pch in Headers */,
+ 617D790F16D932BC0091D4D6 /* physfs_casefolding.h in Headers */,
+ 617D791016D932BC0091D4D6 /* physfs_internal.h in Headers */,
+ 617D791116D932BC0091D4D6 /* physfs_miniz.h in Headers */,
+ 617D791216D932BC0091D4D6 /* physfs_platforms.h in Headers */,
+ 617D791316D932BC0091D4D6 /* physfs.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ D2AAC07D0554694100DB518D /* Physfs */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "Physfs" */;
+ buildPhases = (
+ D2AAC07A0554694100DB518D /* Headers */,
+ D2AAC07B0554694100DB518D /* Sources */,
+ D2AAC07C0554694100DB518D /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Physfs;
+ productName = Physfs;
+ productReference = 617D78E716D932600091D4D6 /* libPhysfs.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 0867D690FE84028FC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "Physfs" */;
+ compatibilityVersion = "Xcode 3.1";
+ developmentRegion = English;
+ hasScannedForEncodings = 1;
+ knownRegions = (
+ English,
+ Japanese,
+ French,
+ German,
+ );
+ mainGroup = 0867D691FE84028FC02AAC07 /* Physfs */;
+ productRefGroup = 034768DFFF38A50411DB9C8B /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ D2AAC07D0554694100DB518D /* Physfs */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+ D2AAC07B0554694100DB518D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 617D78F916D932900091D4D6 /* archiver_dir.c in Sources */,
+ 617D78FA16D932900091D4D6 /* archiver_grp.c in Sources */,
+ 617D78FB16D932900091D4D6 /* archiver_hog.c in Sources */,
+ 617D78FC16D932900091D4D6 /* archiver_iso9660.c in Sources */,
+ 617D78FD16D932900091D4D6 /* archiver_lzma.c in Sources */,
+ 617D78FE16D932900091D4D6 /* archiver_mvl.c in Sources */,
+ 617D78FF16D932900091D4D6 /* archiver_qpak.c in Sources */,
+ 617D790016D932900091D4D6 /* archiver_unpacked.c in Sources */,
+ 617D790116D932900091D4D6 /* archiver_wad.c in Sources */,
+ 617D790216D932900091D4D6 /* archiver_zip.c in Sources */,
+ 617D790316D932900091D4D6 /* physfs_byteorder.c in Sources */,
+ 617D790416D932900091D4D6 /* physfs_unicode.c in Sources */,
+ 617D790516D932900091D4D6 /* physfs.c in Sources */,
+ 617D790616D932900091D4D6 /* platform_macosx.c in Sources */,
+ 617D790716D932900091D4D6 /* platform_posix.c in Sources */,
+ 617D790816D932900091D4D6 /* platform_unix.c in Sources */,
+ 617D790916D932900091D4D6 /* platform_windows.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 1DEB921F08733DC00010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ COPY_PHASE_STRIP = NO;
+ DSTROOT = /tmp/Physfs.dst;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = Physfs_Prefix.pch;
+ INSTALL_PATH = /usr/local/lib;
+ PRODUCT_NAME = Physfs;
+ };
+ name = Debug;
+ };
+ 1DEB922008733DC00010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ DSTROOT = /tmp/Physfs.dst;
+ GCC_MODEL_TUNING = G5;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = Physfs_Prefix.pch;
+ INSTALL_PATH = /usr/local/lib;
+ PRODUCT_NAME = Physfs;
+ };
+ name = Release;
+ };
+ 1DEB922308733DC00010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ GCC_C_LANGUAGE_STANDARD = c99;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = "";
+ GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ "\"$(SRCROOT)/../../liblua\"",
+ "\"$(SRCROOT)/../../../../Library/SDL/include\"",
+ );
+ OTHER_LDFLAGS = "-ObjC";
+ PREBINDING = NO;
+ SDKROOT = iphoneos;
+ };
+ name = Debug;
+ };
+ 1DEB922408733DC00010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ GCC_C_LANGUAGE_STANDARD = c99;
+ GCC_PREPROCESSOR_DEFINITIONS = "";
+ GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ "\"$(SRCROOT)/../../liblua\"",
+ "\"$(SRCROOT)/../../../../Library/SDL/include\"",
+ );
+ OTHER_LDFLAGS = "-ObjC";
+ PREBINDING = NO;
+ SDKROOT = iphoneos;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "Physfs" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB921F08733DC00010E9CD /* Debug */,
+ 1DEB922008733DC00010E9CD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "Physfs" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB922308733DC00010E9CD /* Debug */,
+ 1DEB922408733DC00010E9CD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 0867D690FE84028FC02AAC07 /* Project object */;
+}
diff -r 404ddce27b23 -r c13ebed437cb misc/libphysfs/Xcode/Physfs_Prefix.pch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/Xcode/Physfs_Prefix.pch Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,7 @@
+//
+// Prefix header for all source files of the 'CocoaTouchStaticLibrary' target in the 'CocoaTouchStaticLibrary' project.
+//
+
+#ifdef __OBJC__
+ #import
+#endif
diff -r 404ddce27b23 -r c13ebed437cb misc/libphysfs/archiver_dir.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/archiver_dir.c Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,201 @@
+/*
+ * Standard directory I/O support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ * This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+/* There's no PHYSFS_Io interface here. Use __PHYSFS_createNativeIo(). */
+
+
+
+static char *cvtToDependent(const char *prepend, const char *path, char *buf)
+{
+ BAIL_IF_MACRO(buf == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ sprintf(buf, "%s%s", prepend ? prepend : "", path);
+
+ if (__PHYSFS_platformDirSeparator != '/')
+ {
+ char *p;
+ for (p = strchr(buf, '/'); p != NULL; p = strchr(p + 1, '/'))
+ *p = __PHYSFS_platformDirSeparator;
+ } /* if */
+
+ return buf;
+} /* cvtToDependent */
+
+
+#define CVT_TO_DEPENDENT(buf, pre, dir) { \
+ const size_t len = ((pre) ? strlen((char *) pre) : 0) + strlen(dir) + 1; \
+ buf = cvtToDependent((char*)pre,dir,(char*)__PHYSFS_smallAlloc(len)); \
+}
+
+
+
+static void *DIR_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
+{
+ PHYSFS_Stat st;
+ const char dirsep = __PHYSFS_platformDirSeparator;
+ char *retval = NULL;
+ const size_t namelen = strlen(name);
+ const size_t seplen = 1;
+ int exists = 0;
+
+ assert(io == NULL); /* shouldn't create an Io for these. */
+ BAIL_IF_MACRO(!__PHYSFS_platformStat(name, &exists, &st), ERRPASS, NULL);
+ if (st.filetype != PHYSFS_FILETYPE_DIRECTORY)
+ BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL);
+
+ retval = allocator.Malloc(namelen + seplen + 1);
+ BAIL_IF_MACRO(retval == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+
+ strcpy(retval, name);
+
+ /* make sure there's a dir separator at the end of the string */
+ if (retval[namelen - 1] != dirsep)
+ {
+ retval[namelen] = dirsep;
+ retval[namelen + 1] = '\0';
+ } /* if */
+
+ return retval;
+} /* DIR_openArchive */
+
+
+static void DIR_enumerateFiles(PHYSFS_Dir *opaque, const char *dname,
+ int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+ const char *origdir, void *callbackdata)
+{
+ char *d;
+
+ CVT_TO_DEPENDENT(d, opaque, dname);
+ if (d != NULL)
+ {
+ __PHYSFS_platformEnumerateFiles(d, omitSymLinks, cb,
+ origdir, callbackdata);
+ __PHYSFS_smallFree(d);
+ } /* if */
+} /* DIR_enumerateFiles */
+
+
+static PHYSFS_Io *doOpen(PHYSFS_Dir *opaque, const char *name,
+ const int mode, int *fileExists)
+{
+ char *f;
+ PHYSFS_Io *io = NULL;
+ int existtmp = 0;
+
+ CVT_TO_DEPENDENT(f, opaque, name);
+ BAIL_IF_MACRO(!f, ERRPASS, NULL);
+
+ if (fileExists == NULL)
+ fileExists = &existtmp;
+
+ io = __PHYSFS_createNativeIo(f, mode);
+ if (io == NULL)
+ {
+ const PHYSFS_ErrorCode err = PHYSFS_getLastErrorCode();
+ PHYSFS_Stat statbuf;
+ __PHYSFS_platformStat(f, fileExists, &statbuf);
+ __PHYSFS_setError(err);
+ } /* if */
+ else
+ {
+ *fileExists = 1;
+ } /* else */
+
+ __PHYSFS_smallFree(f);
+
+ return io;
+} /* doOpen */
+
+
+static PHYSFS_Io *DIR_openRead(PHYSFS_Dir *opaque, const char *fnm, int *exist)
+{
+ return doOpen(opaque, fnm, 'r', exist);
+} /* DIR_openRead */
+
+
+static PHYSFS_Io *DIR_openWrite(PHYSFS_Dir *opaque, const char *filename)
+{
+ return doOpen(opaque, filename, 'w', NULL);
+} /* DIR_openWrite */
+
+
+static PHYSFS_Io *DIR_openAppend(PHYSFS_Dir *opaque, const char *filename)
+{
+ return doOpen(opaque, filename, 'a', NULL);
+} /* DIR_openAppend */
+
+
+static int DIR_remove(PHYSFS_Dir *opaque, const char *name)
+{
+ int retval;
+ char *f;
+
+ CVT_TO_DEPENDENT(f, opaque, name);
+ BAIL_IF_MACRO(!f, ERRPASS, 0);
+ retval = __PHYSFS_platformDelete(f);
+ __PHYSFS_smallFree(f);
+ return retval;
+} /* DIR_remove */
+
+
+static int DIR_mkdir(PHYSFS_Dir *opaque, const char *name)
+{
+ int retval;
+ char *f;
+
+ CVT_TO_DEPENDENT(f, opaque, name);
+ BAIL_IF_MACRO(!f, ERRPASS, 0);
+ retval = __PHYSFS_platformMkDir(f);
+ __PHYSFS_smallFree(f);
+ return retval;
+} /* DIR_mkdir */
+
+
+static void DIR_closeArchive(PHYSFS_Dir *opaque)
+{
+ allocator.Free(opaque);
+} /* DIR_closeArchive */
+
+
+static int DIR_stat(PHYSFS_Dir *opaque, const char *name,
+ int *exists, PHYSFS_Stat *stat)
+{
+ int retval = 0;
+ char *d;
+
+ CVT_TO_DEPENDENT(d, opaque, name);
+ BAIL_IF_MACRO(!d, ERRPASS, 0);
+ retval = __PHYSFS_platformStat(d, exists, stat);
+ __PHYSFS_smallFree(d);
+ return retval;
+} /* DIR_stat */
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_DIR =
+{
+ {
+ "",
+ "Non-archive, direct filesystem I/O",
+ "Ryan C. Gordon ",
+ "http://icculus.org/physfs/",
+ },
+ DIR_openArchive, /* openArchive() method */
+ DIR_enumerateFiles, /* enumerateFiles() method */
+ DIR_openRead, /* openRead() method */
+ DIR_openWrite, /* openWrite() method */
+ DIR_openAppend, /* openAppend() method */
+ DIR_remove, /* remove() method */
+ DIR_mkdir, /* mkdir() method */
+ DIR_closeArchive, /* closeArchive() method */
+ DIR_stat /* stat() method */
+};
+
+/* end of dir.c ... */
+
diff -r 404ddce27b23 -r c13ebed437cb misc/libphysfs/archiver_grp.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/archiver_grp.c Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,110 @@
+/*
+ * GRP support routines for PhysicsFS.
+ *
+ * This driver handles BUILD engine archives ("groupfiles"). This format
+ * (but not this driver) was put together by Ken Silverman.
+ *
+ * The format is simple enough. In Ken's words:
+ *
+ * What's the .GRP file format?
+ *
+ * The ".grp" file format is just a collection of a lot of files stored
+ * into 1 big one. I tried to make the format as simple as possible: The
+ * first 12 bytes contains my name, "KenSilverman". The next 4 bytes is
+ * the number of files that were compacted into the group file. Then for
+ * each file, there is a 16 byte structure, where the first 12 bytes are
+ * the filename, and the last 4 bytes are the file's size. The rest of
+ * the group file is just the raw data packed one after the other in the
+ * same order as the list of files.
+ *
+ * (That info is from http://www.advsys.net/ken/build.htm ...)
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ * This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+#if PHYSFS_SUPPORTS_GRP
+
+static UNPKentry *grpLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 fileCount)
+{
+ PHYSFS_uint32 location = 16; /* sizeof sig. */
+ UNPKentry *entries = NULL;
+ UNPKentry *entry = NULL;
+ char *ptr = NULL;
+
+ entries = (UNPKentry *) allocator.Malloc(sizeof (UNPKentry) * fileCount);
+ BAIL_IF_MACRO(entries == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+
+ location += (16 * fileCount);
+
+ for (entry = entries; fileCount > 0; fileCount--, entry++)
+ {
+ GOTO_IF_MACRO(!__PHYSFS_readAll(io, &entry->name, 12), ERRPASS, failed);
+ GOTO_IF_MACRO(!__PHYSFS_readAll(io, &entry->size, 4), ERRPASS, failed);
+ entry->name[12] = '\0'; /* name isn't null-terminated in file. */
+ if ((ptr = strchr(entry->name, ' ')) != NULL)
+ *ptr = '\0'; /* trim extra spaces. */
+
+ entry->size = PHYSFS_swapULE32(entry->size);
+ entry->startPos = location;
+ location += entry->size;
+ } /* for */
+
+ return entries;
+
+failed:
+ allocator.Free(entries);
+ return NULL;
+} /* grpLoadEntries */
+
+
+static void *GRP_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
+{
+ PHYSFS_uint8 buf[12];
+ PHYSFS_uint32 count = 0;
+ UNPKentry *entries = NULL;
+
+ assert(io != NULL); /* shouldn't ever happen. */
+
+ BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
+
+ BAIL_IF_MACRO(!__PHYSFS_readAll(io, buf, sizeof (buf)), ERRPASS, NULL);
+ if (memcmp(buf, "KenSilverman", sizeof (buf)) != 0)
+ BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL);
+
+ BAIL_IF_MACRO(!__PHYSFS_readAll(io, &count, sizeof(count)), ERRPASS, NULL);
+ count = PHYSFS_swapULE32(count);
+
+ entries = grpLoadEntries(io, count);
+ BAIL_IF_MACRO(!entries, ERRPASS, NULL);
+ return UNPK_openArchive(io, entries, count);
+} /* GRP_openArchive */
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_GRP =
+{
+ {
+ "GRP",
+ "Build engine Groupfile format",
+ "Ryan C. Gordon ",
+ "http://icculus.org/physfs/",
+ },
+ GRP_openArchive, /* openArchive() method */
+ UNPK_enumerateFiles, /* enumerateFiles() method */
+ UNPK_openRead, /* openRead() method */
+ UNPK_openWrite, /* openWrite() method */
+ UNPK_openAppend, /* openAppend() method */
+ UNPK_remove, /* remove() method */
+ UNPK_mkdir, /* mkdir() method */
+ UNPK_closeArchive, /* closeArchive() method */
+ UNPK_stat /* stat() method */
+};
+
+#endif /* defined PHYSFS_SUPPORTS_GRP */
+
+/* end of grp.c ... */
+
diff -r 404ddce27b23 -r c13ebed437cb misc/libphysfs/archiver_hog.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/archiver_hog.c Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,116 @@
+/*
+ * HOG support routines for PhysicsFS.
+ *
+ * This driver handles Descent I/II HOG archives.
+ *
+ * The format is very simple:
+ *
+ * The file always starts with the 3-byte signature "DHF" (Descent
+ * HOG file). After that the files of a HOG are just attached after
+ * another, divided by a 17 bytes header, which specifies the name
+ * and length (in bytes) of the forthcoming file! So you just read
+ * the header with its information of how big the following file is,
+ * and then skip exact that number of bytes to get to the next file
+ * in that HOG.
+ *
+ * char sig[3] = {'D', 'H', 'F'}; // "DHF"=Descent HOG File
+ *
+ * struct {
+ * char file_name[13]; // Filename, padded to 13 bytes with 0s
+ * int file_size; // filesize in bytes
+ * char data[file_size]; // The file data
+ * } FILE_STRUCT; // Repeated until the end of the file.
+ *
+ * (That info is from http://www.descent2.com/ddn/specs/hog/)
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ * This file written by Bradley Bell.
+ * Based on grp.c by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+#if PHYSFS_SUPPORTS_HOG
+
+static UNPKentry *hogLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 *_entCount)
+{
+ const PHYSFS_uint64 iolen = io->length(io);
+ PHYSFS_uint32 entCount = 0;
+ void *ptr = NULL;
+ UNPKentry *entries = NULL;
+ UNPKentry *entry = NULL;
+ PHYSFS_uint32 size = 0;
+ PHYSFS_uint32 pos = 3;
+
+ while (pos < iolen)
+ {
+ entCount++;
+ ptr = allocator.Realloc(ptr, sizeof (UNPKentry) * entCount);
+ GOTO_IF_MACRO(ptr == NULL, PHYSFS_ERR_OUT_OF_MEMORY, failed);
+ entries = (UNPKentry *) ptr;
+ entry = &entries[entCount-1];
+
+ GOTO_IF_MACRO(!__PHYSFS_readAll(io, &entry->name, 13), ERRPASS, failed);
+ pos += 13;
+ GOTO_IF_MACRO(!__PHYSFS_readAll(io, &size, 4), ERRPASS, failed);
+ pos += 4;
+
+ entry->size = PHYSFS_swapULE32(size);
+ entry->startPos = pos;
+ pos += size;
+
+ /* skip over entry */
+ GOTO_IF_MACRO(!io->seek(io, pos), ERRPASS, failed);
+ } /* while */
+
+ *_entCount = entCount;
+ return entries;
+
+failed:
+ allocator.Free(entries);
+ return NULL;
+} /* hogLoadEntries */
+
+
+static void *HOG_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
+{
+ PHYSFS_uint8 buf[3];
+ PHYSFS_uint32 count = 0;
+ UNPKentry *entries = NULL;
+
+ assert(io != NULL); /* shouldn't ever happen. */
+ BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
+ BAIL_IF_MACRO(!__PHYSFS_readAll(io, buf, 3), ERRPASS, NULL);
+ BAIL_IF_MACRO(memcmp(buf, "DHF", 3) != 0, PHYSFS_ERR_UNSUPPORTED, NULL);
+
+ entries = hogLoadEntries(io, &count);
+ BAIL_IF_MACRO(!entries, ERRPASS, NULL);
+ return UNPK_openArchive(io, entries, count);
+} /* HOG_openArchive */
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_HOG =
+{
+ {
+ "HOG",
+ "Descent I/II HOG file format",
+ "Bradley Bell ",
+ "http://icculus.org/physfs/",
+ },
+ HOG_openArchive, /* openArchive() method */
+ UNPK_enumerateFiles, /* enumerateFiles() method */
+ UNPK_openRead, /* openRead() method */
+ UNPK_openWrite, /* openWrite() method */
+ UNPK_openAppend, /* openAppend() method */
+ UNPK_remove, /* remove() method */
+ UNPK_mkdir, /* mkdir() method */
+ UNPK_closeArchive, /* closeArchive() method */
+ UNPK_stat /* stat() method */
+};
+
+#endif /* defined PHYSFS_SUPPORTS_HOG */
+
+/* end of hog.c ... */
+
diff -r 404ddce27b23 -r c13ebed437cb misc/libphysfs/archiver_iso9660.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/archiver_iso9660.c Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,969 @@
+/*
+ * ISO9660 support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ * This file written by Christoph Nelles.
+ */
+
+/* !!! FIXME: this file needs Ryanification. */
+
+/*
+ * Handles CD-ROM disk images (and raw CD-ROM devices).
+ *
+ * Not supported:
+ * - RockRidge
+ * - Non 2048 Sectors
+ * - UDF
+ *
+ * Deviations from the standard
+ * - Ignores mandatory sort order
+ * - Allows various invalid file names
+ *
+ * Problems
+ * - Ambiguities in the standard
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+#if PHYSFS_SUPPORTS_ISO9660
+
+#include
+
+/* cache files smaller than this completely in memory */
+#define ISO9660_FULLCACHEMAXSIZE 2048
+
+/* !!! FIXME: this is going to cause trouble. */
+#pragma pack(push) /* push current alignment to stack */
+#pragma pack(1) /* set alignment to 1 byte boundary */
+
+/* This is the format as defined by the standard
+typedef struct
+{
+ PHYSFS_uint32 lsb;
+ PHYSFS_uint32 msb;
+} ISOBB32bit; // 32byte Both Byte type, means the value first in LSB then in MSB
+
+typedef struct
+{
+ PHYSFS_uint16 lsb;
+ PHYSFS_uint16 msb;
+} ISOBB16bit; // 16byte Both Byte type, means the value first in LSB then in MSB
+*/
+
+/* define better ones to simplify coding (less if's) */
+#if PHYSFS_BYTEORDER == PHYSFS_LIL_ENDIAN
+#define ISOBB32bit(name) PHYSFS_uint32 name; PHYSFS_uint32 __dummy_##name;
+#define ISOBB16bit(name) PHYSFS_uint16 name; PHYSFS_uint16 __dummy_##name;
+#else
+#define ISOBB32bit(name) PHYSFS_uint32 __dummy_##name; PHYSFS_uint32 name;
+#define ISOBB16bit(name) PHYSFS_uint16 __dummy_##name; PHYSFS_uint16 name;
+#endif
+
+typedef struct
+{
+ char year[4];
+ char month[2];
+ char day[2];
+ char hour[2];
+ char minute[2];
+ char second[2];
+ char centisec[2];
+ PHYSFS_sint8 offset; /* in 15min from GMT */
+} ISO9660VolumeTimestamp;
+
+typedef struct
+{
+ PHYSFS_uint8 year;
+ PHYSFS_uint8 month;
+ PHYSFS_uint8 day;
+ PHYSFS_uint8 hour;
+ PHYSFS_uint8 minute;
+ PHYSFS_uint8 second;
+ PHYSFS_sint8 offset;
+} ISO9660FileTimestamp;
+
+typedef struct
+{
+ unsigned existence:1;
+ unsigned directory:1;
+ unsigned associated_file:1;
+ unsigned record:1;
+ unsigned protection:1;
+ unsigned reserved:2;
+ unsigned multiextent:1;
+} ISO9660FileFlags;
+
+typedef struct
+{
+ PHYSFS_uint8 length;
+ PHYSFS_uint8 attribute_length;
+ ISOBB32bit(extent_location)
+ ISOBB32bit(data_length)
+ ISO9660FileTimestamp timestamp;
+ ISO9660FileFlags file_flags;
+ PHYSFS_uint8 file_unit_size;
+ PHYSFS_uint8 gap_size;
+ ISOBB16bit(vol_seq_no)
+ PHYSFS_uint8 len_fi;
+ char unused;
+} ISO9660RootDirectoryRecord;
+
+/* this structure is combined for all Volume descriptor types */
+typedef struct
+{
+ PHYSFS_uint8 type;
+ char identifier[5];
+ PHYSFS_uint8 version;
+ PHYSFS_uint8 flags;
+ char system_identifier[32];
+ char volume_identifier[32];
+ char unused2[8];
+ ISOBB32bit(space_size)
+ PHYSFS_uint8 escape_sequences[32];
+ ISOBB16bit(vol_set_size)
+ ISOBB16bit(vol_seq_no)
+ ISOBB16bit(block_size)
+ ISOBB32bit(path_table_size)
+/* PHYSFS_uint32 path_table_start_lsb; // why didn't they use both byte type?
+ PHYSFS_uint32 opt_path_table_start_lsb;
+ PHYSFS_uint32 path_table_start_msb;
+ PHYSFS_uint32 opt_path_table_start_msb;*/
+#if PHYSFS_BYTEORDER == PHYSFS_LIL_ENDIAN
+ PHYSFS_uint32 path_table_start;
+ PHYSFS_uint32 opt_path_table_start;
+ PHYSFS_uint32 unused6;
+ PHYSFS_uint32 unused7;
+#else
+ PHYSFS_uint32 unused6;
+ PHYSFS_uint32 unused7;
+ PHYSFS_uint32 path_table_start;
+ PHYSFS_uint32 opt_path_table_start;
+#endif
+ ISO9660RootDirectoryRecord rootdirectory;
+ char set_identifier[128];
+ char publisher_identifier[128];
+ char preparer_identifer[128];
+ char application_identifier[128];
+ char copyright_file_identifier[37];
+ char abstract_file_identifier[37];
+ char bibliographic_file_identifier[37];
+ ISO9660VolumeTimestamp creation_timestamp;
+ ISO9660VolumeTimestamp modification_timestamp;
+ ISO9660VolumeTimestamp expiration_timestamp;
+ ISO9660VolumeTimestamp effective_timestamp;
+ PHYSFS_uint8 file_structure_version;
+ char unused4;
+ char application_use[512];
+ char unused5[653];
+} ISO9660VolumeDescriptor;
+
+typedef struct
+{
+ PHYSFS_uint8 recordlen;
+ PHYSFS_uint8 extattributelen;
+ ISOBB32bit(extentpos)
+ ISOBB32bit(datalen)
+ ISO9660FileTimestamp recordtime;
+ ISO9660FileFlags flags;
+ PHYSFS_uint8 file_unit_size;
+ PHYSFS_uint8 interleave_gap;
+ ISOBB16bit(volseqno)
+ PHYSFS_uint8 filenamelen;
+ char filename[222]; /* This is not exact, but makes reading easier */
+} ISO9660FileDescriptor;
+
+typedef struct
+{
+ ISOBB16bit(owner)
+ ISOBB16bit(group)
+ PHYSFS_uint16 flags; /* not implemented*/
+ ISO9660VolumeTimestamp create_time; /* yes, not file timestamp */
+ ISO9660VolumeTimestamp mod_time;
+ ISO9660VolumeTimestamp expire_time;
+ ISO9660VolumeTimestamp effective_time;
+ PHYSFS_uint8 record_format;
+ PHYSFS_uint8 record_attributes;
+ ISOBB16bit(record_len)
+ char system_identifier[32];
+ char system_use[64];
+ PHYSFS_uint8 version;
+ ISOBB16bit(escape_len)
+ char reserved[64];
+ /** further fields not implemented */
+} ISO9660ExtAttributeRec;
+
+#pragma pack(pop) /* restore original alignment from stack */
+
+typedef struct
+{
+ PHYSFS_Io *io;
+ PHYSFS_uint32 rootdirstart;
+ PHYSFS_uint32 rootdirsize;
+ PHYSFS_uint64 currpos;
+ int isjoliet;
+ char *path;
+ void *mutex;
+} ISO9660Handle;
+
+
+typedef struct __ISO9660FileHandle
+{
+ PHYSFS_sint64 filesize;
+ PHYSFS_uint64 currpos;
+ PHYSFS_uint64 startblock;
+ ISO9660Handle *isohandle;
+ PHYSFS_uint32 (*read) (struct __ISO9660FileHandle *filehandle, void *buffer,
+ PHYSFS_uint64 len);
+ int (*seek)(struct __ISO9660FileHandle *filehandle, PHYSFS_sint64 offset);
+ void (*close)(struct __ISO9660FileHandle *filehandle);
+ /* !!! FIXME: anonymouse union is going to cause problems. */
+ union
+ {
+ /* !!! FIXME: just use a memory PHYSFS_Io here, unify all this code. */
+ char *cacheddata; /* data of file when cached */
+ PHYSFS_Io *io; /* handle to separate opened file */
+ };
+} ISO9660FileHandle;
+
+/*******************************************************************************
+ * Time conversion functions
+ ******************************************************************************/
+
+static PHYSFS_sint64 iso_mktime(ISO9660FileTimestamp *timestamp)
+{
+ struct tm tm;
+ tm.tm_year = timestamp->year;
+ tm.tm_mon = timestamp->month - 1;
+ tm.tm_mday = timestamp->day;
+ tm.tm_hour = timestamp->hour;
+ tm.tm_min = timestamp->minute;
+ tm.tm_sec = timestamp->second;
+ /* Ignore GMT offset for now... */
+ return mktime(&tm);
+} /* iso_mktime */
+
+static int iso_atoi2(char *text)
+{
+ return ((text[0] - 40) * 10) + (text[1] - 40);
+} /* iso_atoi2 */
+
+static int iso_atoi4(char *text)
+{
+ return ((text[0] - 40) * 1000) + ((text[1] - 40) * 100) +
+ ((text[2] - 40) * 10) + (text[3] - 40);
+} /* iso_atoi4 */
+
+static PHYSFS_sint64 iso_volume_mktime(ISO9660VolumeTimestamp *timestamp)
+{
+ struct tm tm;
+ tm.tm_year = iso_atoi4(timestamp->year);
+ tm.tm_mon = iso_atoi2(timestamp->month) - 1;
+ tm.tm_mday = iso_atoi2(timestamp->day);
+ tm.tm_hour = iso_atoi2(timestamp->hour);
+ tm.tm_min = iso_atoi2(timestamp->minute);
+ tm.tm_sec = iso_atoi2(timestamp->second);
+ /* this allows values outside the range of a unix timestamp... sanitize them */
+ PHYSFS_sint64 value = mktime(&tm);
+ return value == -1 ? 0 : value;
+} /* iso_volume_mktime */
+
+/*******************************************************************************
+ * Filename extraction
+ ******************************************************************************/
+
+static int iso_extractfilenameISO(ISO9660FileDescriptor *descriptor,
+ char *filename, int *version)
+{
+ *filename = '\0';
+ if (descriptor->flags.directory)
+ {
+ strncpy(filename, descriptor->filename, descriptor->filenamelen);
+ filename[descriptor->filenamelen] = '\0';
+ *version = 0;
+ } /* if */
+ else
+ {
+ /* find last SEPARATOR2 */
+ int pos = 0;
+ int lastfound = -1;
+ for(;pos < descriptor->filenamelen; pos++)
+ if (descriptor->filename[pos] == ';')
+ lastfound = pos;
+ BAIL_IF_MACRO(lastfound < 1, PHYSFS_ERR_NO_SUCH_PATH /* !!! FIXME: PHYSFS_ERR_BAD_FILENAME */, -1);
+ BAIL_IF_MACRO(lastfound == (descriptor->filenamelen -1), PHYSFS_ERR_NO_SUCH_PATH /* !!! PHYSFS_ERR_BAD_FILENAME */, -1);
+ strncpy(filename, descriptor->filename, lastfound);
+ if (filename[lastfound - 1] == '.')
+ filename[lastfound - 1] = '\0'; /* consume trailing ., as done in all implementations */
+ else
+ filename[lastfound] = '\0';
+ *version = atoi(descriptor->filename + lastfound);
+ } /* else */
+
+ return 0;
+} /* iso_extractfilenameISO */
+
+
+static int iso_extractfilenameUCS2(ISO9660FileDescriptor *descriptor,
+ char *filename, int *version)
+{
+ PHYSFS_uint16 tmp[128];
+ PHYSFS_uint16 *src;
+ int len;
+
+ *filename = '\0';
+ *version = 1; /* Joliet does not have versions.. at least not on my images */
+
+ src = (PHYSFS_uint16*) descriptor->filename;
+ len = descriptor->filenamelen / 2;
+ tmp[len] = 0;
+
+ while(len--)
+ tmp[len] = PHYSFS_swapUBE16(src[len]);
+
+ PHYSFS_utf8FromUcs2(tmp, filename, 255);
+
+ return 0;
+} /* iso_extractfilenameUCS2 */
+
+
+static int iso_extractfilename(ISO9660Handle *handle,
+ ISO9660FileDescriptor *descriptor, char *filename,int *version)
+{
+ if (handle->isjoliet)
+ return iso_extractfilenameUCS2(descriptor, filename, version);
+ else
+ return iso_extractfilenameISO(descriptor, filename, version);
+} /* iso_extractfilename */
+
+/*******************************************************************************
+ * Basic image read functions
+ ******************************************************************************/
+
+static int iso_readimage(ISO9660Handle *handle, PHYSFS_uint64 where,
+ void *buffer, PHYSFS_uint64 len)
+{
+ BAIL_IF_MACRO(!__PHYSFS_platformGrabMutex(handle->mutex), ERRPASS, -1);
+ int rc = -1;
+ if (where != handle->currpos)
+ GOTO_IF_MACRO(!handle->io->seek(handle->io,where), ERRPASS, unlockme);
+ rc = handle->io->read(handle->io, buffer, len);
+ if (rc == -1)
+ {
+ handle->currpos = (PHYSFS_uint64) -1;
+ goto unlockme;
+ } /* if */
+ handle->currpos += rc;
+
+ unlockme:
+ __PHYSFS_platformReleaseMutex(handle->mutex);
+ return rc;
+} /* iso_readimage */
+
+
+static PHYSFS_sint64 iso_readfiledescriptor(ISO9660Handle *handle,
+ PHYSFS_uint64 where,
+ ISO9660FileDescriptor *descriptor)
+{
+ PHYSFS_sint64 rc = iso_readimage(handle, where, descriptor,
+ sizeof (descriptor->recordlen));
+ BAIL_IF_MACRO(rc == -1, ERRPASS, -1);
+ BAIL_IF_MACRO(rc != 1, PHYSFS_ERR_CORRUPT, -1);
+
+ if (descriptor->recordlen == 0)
+ return 0; /* fill bytes at the end of a sector */
+
+ rc = iso_readimage(handle, where + 1, &descriptor->extattributelen,
+ descriptor->recordlen - sizeof(descriptor->recordlen));
+ BAIL_IF_MACRO(rc == -1, ERRPASS, -1);
+ BAIL_IF_MACRO(rc != 1, PHYSFS_ERR_CORRUPT, -1);
+
+ return 0;
+} /* iso_readfiledescriptor */
+
+static void iso_extractsubpath(char *path, char **subpath)
+{
+ *subpath = strchr(path,'/');
+ if (*subpath != 0)
+ {
+ **subpath = 0;
+ *subpath +=1;
+ } /* if */
+} /* iso_extractsubpath */
+
+/*
+ * Don't use path tables, they are not necessarily faster, but more complicated
+ * to implement as they store only directories and not files, so searching for
+ * a file needs to branch to the directory extent sooner or later.
+ */
+static int iso_find_dir_entry(ISO9660Handle *handle,const char *path,
+ ISO9660FileDescriptor *descriptor, int *exists)
+{
+ char *subpath = 0;
+ PHYSFS_uint64 readpos, end_of_dir;
+ char filename[255];
+ char pathcopy[256];
+ char *mypath;
+ int version = 0;
+
+ strcpy(pathcopy, path);
+ mypath = pathcopy;
+ *exists = 0;
+
+ readpos = handle->rootdirstart;
+ end_of_dir = handle->rootdirstart + handle->rootdirsize;
+ iso_extractsubpath(mypath, &subpath);
+ while (1)
+ {
+ BAIL_IF_MACRO(iso_readfiledescriptor(handle, readpos, descriptor), ERRPASS, -1);
+
+ /* recordlen = 0 -> no more entries or fill entry */
+ if (!descriptor->recordlen)
+ {
+ /* if we are in the last sector of the directory & it's 0 -> end */
+ if ((end_of_dir - 2048) <= (readpos -1))
+ break; /* finished */
+
+ /* else skip to the next sector & continue; */
+ readpos = (((readpos - 1) / 2048) + 1) * 2048;
+ continue;
+ } /* if */
+
+ readpos += descriptor->recordlen;
+ if (descriptor->filenamelen == 1 && (descriptor->filename[0] == 0
+ || descriptor->filename[0] == 1))
+ continue; /* special ones, ignore */
+
+ BAIL_IF_MACRO(
+ iso_extractfilename(handle, descriptor, filename, &version),
+ ERRPASS, -1);
+
+ if (strcmp(filename, mypath) == 0)
+ {
+ if ( (subpath == 0) || (subpath[0] == 0) )
+ {
+ *exists = 1;
+ return 0; /* no subpaths left and we found the entry */
+ } /* if */
+
+ if (descriptor->flags.directory)
+ {
+ /* shorten the path to the subpath */
+ mypath = subpath;
+ iso_extractsubpath(mypath, &subpath);
+ /* gosub to the new directory extent */
+ readpos = descriptor->extentpos * 2048;
+ end_of_dir = readpos + descriptor->datalen;
+ } /* if */
+ else
+ {
+ /* we're at a file but have a remaining subpath -> no match */
+ return 0;
+ } /* else */
+ } /* if */
+ } /* while */
+
+ return 0;
+} /* iso_find_dir_entry */
+
+
+static int iso_read_ext_attributes(ISO9660Handle *handle, int block,
+ ISO9660ExtAttributeRec *attributes)
+{
+ return iso_readimage(handle, block * 2048, attributes,
+ sizeof(ISO9660ExtAttributeRec));
+} /* iso_read_ext_attributes */
+
+
+static int ISO9660_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
+
+static PHYSFS_Io *ISO9660_duplicate(PHYSFS_Io *_io)
+{
+ BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL); /* !!! FIXME: write me. */
+} /* ISO9660_duplicate */
+
+
+static void ISO9660_destroy(PHYSFS_Io *io)
+{
+ ISO9660FileHandle *fhandle = (ISO9660FileHandle*) io->opaque;
+ fhandle->close(fhandle);
+ allocator.Free(io);
+} /* ISO9660_destroy */
+
+
+static PHYSFS_sint64 ISO9660_read(PHYSFS_Io *io, void *buf, PHYSFS_uint64 len)
+{
+ ISO9660FileHandle *fhandle = (ISO9660FileHandle*) io->opaque;
+ return fhandle->read(fhandle, buf, len);
+} /* ISO9660_read */
+
+
+static PHYSFS_sint64 ISO9660_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 l)
+{
+ BAIL_MACRO(PHYSFS_ERR_READ_ONLY, -1);
+} /* ISO9660_write */
+
+
+static PHYSFS_sint64 ISO9660_tell(PHYSFS_Io *io)
+{
+ return ((ISO9660FileHandle*) io->opaque)->currpos;
+} /* ISO9660_tell */
+
+
+static int ISO9660_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
+{
+ ISO9660FileHandle *fhandle = (ISO9660FileHandle*) io->opaque;
+ return fhandle->seek(fhandle, offset);
+} /* ISO9660_seek */
+
+
+static PHYSFS_sint64 ISO9660_length(PHYSFS_Io *io)
+{
+ return ((ISO9660FileHandle*) io->opaque)->filesize;
+} /* ISO9660_length */
+
+
+static const PHYSFS_Io ISO9660_Io =
+{
+ CURRENT_PHYSFS_IO_API_VERSION, NULL,
+ ISO9660_read,
+ ISO9660_write,
+ ISO9660_seek,
+ ISO9660_tell,
+ ISO9660_length,
+ ISO9660_duplicate,
+ ISO9660_flush,
+ ISO9660_destroy
+};
+
+
+/*******************************************************************************
+ * Archive management functions
+ ******************************************************************************/
+
+static void *ISO9660_openArchive(PHYSFS_Io *io, const char *filename, int forWriting)
+{
+ char magicnumber[6];
+ ISO9660Handle *handle;
+ int founddescriptor = 0;
+ int foundjoliet = 0;
+
+ assert(io != NULL); /* shouldn't ever happen. */
+
+ BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
+
+ /* Skip system area to magic number in Volume descriptor */
+ BAIL_IF_MACRO(!io->seek(io, 32769), ERRPASS, NULL);
+ BAIL_IF_MACRO(!io->read(io, magicnumber, 5) != 5, ERRPASS, NULL);
+ if (memcmp(magicnumber, "CD001", 6) != 0)
+ BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL);
+
+ handle = allocator.Malloc(sizeof(ISO9660Handle));
+ GOTO_IF_MACRO(!handle, PHYSFS_ERR_OUT_OF_MEMORY, errorcleanup);
+ handle->path = 0;
+ handle->mutex= 0;
+ handle->io = NULL;
+
+ handle->path = allocator.Malloc(strlen(filename) + 1);
+ GOTO_IF_MACRO(!handle->path, PHYSFS_ERR_OUT_OF_MEMORY, errorcleanup);
+ strcpy(handle->path, filename);
+
+ handle->mutex = __PHYSFS_platformCreateMutex();
+ GOTO_IF_MACRO(!handle->mutex, ERRPASS, errorcleanup);
+
+ handle->io = io;
+
+ /* seek Primary Volume Descriptor */
+ GOTO_IF_MACRO(!io->seek(io, 32768), PHYSFS_ERR_IO, errorcleanup);
+
+ while (1)
+ {
+ ISO9660VolumeDescriptor descriptor;
+ GOTO_IF_MACRO(io->read(io, &descriptor, sizeof(ISO9660VolumeDescriptor)) != sizeof(ISO9660VolumeDescriptor), PHYSFS_ERR_IO, errorcleanup);
+ GOTO_IF_MACRO(strncmp(descriptor.identifier, "CD001", 5) != 0, PHYSFS_ERR_UNSUPPORTED, errorcleanup);
+
+ if (descriptor.type == 255)
+ {
+ /* type 255 terminates the volume descriptor list */
+ if (founddescriptor)
+ return handle; /* ok, we've found one volume descriptor */
+ else
+ GOTO_MACRO(PHYSFS_ERR_CORRUPT, errorcleanup);
+ } /* if */
+ if (descriptor.type == 1 && !founddescriptor)
+ {
+ handle->currpos = io->tell(io);
+ handle->rootdirstart =
+ descriptor.rootdirectory.extent_location * 2048;
+ handle->rootdirsize =
+ descriptor.rootdirectory.data_length;
+ handle->isjoliet = 0;
+ founddescriptor = 1; /* continue search for joliet */
+ } /* if */
+ if (descriptor.type == 2 && !foundjoliet)
+ {
+ /* check if is joliet */
+ PHYSFS_uint8 *s = descriptor.escape_sequences;
+ int joliet = !(descriptor.flags & 1)
+ && (s[0] == 0x25)
+ && (s[1] == 0x2F)
+ && ((s[2] == 0x40) || (s[2] == 0x43) || (s[2] == 0x45));
+ if (!joliet)
+ continue;
+
+ handle->currpos = io->tell(io);
+ handle->rootdirstart =
+ descriptor.rootdirectory.extent_location * 2048;
+ handle->rootdirsize =
+ descriptor.rootdirectory.data_length;
+ handle->isjoliet = 1;
+ founddescriptor = 1;
+ foundjoliet = 1;
+ } /* if */
+ } /* while */
+
+ GOTO_MACRO(PHYSFS_ERR_CORRUPT, errorcleanup); /* not found. */
+
+errorcleanup:
+ if (handle)
+ {
+ if (handle->path)
+ allocator.Free(handle->path);
+ if (handle->mutex)
+ __PHYSFS_platformDestroyMutex(handle->mutex);
+ allocator.Free(handle);
+ } /* if */
+ return NULL;
+} /* ISO9660_openArchive */
+
+
+static void ISO9660_closeArchive(PHYSFS_Dir *opaque)
+{
+ ISO9660Handle *handle = (ISO9660Handle*) opaque;
+ handle->io->destroy(handle->io);
+ __PHYSFS_platformDestroyMutex(handle->mutex);
+ allocator.Free(handle->path);
+ allocator.Free(handle);
+} /* ISO9660_closeArchive */
+
+
+/*******************************************************************************
+ * Read functions
+ ******************************************************************************/
+
+
+static PHYSFS_uint32 iso_file_read_mem(ISO9660FileHandle *filehandle,
+ void *buffer, PHYSFS_uint64 len)
+{
+ /* check remaining bytes & max obj which can be fetched */
+ const PHYSFS_sint64 bytesleft = filehandle->filesize - filehandle->currpos;
+ if (bytesleft < len)
+ len = bytesleft;
+
+ if (len == 0)
+ return 0;
+
+ memcpy(buffer, filehandle->cacheddata + filehandle->currpos, (size_t) len);
+
+ filehandle->currpos += len;
+ return (PHYSFS_uint32) len;
+} /* iso_file_read_mem */
+
+
+static int iso_file_seek_mem(ISO9660FileHandle *fhandle, PHYSFS_sint64 offset)
+{
+ BAIL_IF_MACRO(offset < 0, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+ BAIL_IF_MACRO(offset >= fhandle->filesize, PHYSFS_ERR_PAST_EOF, 0);
+
+ fhandle->currpos = offset;
+ return 0;
+} /* iso_file_seek_mem */
+
+
+static void iso_file_close_mem(ISO9660FileHandle *fhandle)
+{
+ allocator.Free(fhandle->cacheddata);
+ allocator.Free(fhandle);
+} /* iso_file_close_mem */
+
+
+static PHYSFS_uint32 iso_file_read_foreign(ISO9660FileHandle *filehandle,
+ void *buffer, PHYSFS_uint64 len)
+{
+ /* check remaining bytes & max obj which can be fetched */
+ const PHYSFS_sint64 bytesleft = filehandle->filesize - filehandle->currpos;
+ if (bytesleft < len)
+ len = bytesleft;
+
+ const PHYSFS_sint64 rc = filehandle->io->read(filehandle->io, buffer, len);
+ BAIL_IF_MACRO(rc == -1, ERRPASS, -1);
+
+ filehandle->currpos += rc; /* i trust my internal book keeping */
+ BAIL_IF_MACRO(rc < len, PHYSFS_ERR_CORRUPT, -1);
+ return rc;
+} /* iso_file_read_foreign */
+
+
+static int iso_file_seek_foreign(ISO9660FileHandle *fhandle,
+ PHYSFS_sint64 offset)
+{
+ BAIL_IF_MACRO(offset < 0, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+ BAIL_IF_MACRO(offset >= fhandle->filesize, PHYSFS_ERR_PAST_EOF, 0);
+
+ PHYSFS_sint64 pos = fhandle->startblock * 2048 + offset;
+ BAIL_IF_MACRO(!fhandle->io->seek(fhandle->io, pos), ERRPASS, -1);
+
+ fhandle->currpos = offset;
+ return 0;
+} /* iso_file_seek_foreign */
+
+
+static void iso_file_close_foreign(ISO9660FileHandle *fhandle)
+{
+ fhandle->io->destroy(fhandle->io);
+ allocator.Free(fhandle);
+} /* iso_file_close_foreign */
+
+
+static int iso_file_open_mem(ISO9660Handle *handle, ISO9660FileHandle *fhandle)
+{
+ fhandle->cacheddata = allocator.Malloc(fhandle->filesize);
+ BAIL_IF_MACRO(!fhandle->cacheddata, PHYSFS_ERR_OUT_OF_MEMORY, -1);
+ int rc = iso_readimage(handle, fhandle->startblock * 2048,
+ fhandle->cacheddata, fhandle->filesize);
+ GOTO_IF_MACRO(rc < 0, ERRPASS, freemem);
+ GOTO_IF_MACRO(rc == 0, PHYSFS_ERR_CORRUPT, freemem);
+
+ fhandle->read = iso_file_read_mem;
+ fhandle->seek = iso_file_seek_mem;
+ fhandle->close = iso_file_close_mem;
+ return 0;
+
+freemem:
+ allocator.Free(fhandle->cacheddata);
+ return -1;
+} /* iso_file_open_mem */
+
+
+static int iso_file_open_foreign(ISO9660Handle *handle,
+ ISO9660FileHandle *fhandle)
+{
+ int rc;
+ fhandle->io = __PHYSFS_createNativeIo(handle->path, 'r');
+ BAIL_IF_MACRO(!fhandle->io, ERRPASS, -1);
+ rc = fhandle->io->seek(fhandle->io, fhandle->startblock * 2048);
+ GOTO_IF_MACRO(!rc, ERRPASS, closefile);
+
+ fhandle->read = iso_file_read_foreign;
+ fhandle->seek = iso_file_seek_foreign;
+ fhandle->close = iso_file_close_foreign;
+ return 0;
+
+closefile:
+ fhandle->io->destroy(fhandle->io);
+ return -1;
+} /* iso_file_open_foreign */
+
+
+static PHYSFS_Io *ISO9660_openRead(PHYSFS_Dir *opaque, const char *filename,
+ int *exists)
+{
+ PHYSFS_Io *retval = NULL;
+ ISO9660Handle *handle = (ISO9660Handle*) opaque;
+ ISO9660FileHandle *fhandle;
+ ISO9660FileDescriptor descriptor;
+ int rc;
+
+ fhandle = allocator.Malloc(sizeof(ISO9660FileHandle));
+ BAIL_IF_MACRO(fhandle == 0, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ fhandle->cacheddata = 0;
+
+ retval = allocator.Malloc(sizeof(PHYSFS_Io));
+ GOTO_IF_MACRO(retval == 0, PHYSFS_ERR_OUT_OF_MEMORY, errorhandling);
+
+ /* find file descriptor */
+ rc = iso_find_dir_entry(handle, filename, &descriptor, exists);
+ GOTO_IF_MACRO(rc, ERRPASS, errorhandling);
+ GOTO_IF_MACRO(!*exists, PHYSFS_ERR_NO_SUCH_PATH, errorhandling);
+
+ fhandle->startblock = descriptor.extentpos + descriptor.extattributelen;
+ fhandle->filesize = descriptor.datalen;
+ fhandle->currpos = 0;
+ fhandle->isohandle = handle;
+ fhandle->cacheddata = NULL;
+ fhandle->io = NULL;
+
+ if (descriptor.datalen <= ISO9660_FULLCACHEMAXSIZE)
+ rc = iso_file_open_mem(handle, fhandle);
+ else
+ rc = iso_file_open_foreign(handle, fhandle);
+ GOTO_IF_MACRO(rc, ERRPASS, errorhandling);
+
+ memcpy(retval, &ISO9660_Io, sizeof (PHYSFS_Io));
+ retval->opaque = fhandle;
+ return retval;
+
+errorhandling:
+ if (retval) allocator.Free(retval);
+ if (fhandle) allocator.Free(fhandle);
+ return NULL;
+} /* ISO9660_openRead */
+
+
+
+/*******************************************************************************
+ * Information gathering functions
+ ******************************************************************************/
+
+static void ISO9660_enumerateFiles(PHYSFS_Dir *opaque, const char *dname,
+ int omitSymLinks,
+ PHYSFS_EnumFilesCallback cb,
+ const char *origdir, void *callbackdata)
+{
+ ISO9660Handle *handle = (ISO9660Handle*) opaque;
+ ISO9660FileDescriptor descriptor;
+ PHYSFS_uint64 readpos;
+ PHYSFS_uint64 end_of_dir;
+ char filename[130]; /* ISO allows 31, Joliet 128 -> 128 + 2 eol bytes */
+ int version = 0;
+
+ if (*dname == '\0')
+ {
+ readpos = handle->rootdirstart;
+ end_of_dir = readpos + handle->rootdirsize;
+ } /* if */
+ else
+ {
+ printf("pfad %s\n",dname);
+ int exists = 0;
+ BAIL_IF_MACRO(iso_find_dir_entry(handle,dname, &descriptor, &exists), ERRPASS,);
+ BAIL_IF_MACRO(!exists, ERRPASS, );
+ BAIL_IF_MACRO(!descriptor.flags.directory, ERRPASS,);
+
+ readpos = descriptor.extentpos * 2048;
+ end_of_dir = readpos + descriptor.datalen;
+ } /* else */
+
+ while (1)
+ {
+ BAIL_IF_MACRO(iso_readfiledescriptor(handle, readpos, &descriptor), ERRPASS, );
+
+ /* recordlen = 0 -> no more entries or fill entry */
+ if (!descriptor.recordlen)
+ {
+ /* if we are in the last sector of the directory & it's 0 -> end */
+ if ((end_of_dir - 2048) <= (readpos -1))
+ break; /* finished */
+
+ /* else skip to the next sector & continue; */
+ readpos = (((readpos - 1) / 2048) + 1) * 2048;
+ continue;
+ } /* if */
+
+ readpos += descriptor.recordlen;
+ if (descriptor.filenamelen == 1 && (descriptor.filename[0] == 0
+ || descriptor.filename[0] == 1))
+ continue; /* special ones, ignore */
+
+ strncpy(filename,descriptor.filename,descriptor.filenamelen);
+ iso_extractfilename(handle, &descriptor, filename, &version);
+ cb(callbackdata, origdir,filename);
+ } /* while */
+} /* ISO9660_enumerateFiles */
+
+
+static int ISO9660_stat(PHYSFS_Dir *opaque, const char *name, int *exists,
+ PHYSFS_Stat *stat)
+{
+ ISO9660Handle *handle = (ISO9660Handle*) opaque;
+ ISO9660FileDescriptor descriptor;
+ ISO9660ExtAttributeRec extattr;
+ BAIL_IF_MACRO(iso_find_dir_entry(handle, name, &descriptor, exists), ERRPASS, -1);
+ if (!*exists)
+ return 0;
+
+ stat->readonly = 1;
+
+ /* try to get extended info */
+ if (descriptor.extattributelen)
+ {
+ BAIL_IF_MACRO(iso_read_ext_attributes(handle,
+ descriptor.extentpos, &extattr), ERRPASS, -1);
+ stat->createtime = iso_volume_mktime(&extattr.create_time);
+ stat->modtime = iso_volume_mktime(&extattr.mod_time);
+ stat->accesstime = iso_volume_mktime(&extattr.mod_time);
+ } /* if */
+ else
+ {
+ stat->createtime = iso_mktime(&descriptor.recordtime);
+ stat->modtime = iso_mktime(&descriptor.recordtime);
+ stat->accesstime = iso_mktime(&descriptor.recordtime);
+ } /* else */
+
+ if (descriptor.flags.directory)
+ {
+ stat->filesize = 0;
+ stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
+ } /* if */
+ else
+ {
+ stat->filesize = descriptor.datalen;
+ stat->filetype = PHYSFS_FILETYPE_REGULAR;
+ } /* else */
+
+ return 1;
+} /* ISO9660_stat */
+
+
+/*******************************************************************************
+ * Not supported functions
+ ******************************************************************************/
+
+static PHYSFS_Io *ISO9660_openWrite(PHYSFS_Dir *opaque, const char *name)
+{
+ BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
+} /* ISO9660_openWrite */
+
+
+static PHYSFS_Io *ISO9660_openAppend(PHYSFS_Dir *opaque, const char *name)
+{
+ BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
+} /* ISO9660_openAppend */
+
+
+static int ISO9660_remove(PHYSFS_Dir *opaque, const char *name)
+{
+ BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
+} /* ISO9660_remove */
+
+
+static int ISO9660_mkdir(PHYSFS_Dir *opaque, const char *name)
+{
+ BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
+} /* ISO9660_mkdir */
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_ISO9660 =
+{
+ {
+ "ISO",
+ "ISO9660 image file",
+ "Christoph Nelles ",
+ "http://www.evilazrael.de/",
+ },
+ ISO9660_openArchive, /* openArchive() method */
+ ISO9660_enumerateFiles, /* enumerateFiles() method */
+ ISO9660_openRead, /* openRead() method */
+ ISO9660_openWrite, /* openWrite() method */
+ ISO9660_openAppend, /* openAppend() method */
+ ISO9660_remove, /* remove() method */
+ ISO9660_mkdir, /* mkdir() method */
+ ISO9660_closeArchive, /* closeArchive() method */
+ ISO9660_stat /* stat() method */
+};
+
+#endif /* defined PHYSFS_SUPPORTS_ISO9660 */
+
+/* end of archiver_iso9660.c ... */
+
diff -r 404ddce27b23 -r c13ebed437cb misc/libphysfs/archiver_lzma.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/archiver_lzma.c Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,701 @@
+/*
+ * LZMA support routines for PhysicsFS.
+ *
+ * Please see the file lzma.txt in the lzma/ directory.
+ *
+ * This file was written by Dennis Schridde, with some peeking at "7zMain.c"
+ * by Igor Pavlov.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+#if PHYSFS_SUPPORTS_7Z
+
+#include "lzma/C/7zCrc.h"
+#include "lzma/C/Archive/7z/7zIn.h"
+#include "lzma/C/Archive/7z/7zExtract.h"
+
+
+/* 7z internal from 7zIn.c */
+extern int TestSignatureCandidate(Byte *testBytes);
+
+
+#ifdef _LZMA_IN_CB
+# define BUFFER_SIZE (1 << 12)
+#endif /* _LZMA_IN_CB */
+
+
+/*
+ * Carries filestream metadata through 7z
+ */
+typedef struct _FileInputStream
+{
+ ISzAlloc allocImp; /* Allocation implementation, used by 7z */
+ ISzAlloc allocTempImp; /* Temporary allocation implementation, used by 7z */
+ ISzInStream inStream; /* Input stream with read callbacks, used by 7z */
+ PHYSFS_Io *io; /* Filehandle, used by read implementation */
+#ifdef _LZMA_IN_CB
+ Byte buffer[BUFFER_SIZE]; /* Buffer, used by read implementation */
+#endif /* _LZMA_IN_CB */
+} FileInputStream;
+
+/*
+ * In the 7z format archives are splited into blocks, those are called folders
+ * Set by LZMA_read()
+*/
+typedef struct _LZMAfolder
+{
+ PHYSFS_uint32 index; /* Index of folder in archive */
+ PHYSFS_uint32 references; /* Number of files using this block */
+ PHYSFS_uint8 *cache; /* Cached folder */
+ size_t size; /* Size of folder */
+} LZMAfolder;
+
+/*
+ * Set by LZMA_openArchive(), except folder which gets it's values
+ * in LZMA_read()
+ */
+typedef struct _LZMAarchive
+{
+ struct _LZMAfile *files; /* Array of files, size == archive->db.Database.NumFiles */
+ LZMAfolder *folders; /* Array of folders, size == archive->db.Database.NumFolders */
+ CArchiveDatabaseEx db; /* For 7z: Database */
+ FileInputStream stream; /* For 7z: Input file incl. read and seek callbacks */
+} LZMAarchive;
+
+/* Set by LZMA_openArchive(), except offset which is set by LZMA_read() */
+typedef struct _LZMAfile
+{
+ PHYSFS_uint32 index; /* Index of file in archive */
+ LZMAarchive *archive; /* Link to corresponding archive */
+ LZMAfolder *folder; /* Link to corresponding folder */
+ CFileItem *item; /* For 7z: File info, eg. name, size */
+ size_t offset; /* Offset in folder */
+ size_t position; /* Current "virtual" position in file */
+} LZMAfile;
+
+
+/* Memory management implementations to be passed to 7z */
+
+static void *SzAllocPhysicsFS(size_t size)
+{
+ return ((size == 0) ? NULL : allocator.Malloc(size));
+} /* SzAllocPhysicsFS */
+
+
+static void SzFreePhysicsFS(void *address)
+{
+ if (address != NULL)
+ allocator.Free(address);
+} /* SzFreePhysicsFS */
+
+
+/* Filesystem implementations to be passed to 7z */
+
+#ifdef _LZMA_IN_CB
+
+/*
+ * Read implementation, to be passed to 7z
+ * WARNING: If the ISzInStream in 'object' is not contained in a valid FileInputStream this _will_ break horribly!
+ */
+SZ_RESULT SzFileReadImp(void *object, void **buffer, size_t maxReqSize,
+ size_t *processedSize)
+{
+ FileInputStream *s = (FileInputStream *)(object - offsetof(FileInputStream, inStream)); /* HACK! */
+ PHYSFS_sint64 processedSizeLoc = 0;
+
+ if (maxReqSize > BUFFER_SIZE)
+ maxReqSize = BUFFER_SIZE;
+ processedSizeLoc = s->io->read(s->io, s->buffer, maxReqSize);
+ *buffer = s->buffer;
+ if (processedSize != NULL)
+ *processedSize = (size_t) processedSizeLoc;
+
+ return SZ_OK;
+} /* SzFileReadImp */
+
+#else
+
+/*
+ * Read implementation, to be passed to 7z
+ * WARNING: If the ISzInStream in 'object' is not contained in a valid FileInputStream this _will_ break horribly!
+ */
+SZ_RESULT SzFileReadImp(void *object, void *buffer, size_t size,
+ size_t *processedSize)
+{
+ FileInputStream *s = (FileInputStream *)((unsigned long)object - offsetof(FileInputStream, inStream)); /* HACK! */
+ const size_t processedSizeLoc = s->io->read(s->io, buffer, size);
+ if (processedSize != NULL)
+ *processedSize = processedSizeLoc;
+ return SZ_OK;
+} /* SzFileReadImp */
+
+#endif
+
+/*
+ * Seek implementation, to be passed to 7z
+ * WARNING: If the ISzInStream in 'object' is not contained in a valid FileInputStream this _will_ break horribly!
+ */
+SZ_RESULT SzFileSeekImp(void *object, CFileSize pos)
+{
+ FileInputStream *s = (FileInputStream *)((unsigned long)object - offsetof(FileInputStream, inStream)); /* HACK! */
+ if (s->io->seek(s->io, (PHYSFS_uint64) pos))
+ return SZ_OK;
+ return SZE_FAIL;
+} /* SzFileSeekImp */
+
+
+/*
+ * Translate Microsoft FILETIME (used by 7zip) into UNIX timestamp
+ */
+static PHYSFS_sint64 lzma_filetime_to_unix_timestamp(CArchiveFileTime *ft)
+{
+ /* MS counts in nanoseconds ... */
+ const PHYSFS_uint64 FILETIME_NANOTICKS_PER_SECOND = __PHYSFS_UI64(10000000);
+ /* MS likes to count seconds since 01.01.1601 ... */
+ const PHYSFS_uint64 FILETIME_UNIX_DIFF = __PHYSFS_UI64(11644473600);
+
+ PHYSFS_uint64 filetime = ft->Low | ((PHYSFS_uint64)ft->High << 32);
+ return filetime/FILETIME_NANOTICKS_PER_SECOND - FILETIME_UNIX_DIFF;
+} /* lzma_filetime_to_unix_timestamp */
+
+
+/*
+ * Compare a file with a given name, C89 stdlib variant
+ * Used for sorting
+ */
+static int lzma_file_cmp_stdlib(const void *key, const void *object)
+{
+ const char *name = (const char *) key;
+ LZMAfile *file = (LZMAfile *) object;
+ return strcmp(name, file->item->Name);
+} /* lzma_file_cmp_posix */
+
+
+/*
+ * Compare two files with each other based on the name
+ * Used for sorting
+ */
+static int lzma_file_cmp(void *_a, size_t one, size_t two)
+{
+ LZMAfile *files = (LZMAfile *) _a;
+ return strcmp(files[one].item->Name, files[two].item->Name);
+} /* lzma_file_cmp */
+
+
+/*
+ * Swap two entries in the file array
+ */
+static void lzma_file_swap(void *_a, size_t one, size_t two)
+{
+ LZMAfile tmp;
+ LZMAfile *first = &(((LZMAfile *) _a)[one]);
+ LZMAfile *second = &(((LZMAfile *) _a)[two]);
+ memcpy(&tmp, first, sizeof (LZMAfile));
+ memcpy(first, second, sizeof (LZMAfile));
+ memcpy(second, &tmp, sizeof (LZMAfile));
+} /* lzma_file_swap */
+
+
+/*
+ * Find entry 'name' in 'archive'
+ */
+static LZMAfile * lzma_find_file(const LZMAarchive *archive, const char *name)
+{
+ LZMAfile *file = bsearch(name, archive->files, archive->db.Database.NumFiles, sizeof(*archive->files), lzma_file_cmp_stdlib); /* FIXME: Should become __PHYSFS_search!!! */
+
+ BAIL_IF_MACRO(file == NULL, PHYSFS_ERR_NO_SUCH_PATH, NULL);
+
+ return file;
+} /* lzma_find_file */
+
+
+/*
+ * Load metadata for the file at given index
+ */
+static int lzma_file_init(LZMAarchive *archive, PHYSFS_uint32 fileIndex)
+{
+ LZMAfile *file = &archive->files[fileIndex];
+ PHYSFS_uint32 folderIndex = archive->db.FileIndexToFolderIndexMap[fileIndex];
+
+ file->index = fileIndex; /* Store index into 7z array, since we sort our own. */
+ file->archive = archive;
+ file->folder = (folderIndex != (PHYSFS_uint32)-1 ? &archive->folders[folderIndex] : NULL); /* Directories don't have a folder (they contain no own data...) */
+ file->item = &archive->db.Database.Files[fileIndex]; /* Holds crucial data and is often referenced -> Store link */
+ file->position = 0;
+ file->offset = 0; /* Offset will be set by LZMA_read() */
+
+ return 1;
+} /* lzma_load_file */
+
+
+/*
+ * Load metadata for all files
+ */
+static int lzma_files_init(LZMAarchive *archive)
+{
+ PHYSFS_uint32 fileIndex = 0, numFiles = archive->db.Database.NumFiles;
+
+ for (fileIndex = 0; fileIndex < numFiles; fileIndex++ )
+ {
+ if (!lzma_file_init(archive, fileIndex))
+ {
+ return 0; /* FALSE on failure */
+ }
+ } /* for */
+
+ __PHYSFS_sort(archive->files, (size_t) numFiles, lzma_file_cmp, lzma_file_swap);
+
+ return 1;
+} /* lzma_load_files */
+
+
+/*
+ * Initialise specified archive
+ */
+static void lzma_archive_init(LZMAarchive *archive)
+{
+ memset(archive, 0, sizeof(*archive));
+
+ /* Prepare callbacks for 7z */
+ archive->stream.inStream.Read = SzFileReadImp;
+ archive->stream.inStream.Seek = SzFileSeekImp;
+
+ archive->stream.allocImp.Alloc = SzAllocPhysicsFS;
+ archive->stream.allocImp.Free = SzFreePhysicsFS;
+
+ archive->stream.allocTempImp.Alloc = SzAllocPhysicsFS;
+ archive->stream.allocTempImp.Free = SzFreePhysicsFS;
+}
+
+
+/*
+ * Deinitialise archive
+ */
+static void lzma_archive_exit(LZMAarchive *archive)
+{
+ /* Free arrays */
+ allocator.Free(archive->folders);
+ allocator.Free(archive->files);
+ allocator.Free(archive);
+}
+
+/*
+ * Wrap all 7z calls in this, so the physfs error state is set appropriately.
+ */
+static int lzma_err(SZ_RESULT rc)
+{
+ switch (rc)
+ {
+ case SZ_OK: /* Same as LZMA_RESULT_OK */
+ break;
+ case SZE_DATA_ERROR: /* Same as LZMA_RESULT_DATA_ERROR */
+ __PHYSFS_setError(PHYSFS_ERR_CORRUPT); /*!!!FIXME: was "PHYSFS_ERR_DATA_ERROR" */
+ break;
+ case SZE_OUTOFMEMORY:
+ __PHYSFS_setError(PHYSFS_ERR_OUT_OF_MEMORY);
+ break;
+ case SZE_CRC_ERROR:
+ __PHYSFS_setError(PHYSFS_ERR_CORRUPT);
+ break;
+ case SZE_NOTIMPL:
+ __PHYSFS_setError(PHYSFS_ERR_UNSUPPORTED);
+ break;
+ case SZE_FAIL:
+ __PHYSFS_setError(PHYSFS_ERR_OTHER_ERROR); /* !!! FIXME: right? */
+ break;
+ case SZE_ARCHIVE_ERROR:
+ __PHYSFS_setError(PHYSFS_ERR_CORRUPT); /* !!! FIXME: right? */
+ break;
+ default:
+ __PHYSFS_setError(PHYSFS_ERR_OTHER_ERROR);
+ } /* switch */
+
+ return rc;
+} /* lzma_err */
+
+
+static PHYSFS_sint64 LZMA_read(PHYSFS_Io *io, void *outBuf, PHYSFS_uint64 len)
+{
+ LZMAfile *file = (LZMAfile *) io->opaque;
+
+ size_t wantedSize = (size_t) len;
+ const size_t remainingSize = file->item->Size - file->position;
+ size_t fileSize = 0;
+
+ BAIL_IF_MACRO(wantedSize == 0, ERRPASS, 0); /* quick rejection. */
+ BAIL_IF_MACRO(remainingSize == 0, PHYSFS_ERR_PAST_EOF, 0);
+
+ if (wantedSize > remainingSize)
+ wantedSize = remainingSize;
+
+ /* Only decompress the folder if it is not already cached */
+ if (file->folder->cache == NULL)
+ {
+ const int rc = lzma_err(SzExtract(
+ &file->archive->stream.inStream, /* compressed data */
+ &file->archive->db, /* 7z's database, containing everything */
+ file->index, /* Index into database arrays */
+ /* Index of cached folder, will be changed by SzExtract */
+ &file->folder->index,
+ /* Cache for decompressed folder, allocated/freed by SzExtract */
+ &file->folder->cache,
+ /* Size of cache, will be changed by SzExtract */
+ &file->folder->size,
+ /* Offset of this file inside the cache, set by SzExtract */
+ &file->offset,
+ &fileSize, /* Size of this file */
+ &file->archive->stream.allocImp,
+ &file->archive->stream.allocTempImp));
+
+ if (rc != SZ_OK)
+ return -1;
+ } /* if */
+
+ /* Copy wanted bytes over from cache to outBuf */
+ memcpy(outBuf, (file->folder->cache + file->offset + file->position),
+ wantedSize);
+ file->position += wantedSize; /* Increase virtual position */
+
+ return wantedSize;
+} /* LZMA_read */
+
+
+static PHYSFS_sint64 LZMA_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
+{
+ BAIL_MACRO(PHYSFS_ERR_READ_ONLY, -1);
+} /* LZMA_write */
+
+
+static PHYSFS_sint64 LZMA_tell(PHYSFS_Io *io)
+{
+ LZMAfile *file = (LZMAfile *) io->opaque;
+ return file->position;
+} /* LZMA_tell */
+
+
+static int LZMA_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
+{
+ LZMAfile *file = (LZMAfile *) io->opaque;
+
+ BAIL_IF_MACRO(offset > file->item->Size, PHYSFS_ERR_PAST_EOF, 0);
+
+ file->position = offset; /* We only use a virtual position... */
+
+ return 1;
+} /* LZMA_seek */
+
+
+static PHYSFS_sint64 LZMA_length(PHYSFS_Io *io)
+{
+ const LZMAfile *file = (LZMAfile *) io->opaque;
+ return (file->item->Size);
+} /* LZMA_length */
+
+
+static PHYSFS_Io *LZMA_duplicate(PHYSFS_Io *_io)
+{
+ /* !!! FIXME: this archiver needs to be reworked to allow multiple
+ * !!! FIXME: opens before we worry about duplication. */
+ BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL);
+} /* LZMA_duplicate */
+
+
+static int LZMA_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
+
+
+static void LZMA_destroy(PHYSFS_Io *io)
+{
+ LZMAfile *file = (LZMAfile *) io->opaque;
+
+ if (file->folder != NULL)
+ {
+ /* Only decrease refcount if someone actually requested this file... Prevents from overflows and close-on-open... */
+ if (file->folder->references > 0)
+ file->folder->references--;
+ if (file->folder->references == 0)
+ {
+ /* Free the cache which might have been allocated by LZMA_read() */
+ allocator.Free(file->folder->cache);
+ file->folder->cache = NULL;
+ }
+ /* !!! FIXME: we don't free (file) or (file->folder)?! */
+ } /* if */
+} /* LZMA_destroy */
+
+
+static const PHYSFS_Io LZMA_Io =
+{
+ CURRENT_PHYSFS_IO_API_VERSION, NULL,
+ LZMA_read,
+ LZMA_write,
+ LZMA_seek,
+ LZMA_tell,
+ LZMA_length,
+ LZMA_duplicate,
+ LZMA_flush,
+ LZMA_destroy
+};
+
+
+static void *LZMA_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
+{
+ PHYSFS_uint8 sig[k7zSignatureSize];
+ size_t len = 0;
+ LZMAarchive *archive = NULL;
+
+ assert(io != NULL); /* shouldn't ever happen. */
+
+ BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
+
+ if (io->read(io, sig, k7zSignatureSize) != k7zSignatureSize)
+ return 0;
+ BAIL_IF_MACRO(!TestSignatureCandidate(sig), PHYSFS_ERR_UNSUPPORTED, NULL);
+ BAIL_IF_MACRO(!io->seek(io, 0), ERRPASS, NULL);
+
+ archive = (LZMAarchive *) allocator.Malloc(sizeof (LZMAarchive));
+ BAIL_IF_MACRO(archive == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+
+ lzma_archive_init(archive);
+ archive->stream.io = io;
+
+ CrcGenerateTable();
+ SzArDbExInit(&archive->db);
+ if (lzma_err(SzArchiveOpen(&archive->stream.inStream,
+ &archive->db,
+ &archive->stream.allocImp,
+ &archive->stream.allocTempImp)) != SZ_OK)
+ {
+ SzArDbExFree(&archive->db, SzFreePhysicsFS);
+ lzma_archive_exit(archive);
+ return NULL; /* Error is set by lzma_err! */
+ } /* if */
+
+ len = archive->db.Database.NumFiles * sizeof (LZMAfile);
+ archive->files = (LZMAfile *) allocator.Malloc(len);
+ if (archive->files == NULL)
+ {
+ SzArDbExFree(&archive->db, SzFreePhysicsFS);
+ lzma_archive_exit(archive);
+ BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ }
+
+ /*
+ * Init with 0 so we know when a folder is already cached
+ * Values will be set by LZMA_openRead()
+ */
+ memset(archive->files, 0, len);
+
+ len = archive->db.Database.NumFolders * sizeof (LZMAfolder);
+ archive->folders = (LZMAfolder *) allocator.Malloc(len);
+ if (archive->folders == NULL)
+ {
+ SzArDbExFree(&archive->db, SzFreePhysicsFS);
+ lzma_archive_exit(archive);
+ BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ }
+
+ /*
+ * Init with 0 so we know when a folder is already cached
+ * Values will be set by LZMA_read()
+ */
+ memset(archive->folders, 0, len);
+
+ if(!lzma_files_init(archive))
+ {
+ SzArDbExFree(&archive->db, SzFreePhysicsFS);
+ lzma_archive_exit(archive);
+ BAIL_MACRO(PHYSFS_ERR_OTHER_ERROR, NULL);
+ }
+
+ return archive;
+} /* LZMA_openArchive */
+
+
+/*
+ * Moved to seperate function so we can use alloca then immediately throw
+ * away the allocated stack space...
+ */
+static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata,
+ const char *odir, const char *str, size_t flen)
+{
+ char *newstr = __PHYSFS_smallAlloc(flen + 1);
+ if (newstr == NULL)
+ return;
+
+ memcpy(newstr, str, flen);
+ newstr[flen] = '\0';
+ cb(callbackdata, odir, newstr);
+ __PHYSFS_smallFree(newstr);
+} /* doEnumCallback */
+
+
+static void LZMA_enumerateFiles(PHYSFS_Dir *opaque, const char *dname,
+ int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+ const char *origdir, void *callbackdata)
+{
+ size_t dlen = strlen(dname),
+ dlen_inc = dlen + ((dlen > 0) ? 1 : 0);
+ LZMAarchive *archive = (LZMAarchive *) opaque;
+ LZMAfile *file = NULL,
+ *lastFile = &archive->files[archive->db.Database.NumFiles];
+ if (dlen)
+ {
+ file = lzma_find_file(archive, dname);
+ if (file != NULL) /* if 'file' is NULL it should stay so, otherwise errors will not be handled */
+ file += 1;
+ }
+ else
+ {
+ file = archive->files;
+ }
+
+ BAIL_IF_MACRO(file == NULL, PHYSFS_ERR_NO_SUCH_PATH, );
+
+ while (file < lastFile)
+ {
+ const char * fname = file->item->Name;
+ const char * dirNameEnd = fname + dlen_inc;
+
+ if (strncmp(dname, fname, dlen) != 0) /* Stop after mismatch, archive->files is sorted */
+ break;
+
+ if (strchr(dirNameEnd, '/')) /* Skip subdirs */
+ {
+ file++;
+ continue;
+ }
+
+ /* Do the actual callback... */
+ doEnumCallback(cb, callbackdata, origdir, dirNameEnd, strlen(dirNameEnd));
+
+ file++;
+ }
+} /* LZMA_enumerateFiles */
+
+
+static PHYSFS_Io *LZMA_openRead(PHYSFS_Dir *opaque, const char *name,
+ int *fileExists)
+{
+ LZMAarchive *archive = (LZMAarchive *) opaque;
+ LZMAfile *file = lzma_find_file(archive, name);
+ PHYSFS_Io *io = NULL;
+
+ *fileExists = (file != NULL);
+ BAIL_IF_MACRO(file == NULL, PHYSFS_ERR_NO_SUCH_PATH, NULL);
+ BAIL_IF_MACRO(file->folder == NULL, PHYSFS_ERR_NOT_A_FILE, NULL);
+
+ file->position = 0;
+ file->folder->references++; /* Increase refcount for automatic cleanup... */
+
+ io = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
+ BAIL_IF_MACRO(io == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ memcpy(io, &LZMA_Io, sizeof (*io));
+ io->opaque = file;
+
+ return io;
+} /* LZMA_openRead */
+
+
+static PHYSFS_Io *LZMA_openWrite(PHYSFS_Dir *opaque, const char *filename)
+{
+ BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
+} /* LZMA_openWrite */
+
+
+static PHYSFS_Io *LZMA_openAppend(PHYSFS_Dir *opaque, const char *filename)
+{
+ BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
+} /* LZMA_openAppend */
+
+
+static void LZMA_closeArchive(PHYSFS_Dir *opaque)
+{
+ LZMAarchive *archive = (LZMAarchive *) opaque;
+
+#if 0 /* !!! FIXME: you shouldn't have to do this. */
+ PHYSFS_uint32 fileIndex = 0, numFiles = archive->db.Database.NumFiles;
+ for (fileIndex = 0; fileIndex < numFiles; fileIndex++)
+ {
+ LZMA_fileClose(&archive->files[fileIndex]);
+ } /* for */
+#endif
+
+ SzArDbExFree(&archive->db, SzFreePhysicsFS);
+ archive->stream.io->destroy(archive->stream.io);
+ lzma_archive_exit(archive);
+} /* LZMA_closeArchive */
+
+
+static int LZMA_remove(PHYSFS_Dir *opaque, const char *name)
+{
+ BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
+} /* LZMA_remove */
+
+
+static int LZMA_mkdir(PHYSFS_Dir *opaque, const char *name)
+{
+ BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
+} /* LZMA_mkdir */
+
+static int LZMA_stat(PHYSFS_Dir *opaque, const char *filename,
+ int *exists, PHYSFS_Stat *stat)
+{
+ const LZMAarchive *archive = (const LZMAarchive *) opaque;
+ const LZMAfile *file = lzma_find_file(archive, filename);
+
+ *exists = (file != 0);
+ if (!file)
+ return 0;
+
+ if(file->item->IsDirectory)
+ {
+ stat->filesize = 0;
+ stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
+ } /* if */
+ else
+ {
+ stat->filesize = (PHYSFS_sint64) file->item->Size;
+ stat->filetype = PHYSFS_FILETYPE_REGULAR;
+ } /* else */
+
+ /* !!! FIXME: the 0's should be -1's? */
+ if (file->item->IsLastWriteTimeDefined)
+ stat->modtime = lzma_filetime_to_unix_timestamp(&file->item->LastWriteTime);
+ else
+ stat->modtime = 0;
+
+ /* real create and accesstype are currently not in the lzma SDK */
+ stat->createtime = stat->modtime;
+ stat->accesstime = 0;
+
+ stat->readonly = 1; /* 7zips are always read only */
+
+ return 1;
+} /* LZMA_stat */
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_LZMA =
+{
+ {
+ "7Z",
+ "LZMA (7zip) format",
+ "Dennis Schridde ",
+ "http://icculus.org/physfs/",
+ },
+ LZMA_openArchive, /* openArchive() method */
+ LZMA_enumerateFiles, /* enumerateFiles() method */
+ LZMA_openRead, /* openRead() method */
+ LZMA_openWrite, /* openWrite() method */
+ LZMA_openAppend, /* openAppend() method */
+ LZMA_remove, /* remove() method */
+ LZMA_mkdir, /* mkdir() method */
+ LZMA_closeArchive, /* closeArchive() method */
+ LZMA_stat /* stat() method */
+};
+
+#endif /* defined PHYSFS_SUPPORTS_7Z */
+
+/* end of lzma.c ... */
+
diff -r 404ddce27b23 -r c13ebed437cb misc/libphysfs/archiver_mvl.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/archiver_mvl.c Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,103 @@
+/*
+ * MVL support routines for PhysicsFS.
+ *
+ * This driver handles Descent II Movielib archives.
+ *
+ * The file format of MVL is quite easy...
+ *
+ * //MVL File format - Written by Heiko Herrmann
+ * char sig[4] = {'D','M', 'V', 'L'}; // "DMVL"=Descent MoVie Library
+ *
+ * int num_files; // the number of files in this MVL
+ *
+ * struct {
+ * char file_name[13]; // Filename, padded to 13 bytes with 0s
+ * int file_size; // filesize in bytes
+ * }DIR_STRUCT[num_files];
+ *
+ * struct {
+ * char data[file_size]; // The file data
+ * }FILE_STRUCT[num_files];
+ *
+ * (That info is from http://www.descent2.com/ddn/specs/mvl/)
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ * This file written by Bradley Bell.
+ * Based on grp.c by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+#if PHYSFS_SUPPORTS_MVL
+
+static UNPKentry *mvlLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 fileCount)
+{
+ PHYSFS_uint32 location = 8; /* sizeof sig. */
+ UNPKentry *entries = NULL;
+ UNPKentry *entry = NULL;
+
+ entries = (UNPKentry *) allocator.Malloc(sizeof (UNPKentry) * fileCount);
+ BAIL_IF_MACRO(entries == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+
+ location += (17 * fileCount);
+
+ for (entry = entries; fileCount > 0; fileCount--, entry++)
+ {
+ if (!__PHYSFS_readAll(io, &entry->name, 13)) goto failed;
+ if (!__PHYSFS_readAll(io, &entry->size, 4)) goto failed;
+ entry->size = PHYSFS_swapULE32(entry->size);
+ entry->startPos = location;
+ location += entry->size;
+ } /* for */
+
+ return entries;
+
+failed:
+ allocator.Free(entries);
+ return NULL;
+} /* mvlLoadEntries */
+
+
+static void *MVL_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
+{
+ PHYSFS_uint8 buf[4];
+ PHYSFS_uint32 count = 0;
+ UNPKentry *entries = NULL;
+
+ assert(io != NULL); /* shouldn't ever happen. */
+ BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
+ BAIL_IF_MACRO(!__PHYSFS_readAll(io, buf, 4), ERRPASS, NULL);
+ BAIL_IF_MACRO(memcmp(buf, "DMVL", 4) != 0, PHYSFS_ERR_UNSUPPORTED, NULL);
+ BAIL_IF_MACRO(!__PHYSFS_readAll(io, &count, sizeof(count)), ERRPASS, NULL);
+
+ count = PHYSFS_swapULE32(count);
+ entries = mvlLoadEntries(io, count);
+ return (!entries) ? NULL : UNPK_openArchive(io, entries, count);
+} /* MVL_openArchive */
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_MVL =
+{
+ {
+ "MVL",
+ "Descent II Movielib format",
+ "Bradley Bell ",
+ "http://icculus.org/physfs/",
+ },
+ MVL_openArchive, /* openArchive() method */
+ UNPK_enumerateFiles, /* enumerateFiles() method */
+ UNPK_openRead, /* openRead() method */
+ UNPK_openWrite, /* openWrite() method */
+ UNPK_openAppend, /* openAppend() method */
+ UNPK_remove, /* remove() method */
+ UNPK_mkdir, /* mkdir() method */
+ UNPK_closeArchive, /* closeArchive() method */
+ UNPK_stat /* stat() method */
+};
+
+#endif /* defined PHYSFS_SUPPORTS_MVL */
+
+/* end of mvl.c ... */
+
diff -r 404ddce27b23 -r c13ebed437cb misc/libphysfs/archiver_qpak.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/archiver_qpak.c Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,119 @@
+/*
+ * QPAK support routines for PhysicsFS.
+ *
+ * This archiver handles the archive format utilized by Quake 1 and 2.
+ * Quake3-based games use the PkZip/Info-Zip format (which our zip.c
+ * archiver handles).
+ *
+ * ========================================================================
+ *
+ * This format info (in more detail) comes from:
+ * http://debian.fmi.uni-sofia.bg/~sergei/cgsr/docs/pak.txt
+ *
+ * Quake PAK Format
+ *
+ * Header
+ * (4 bytes) signature = 'PACK'
+ * (4 bytes) directory offset
+ * (4 bytes) directory length
+ *
+ * Directory
+ * (56 bytes) file name
+ * (4 bytes) file position
+ * (4 bytes) file length
+ *
+ * ========================================================================
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ * This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+#if PHYSFS_SUPPORTS_QPAK
+
+#define QPAK_SIG 0x4B434150 /* "PACK" in ASCII. */
+
+static UNPKentry *qpakLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 fileCount)
+{
+ UNPKentry *entries = NULL;
+ UNPKentry *entry = NULL;
+
+ entries = (UNPKentry *) allocator.Malloc(sizeof (UNPKentry) * fileCount);
+ BAIL_IF_MACRO(entries == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+
+ for (entry = entries; fileCount > 0; fileCount--, entry++)
+ {
+ if (!__PHYSFS_readAll(io, &entry->name, 56)) goto failed;
+ if (!__PHYSFS_readAll(io, &entry->startPos, 4)) goto failed;
+ if (!__PHYSFS_readAll(io, &entry->size, 4)) goto failed;
+ entry->size = PHYSFS_swapULE32(entry->size);
+ entry->startPos = PHYSFS_swapULE32(entry->startPos);
+ } /* for */
+
+ return entries;
+
+failed:
+ allocator.Free(entries);
+ return NULL;
+} /* qpakLoadEntries */
+
+
+static void *QPAK_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
+{
+ UNPKentry *entries = NULL;
+ PHYSFS_uint32 val = 0;
+ PHYSFS_uint32 pos = 0;
+ PHYSFS_uint32 count = 0;
+
+ assert(io != NULL); /* shouldn't ever happen. */
+
+ BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
+
+ BAIL_IF_MACRO(!__PHYSFS_readAll(io, &val, 4), ERRPASS, NULL);
+ if (PHYSFS_swapULE32(val) != QPAK_SIG)
+ BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL);
+
+ BAIL_IF_MACRO(!__PHYSFS_readAll(io, &val, 4), ERRPASS, NULL);
+ pos = PHYSFS_swapULE32(val); /* directory table offset. */
+
+ BAIL_IF_MACRO(!__PHYSFS_readAll(io, &val, 4), ERRPASS, NULL);
+ count = PHYSFS_swapULE32(val);
+
+ /* corrupted archive? */
+ BAIL_IF_MACRO((count % 64) != 0, PHYSFS_ERR_CORRUPT, NULL);
+ count /= 64;
+
+ BAIL_IF_MACRO(!io->seek(io, pos), ERRPASS, NULL);
+
+ entries = qpakLoadEntries(io, count);
+ BAIL_IF_MACRO(!entries, ERRPASS, NULL);
+ return UNPK_openArchive(io, entries, count);
+} /* QPAK_openArchive */
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_QPAK =
+{
+ {
+ "PAK",
+ "Quake I/II format",
+ "Ryan C. Gordon ",
+ "http://icculus.org/physfs/",
+ },
+ QPAK_openArchive, /* openArchive() method */
+ UNPK_enumerateFiles, /* enumerateFiles() method */
+ UNPK_openRead, /* openRead() method */
+ UNPK_openWrite, /* openWrite() method */
+ UNPK_openAppend, /* openAppend() method */
+ UNPK_remove, /* remove() method */
+ UNPK_mkdir, /* mkdir() method */
+ UNPK_closeArchive, /* closeArchive() method */
+ UNPK_stat /* stat() method */
+};
+
+#endif /* defined PHYSFS_SUPPORTS_QPAK */
+
+/* end of qpak.c ... */
+
diff -r 404ddce27b23 -r c13ebed437cb misc/libphysfs/archiver_unpacked.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/archiver_unpacked.c Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,470 @@
+/*
+ * High-level PhysicsFS archiver for simple unpacked file formats.
+ *
+ * This is a framework that basic archivers build on top of. It's for simple
+ * formats that can just hand back a list of files and the offsets of their
+ * uncompressed data. There are an alarming number of formats like this.
+ *
+ * RULES: Archive entries must be uncompressed, must not have separate subdir
+ * entries (but can have subdirs), must be case insensitive LOW ASCII
+ * filenames <= 56 bytes. No symlinks, etc. We can relax some of these rules
+ * as necessary.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ * This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+typedef struct
+{
+ PHYSFS_Io *io;
+ PHYSFS_uint32 entryCount;
+ UNPKentry *entries;
+} UNPKinfo;
+
+
+typedef struct
+{
+ PHYSFS_Io *io;
+ UNPKentry *entry;
+ PHYSFS_uint32 curPos;
+} UNPKfileinfo;
+
+
+void UNPK_closeArchive(PHYSFS_Dir *opaque)
+{
+ UNPKinfo *info = ((UNPKinfo *) opaque);
+ info->io->destroy(info->io);
+ allocator.Free(info->entries);
+ allocator.Free(info);
+} /* UNPK_closeArchive */
+
+
+static PHYSFS_sint64 UNPK_read(PHYSFS_Io *io, void *buffer, PHYSFS_uint64 len)
+{
+ UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque;
+ const UNPKentry *entry = finfo->entry;
+ const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos);
+ PHYSFS_sint64 rc;
+
+ if (bytesLeft < len)
+ len = bytesLeft;
+
+ rc = finfo->io->read(finfo->io, buffer, len);
+ if (rc > 0)
+ finfo->curPos += (PHYSFS_uint32) rc;
+
+ return rc;
+} /* UNPK_read */
+
+
+static PHYSFS_sint64 UNPK_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
+{
+ BAIL_MACRO(PHYSFS_ERR_READ_ONLY, -1);
+} /* UNPK_write */
+
+
+static PHYSFS_sint64 UNPK_tell(PHYSFS_Io *io)
+{
+ return ((UNPKfileinfo *) io->opaque)->curPos;
+} /* UNPK_tell */
+
+
+static int UNPK_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
+{
+ UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque;
+ const UNPKentry *entry = finfo->entry;
+ int rc;
+
+ BAIL_IF_MACRO(offset >= entry->size, PHYSFS_ERR_PAST_EOF, 0);
+ rc = finfo->io->seek(finfo->io, entry->startPos + offset);
+ if (rc)
+ finfo->curPos = (PHYSFS_uint32) offset;
+
+ return rc;
+} /* UNPK_seek */
+
+
+static PHYSFS_sint64 UNPK_length(PHYSFS_Io *io)
+{
+ const UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque;
+ return ((PHYSFS_sint64) finfo->entry->size);
+} /* UNPK_length */
+
+
+static PHYSFS_Io *UNPK_duplicate(PHYSFS_Io *_io)
+{
+ UNPKfileinfo *origfinfo = (UNPKfileinfo *) _io->opaque;
+ PHYSFS_Io *io = NULL;
+ PHYSFS_Io *retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
+ UNPKfileinfo *finfo = (UNPKfileinfo *) allocator.Malloc(sizeof (UNPKfileinfo));
+ GOTO_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, UNPK_duplicate_failed);
+ GOTO_IF_MACRO(!finfo, PHYSFS_ERR_OUT_OF_MEMORY, UNPK_duplicate_failed);
+
+ io = origfinfo->io->duplicate(origfinfo->io);
+ if (!io) goto UNPK_duplicate_failed;
+ finfo->io = io;
+ finfo->entry = origfinfo->entry;
+ finfo->curPos = 0;
+ memcpy(retval, _io, sizeof (PHYSFS_Io));
+ retval->opaque = finfo;
+ return retval;
+
+UNPK_duplicate_failed:
+ if (finfo != NULL) allocator.Free(finfo);
+ if (retval != NULL) allocator.Free(retval);
+ if (io != NULL) io->destroy(io);
+ return NULL;
+} /* UNPK_duplicate */
+
+static int UNPK_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
+
+static void UNPK_destroy(PHYSFS_Io *io)
+{
+ UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque;
+ finfo->io->destroy(finfo->io);
+ allocator.Free(finfo);
+ allocator.Free(io);
+} /* UNPK_destroy */
+
+
+static const PHYSFS_Io UNPK_Io =
+{
+ CURRENT_PHYSFS_IO_API_VERSION, NULL,
+ UNPK_read,
+ UNPK_write,
+ UNPK_seek,
+ UNPK_tell,
+ UNPK_length,
+ UNPK_duplicate,
+ UNPK_flush,
+ UNPK_destroy
+};
+
+
+static int entryCmp(void *_a, size_t one, size_t two)
+{
+ if (one != two)
+ {
+ const UNPKentry *a = (const UNPKentry *) _a;
+ return __PHYSFS_stricmpASCII(a[one].name, a[two].name);
+ } /* if */
+
+ return 0;
+} /* entryCmp */
+
+
+static void entrySwap(void *_a, size_t one, size_t two)
+{
+ if (one != two)
+ {
+ UNPKentry tmp;
+ UNPKentry *first = &(((UNPKentry *) _a)[one]);
+ UNPKentry *second = &(((UNPKentry *) _a)[two]);
+ memcpy(&tmp, first, sizeof (UNPKentry));
+ memcpy(first, second, sizeof (UNPKentry));
+ memcpy(second, &tmp, sizeof (UNPKentry));
+ } /* if */
+} /* entrySwap */
+
+
+static PHYSFS_sint32 findStartOfDir(UNPKinfo *info, const char *path,
+ int stop_on_first_find)
+{
+ PHYSFS_sint32 lo = 0;
+ PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
+ PHYSFS_sint32 middle;
+ PHYSFS_uint32 dlen = (PHYSFS_uint32) strlen(path);
+ PHYSFS_sint32 retval = -1;
+ const char *name;
+ int rc;
+
+ if (*path == '\0') /* root dir? */
+ return 0;
+
+ if ((dlen > 0) && (path[dlen - 1] == '/')) /* ignore trailing slash. */
+ dlen--;
+
+ while (lo <= hi)
+ {
+ middle = lo + ((hi - lo) / 2);
+ name = info->entries[middle].name;
+ rc = __PHYSFS_strnicmpASCII(path, name, dlen);
+ if (rc == 0)
+ {
+ char ch = name[dlen];
+ if (ch < '/') /* make sure this isn't just a substr match. */
+ rc = -1;
+ else if (ch > '/')
+ rc = 1;
+ else
+ {
+ if (stop_on_first_find) /* Just checking dir's existance? */
+ return middle;
+
+ if (name[dlen + 1] == '\0') /* Skip initial dir entry. */
+ return (middle + 1);
+
+ /* there might be more entries earlier in the list. */
+ retval = middle;
+ hi = middle - 1;
+ } /* else */
+ } /* if */
+
+ if (rc > 0)
+ lo = middle + 1;
+ else
+ hi = middle - 1;
+ } /* while */
+
+ return retval;
+} /* findStartOfDir */
+
+
+/*
+ * Moved to seperate function so we can use alloca then immediately throw
+ * away the allocated stack space...
+ */
+static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata,
+ const char *odir, const char *str, PHYSFS_sint32 ln)
+{
+ char *newstr = __PHYSFS_smallAlloc(ln + 1);
+ if (newstr == NULL)
+ return;
+
+ memcpy(newstr, str, ln);
+ newstr[ln] = '\0';
+ cb(callbackdata, odir, newstr);
+ __PHYSFS_smallFree(newstr);
+} /* doEnumCallback */
+
+
+void UNPK_enumerateFiles(PHYSFS_Dir *opaque, const char *dname,
+ int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+ const char *origdir, void *callbackdata)
+{
+ UNPKinfo *info = ((UNPKinfo *) opaque);
+ PHYSFS_sint32 dlen, dlen_inc, max, i;
+
+ i = findStartOfDir(info, dname, 0);
+ if (i == -1) /* no such directory. */
+ return;
+
+ dlen = (PHYSFS_sint32) strlen(dname);
+ if ((dlen > 0) && (dname[dlen - 1] == '/')) /* ignore trailing slash. */
+ dlen--;
+
+ dlen_inc = ((dlen > 0) ? 1 : 0) + dlen;
+ max = (PHYSFS_sint32) info->entryCount;
+ while (i < max)
+ {
+ char *add;
+ char *ptr;
+ PHYSFS_sint32 ln;
+ char *e = info->entries[i].name;
+ if ((dlen) &&
+ ((__PHYSFS_strnicmpASCII(e, dname, dlen)) || (e[dlen] != '/')))
+ {
+ break; /* past end of this dir; we're done. */
+ } /* if */
+
+ add = e + dlen_inc;
+ ptr = strchr(add, '/');
+ ln = (PHYSFS_sint32) ((ptr) ? ptr-add : strlen(add));
+ doEnumCallback(cb, callbackdata, origdir, add, ln);
+ ln += dlen_inc; /* point past entry to children... */
+
+ /* increment counter and skip children of subdirs... */
+ while ((++i < max) && (ptr != NULL))
+ {
+ char *e_new = info->entries[i].name;
+ if ((__PHYSFS_strnicmpASCII(e, e_new, ln) != 0) ||
+ (e_new[ln] != '/'))
+ {
+ break;
+ } /* if */
+ } /* while */
+ } /* while */
+} /* UNPK_enumerateFiles */
+
+
+/*
+ * This will find the UNPKentry associated with a path in platform-independent
+ * notation. Directories don't have UNPKentries associated with them, but
+ * (*isDir) will be set to non-zero if a dir was hit.
+ */
+static UNPKentry *findEntry(const UNPKinfo *info, const char *path, int *isDir)
+{
+ UNPKentry *a = info->entries;
+ PHYSFS_sint32 pathlen = (PHYSFS_sint32) strlen(path);
+ PHYSFS_sint32 lo = 0;
+ PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
+ PHYSFS_sint32 middle;
+ const char *thispath = NULL;
+ int rc;
+
+ while (lo <= hi)
+ {
+ middle = lo + ((hi - lo) / 2);
+ thispath = a[middle].name;
+ rc = __PHYSFS_strnicmpASCII(path, thispath, pathlen);
+
+ if (rc > 0)
+ lo = middle + 1;
+
+ else if (rc < 0)
+ hi = middle - 1;
+
+ else /* substring match...might be dir or entry or nothing. */
+ {
+ if (isDir != NULL)
+ {
+ *isDir = (thispath[pathlen] == '/');
+ if (*isDir)
+ return NULL;
+ } /* if */
+
+ if (thispath[pathlen] == '\0') /* found entry? */
+ return &a[middle];
+ /* adjust search params, try again. */
+ else if (thispath[pathlen] > '/')
+ hi = middle - 1;
+ else
+ lo = middle + 1;
+ } /* if */
+ } /* while */
+
+ if (isDir != NULL)
+ *isDir = 0;
+
+ BAIL_MACRO(PHYSFS_ERR_NO_SUCH_PATH, NULL);
+} /* findEntry */
+
+
+PHYSFS_Io *UNPK_openRead(PHYSFS_Dir *opaque, const char *fnm, int *fileExists)
+{
+ PHYSFS_Io *retval = NULL;
+ UNPKinfo *info = (UNPKinfo *) opaque;
+ UNPKfileinfo *finfo = NULL;
+ int isdir = 0;
+ UNPKentry *entry = findEntry(info, fnm, &isdir);
+
+ *fileExists = (entry != NULL);
+ GOTO_IF_MACRO(isdir, PHYSFS_ERR_NOT_A_FILE, UNPK_openRead_failed);
+ GOTO_IF_MACRO(!entry, ERRPASS, UNPK_openRead_failed);
+
+ retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
+ GOTO_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, UNPK_openRead_failed);
+
+ finfo = (UNPKfileinfo *) allocator.Malloc(sizeof (UNPKfileinfo));
+ GOTO_IF_MACRO(!finfo, PHYSFS_ERR_OUT_OF_MEMORY, UNPK_openRead_failed);
+
+ finfo->io = info->io->duplicate(info->io);
+ GOTO_IF_MACRO(!finfo->io, ERRPASS, UNPK_openRead_failed);
+
+ if (!finfo->io->seek(finfo->io, entry->startPos))
+ goto UNPK_openRead_failed;
+
+ finfo->curPos = 0;
+ finfo->entry = entry;
+
+ memcpy(retval, &UNPK_Io, sizeof (*retval));
+ retval->opaque = finfo;
+ return retval;
+
+UNPK_openRead_failed:
+ if (finfo != NULL)
+ {
+ if (finfo->io != NULL)
+ finfo->io->destroy(finfo->io);
+ allocator.Free(finfo);
+ } /* if */
+
+ if (retval != NULL)
+ allocator.Free(retval);
+
+ return NULL;
+} /* UNPK_openRead */
+
+
+PHYSFS_Io *UNPK_openWrite(PHYSFS_Dir *opaque, const char *name)
+{
+ BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
+} /* UNPK_openWrite */
+
+
+PHYSFS_Io *UNPK_openAppend(PHYSFS_Dir *opaque, const char *name)
+{
+ BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
+} /* UNPK_openAppend */
+
+
+int UNPK_remove(PHYSFS_Dir *opaque, const char *name)
+{
+ BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
+} /* UNPK_remove */
+
+
+int UNPK_mkdir(PHYSFS_Dir *opaque, const char *name)
+{
+ BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
+} /* UNPK_mkdir */
+
+
+int UNPK_stat(PHYSFS_Dir *opaque, const char *filename,
+ int *exists, PHYSFS_Stat *stat)
+{
+ int isDir = 0;
+ const UNPKinfo *info = (const UNPKinfo *) opaque;
+ const UNPKentry *entry = findEntry(info, filename, &isDir);
+
+ if (isDir)
+ {
+ *exists = 1;
+ stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
+ stat->filesize = 0;
+ } /* if */
+ else if (entry != NULL)
+ {
+ *exists = 1;
+ stat->filetype = PHYSFS_FILETYPE_REGULAR;
+ stat->filesize = entry->size;
+ } /* else if */
+ else
+ {
+ *exists = 0;
+ return 0;
+ } /* else */
+
+ stat->modtime = -1;
+ stat->createtime = -1;
+ stat->accesstime = -1;
+ stat->readonly = 1;
+
+ return 1;
+} /* UNPK_stat */
+
+
+PHYSFS_Dir *UNPK_openArchive(PHYSFS_Io *io, UNPKentry *e,
+ const PHYSFS_uint32 num)
+{
+ UNPKinfo *info = (UNPKinfo *) allocator.Malloc(sizeof (UNPKinfo));
+ if (info == NULL)
+ {
+ allocator.Free(e);
+ BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ } /* if */
+
+ __PHYSFS_sort(e, (size_t) num, entryCmp, entrySwap);
+ info->io = io;
+ info->entryCount = num;
+ info->entries = e;
+
+ return info;
+} /* UNPK_openArchive */
+
+/* end of archiver_unpacked.c ... */
+
diff -r 404ddce27b23 -r c13ebed437cb misc/libphysfs/archiver_wad.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/archiver_wad.c Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,127 @@
+/*
+ * WAD support routines for PhysicsFS.
+ *
+ * This driver handles DOOM engine archives ("wads").
+ * This format (but not this driver) was designed by id Software for use
+ * with the DOOM engine.
+ * The specs of the format are from the unofficial doom specs v1.666
+ * found here: http://www.gamers.org/dhs/helpdocs/dmsp1666.html
+ * The format of the archive: (from the specs)
+ *
+ * A WAD file has three parts:
+ * (1) a twelve-byte header
+ * (2) one or more "lumps"
+ * (3) a directory or "info table" that contains the names, offsets, and
+ * sizes of all the lumps in the WAD
+ *
+ * The header consists of three four-byte parts:
+ * (a) an ASCII string which must be either "IWAD" or "PWAD"
+ * (b) a 4-byte (long) integer which is the number of lumps in the wad
+ * (c) a long integer which is the file offset to the start of
+ * the directory
+ *
+ * The directory has one 16-byte entry for every lump. Each entry consists
+ * of three parts:
+ *
+ * (a) a long integer, the file offset to the start of the lump
+ * (b) a long integer, the size of the lump in bytes
+ * (c) an 8-byte ASCII string, the name of the lump, padded with zeros.
+ * For example, the "DEMO1" entry in hexadecimal would be
+ * (44 45 4D 4F 31 00 00 00)
+ *
+ * Note that there is no way to tell if an opened WAD archive is a
+ * IWAD or PWAD with this archiver.
+ * I couldn't think of a way to provide that information, without being too
+ * hacky.
+ * I don't think it's really that important though.
+ *
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ * This file written by Travis Wells, based on the GRP archiver by
+ * Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+#if PHYSFS_SUPPORTS_WAD
+
+static UNPKentry *wadLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 fileCount)
+{
+ PHYSFS_uint32 directoryOffset;
+ UNPKentry *entries = NULL;
+ UNPKentry *entry = NULL;
+
+ BAIL_IF_MACRO(!__PHYSFS_readAll(io, &directoryOffset, 4), ERRPASS, 0);
+ directoryOffset = PHYSFS_swapULE32(directoryOffset);
+
+ BAIL_IF_MACRO(!io->seek(io, directoryOffset), ERRPASS, 0);
+
+ entries = (UNPKentry *) allocator.Malloc(sizeof (UNPKentry) * fileCount);
+ BAIL_IF_MACRO(!entries, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+
+ for (entry = entries; fileCount > 0; fileCount--, entry++)
+ {
+ if (!__PHYSFS_readAll(io, &entry->startPos, 4)) goto failed;
+ if (!__PHYSFS_readAll(io, &entry->size, 4)) goto failed;
+ if (!__PHYSFS_readAll(io, &entry->name, 8)) goto failed;
+
+ entry->name[8] = '\0'; /* name might not be null-terminated in file. */
+ entry->size = PHYSFS_swapULE32(entry->size);
+ entry->startPos = PHYSFS_swapULE32(entry->startPos);
+ } /* for */
+
+ return entries;
+
+failed:
+ allocator.Free(entries);
+ return NULL;
+} /* wadLoadEntries */
+
+
+static void *WAD_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
+{
+ PHYSFS_uint8 buf[4];
+ UNPKentry *entries = NULL;
+ PHYSFS_uint32 count = 0;
+
+ assert(io != NULL); /* shouldn't ever happen. */
+
+ BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
+ BAIL_IF_MACRO(!__PHYSFS_readAll(io, buf, sizeof (buf)), ERRPASS, NULL);
+ if ((memcmp(buf, "IWAD", 4) != 0) && (memcmp(buf, "PWAD", 4) != 0))
+ BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL);
+
+ BAIL_IF_MACRO(!__PHYSFS_readAll(io, &count, sizeof (count)), ERRPASS, NULL);
+ count = PHYSFS_swapULE32(count);
+
+ entries = wadLoadEntries(io, count);
+ BAIL_IF_MACRO(!entries, ERRPASS, NULL);
+ return UNPK_openArchive(io, entries, count);
+} /* WAD_openArchive */
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_WAD =
+{
+ {
+ "WAD",
+ "DOOM engine format",
+ "Travis Wells ",
+ "http://www.3dmm2.com/doom/",
+ },
+ WAD_openArchive, /* openArchive() method */
+ UNPK_enumerateFiles, /* enumerateFiles() method */
+ UNPK_openRead, /* openRead() method */
+ UNPK_openWrite, /* openWrite() method */
+ UNPK_openAppend, /* openAppend() method */
+ UNPK_remove, /* remove() method */
+ UNPK_mkdir, /* mkdir() method */
+ UNPK_closeArchive, /* closeArchive() method */
+ UNPK_stat /* stat() method */
+};
+
+#endif /* defined PHYSFS_SUPPORTS_WAD */
+
+/* end of wad.c ... */
+
diff -r 404ddce27b23 -r c13ebed437cb misc/libphysfs/archiver_zip.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/archiver_zip.c Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,1717 @@
+/*
+ * ZIP support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ * This file written by Ryan C. Gordon, with some peeking at "unzip.c"
+ * by Gilles Vollant.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+#if PHYSFS_SUPPORTS_ZIP
+
+#include
+#include
+
+#define USE_MINIZ 1
+#if USE_MINIZ
+#include "physfs_miniz.h"
+#else
+#include
+#endif
+
+/*
+ * A buffer of ZIP_READBUFSIZE is allocated for each compressed file opened,
+ * and is freed when you close the file; compressed data is read into
+ * this buffer, and then is decompressed into the buffer passed to
+ * PHYSFS_read().
+ *
+ * Uncompressed entries in a zipfile do not allocate this buffer; they just
+ * read data directly into the buffer passed to PHYSFS_read().
+ *
+ * Depending on your speed and memory requirements, you should tweak this
+ * value.
+ */
+#define ZIP_READBUFSIZE (16 * 1024)
+
+
+/*
+ * Entries are "unresolved" until they are first opened. At that time,
+ * local file headers parsed/validated, data offsets will be updated to look
+ * at the actual file data instead of the header, and symlinks will be
+ * followed and optimized. This means that we don't seek and read around the
+ * archive until forced to do so, and after the first time, we had to do
+ * less reading and parsing, which is very CD-ROM friendly.
+ */
+typedef enum
+{
+ ZIP_UNRESOLVED_FILE,
+ ZIP_UNRESOLVED_SYMLINK,
+ ZIP_RESOLVING,
+ ZIP_RESOLVED,
+ ZIP_BROKEN_FILE,
+ ZIP_BROKEN_SYMLINK
+} ZipResolveType;
+
+
+/*
+ * One ZIPentry is kept for each file in an open ZIP archive.
+ */
+typedef struct _ZIPentry
+{
+ char *name; /* Name of file in archive */
+ struct _ZIPentry *symlink; /* NULL or file we symlink to */
+ ZipResolveType resolved; /* Have we resolved file/symlink? */
+ PHYSFS_uint64 offset; /* offset of data in archive */
+ PHYSFS_uint16 version; /* version made by */
+ PHYSFS_uint16 version_needed; /* version needed to extract */
+ PHYSFS_uint16 compression_method; /* compression method */
+ PHYSFS_uint32 crc; /* crc-32 */
+ PHYSFS_uint64 compressed_size; /* compressed size */
+ PHYSFS_uint64 uncompressed_size; /* uncompressed size */
+ PHYSFS_sint64 last_mod_time; /* last file mod time */
+} ZIPentry;
+
+/*
+ * One ZIPinfo is kept for each open ZIP archive.
+ */
+typedef struct
+{
+ PHYSFS_Io *io;
+ int zip64; /* non-zero if this is a Zip64 archive. */
+ PHYSFS_uint64 entryCount; /* Number of files in ZIP. */
+ ZIPentry *entries; /* info on all files in ZIP. */
+} ZIPinfo;
+
+/*
+ * One ZIPfileinfo is kept for each open file in a ZIP archive.
+ */
+typedef struct
+{
+ ZIPentry *entry; /* Info on file. */
+ PHYSFS_Io *io; /* physical file handle. */
+ PHYSFS_uint32 compressed_position; /* offset in compressed data. */
+ PHYSFS_uint32 uncompressed_position; /* tell() position. */
+ PHYSFS_uint8 *buffer; /* decompression buffer. */
+ z_stream stream; /* zlib stream state. */
+} ZIPfileinfo;
+
+
+/* Magic numbers... */
+#define ZIP_LOCAL_FILE_SIG 0x04034b50
+#define ZIP_CENTRAL_DIR_SIG 0x02014b50
+#define ZIP_END_OF_CENTRAL_DIR_SIG 0x06054b50
+#define ZIP64_END_OF_CENTRAL_DIR_SIG 0x06064b50
+#define ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIG 0x07064b50
+#define ZIP64_EXTENDED_INFO_EXTRA_FIELD_SIG 0x0001
+
+/* compression methods... */
+#define COMPMETH_NONE 0
+/* ...and others... */
+
+
+#define UNIX_FILETYPE_MASK 0170000
+#define UNIX_FILETYPE_SYMLINK 0120000
+
+
+/*
+ * Bridge physfs allocation functions to zlib's format...
+ */
+static voidpf zlibPhysfsAlloc(voidpf opaque, uInt items, uInt size)
+{
+ return ((PHYSFS_Allocator *) opaque)->Malloc(items * size);
+} /* zlibPhysfsAlloc */
+
+/*
+ * Bridge physfs allocation functions to zlib's format...
+ */
+static void zlibPhysfsFree(voidpf opaque, voidpf address)
+{
+ ((PHYSFS_Allocator *) opaque)->Free(address);
+} /* zlibPhysfsFree */
+
+
+/*
+ * Construct a new z_stream to a sane state.
+ */
+static void initializeZStream(z_stream *pstr)
+{
+ memset(pstr, '\0', sizeof (z_stream));
+ pstr->zalloc = zlibPhysfsAlloc;
+ pstr->zfree = zlibPhysfsFree;
+ pstr->opaque = &allocator;
+} /* initializeZStream */
+
+
+static PHYSFS_ErrorCode zlib_error_code(int rc)
+{
+ switch (rc)
+ {
+ case Z_OK: return PHYSFS_ERR_OK; /* not an error. */
+ case Z_STREAM_END: return PHYSFS_ERR_OK; /* not an error. */
+ case Z_ERRNO: return PHYSFS_ERR_IO;
+ case Z_MEM_ERROR: return PHYSFS_ERR_OUT_OF_MEMORY;
+ default: return PHYSFS_ERR_CORRUPT;
+ } /* switch */
+} /* zlib_error_string */
+
+
+/*
+ * Wrap all zlib calls in this, so the physfs error state is set appropriately.
+ */
+static int zlib_err(const int rc)
+{
+ __PHYSFS_setError(zlib_error_code(rc));
+ return rc;
+} /* zlib_err */
+
+
+/*
+ * Read an unsigned 64-bit int and swap to native byte order.
+ */
+static int readui64(PHYSFS_Io *io, PHYSFS_uint64 *val)
+{
+ PHYSFS_uint64 v;
+ BAIL_IF_MACRO(!__PHYSFS_readAll(io, &v, sizeof (v)), ERRPASS, 0);
+ *val = PHYSFS_swapULE64(v);
+ return 1;
+} /* readui64 */
+
+/*
+ * Read an unsigned 32-bit int and swap to native byte order.
+ */
+static int readui32(PHYSFS_Io *io, PHYSFS_uint32 *val)
+{
+ PHYSFS_uint32 v;
+ BAIL_IF_MACRO(!__PHYSFS_readAll(io, &v, sizeof (v)), ERRPASS, 0);
+ *val = PHYSFS_swapULE32(v);
+ return 1;
+} /* readui32 */
+
+
+/*
+ * Read an unsigned 16-bit int and swap to native byte order.
+ */
+static int readui16(PHYSFS_Io *io, PHYSFS_uint16 *val)
+{
+ PHYSFS_uint16 v;
+ BAIL_IF_MACRO(!__PHYSFS_readAll(io, &v, sizeof (v)), ERRPASS, 0);
+ *val = PHYSFS_swapULE16(v);
+ return 1;
+} /* readui16 */
+
+
+static PHYSFS_sint64 ZIP_read(PHYSFS_Io *_io, void *buf, PHYSFS_uint64 len)
+{
+ ZIPfileinfo *finfo = (ZIPfileinfo *) _io->opaque;
+ PHYSFS_Io *io = finfo->io;
+ ZIPentry *entry = finfo->entry;
+ PHYSFS_sint64 retval = 0;
+ PHYSFS_sint64 maxread = (PHYSFS_sint64) len;
+ PHYSFS_sint64 avail = entry->uncompressed_size -
+ finfo->uncompressed_position;
+
+ if (avail < maxread)
+ maxread = avail;
+
+ BAIL_IF_MACRO(maxread == 0, ERRPASS, 0); /* quick rejection. */
+
+ if (entry->compression_method == COMPMETH_NONE)
+ retval = io->read(io, buf, maxread);
+ else
+ {
+ finfo->stream.next_out = buf;
+ finfo->stream.avail_out = (uInt) maxread;
+
+ while (retval < maxread)
+ {
+ PHYSFS_uint32 before = finfo->stream.total_out;
+ int rc;
+
+ if (finfo->stream.avail_in == 0)
+ {
+ PHYSFS_sint64 br;
+
+ br = entry->compressed_size - finfo->compressed_position;
+ if (br > 0)
+ {
+ if (br > ZIP_READBUFSIZE)
+ br = ZIP_READBUFSIZE;
+
+ br = io->read(io, finfo->buffer, (PHYSFS_uint64) br);
+ if (br <= 0)
+ break;
+
+ finfo->compressed_position += (PHYSFS_uint32) br;
+ finfo->stream.next_in = finfo->buffer;
+ finfo->stream.avail_in = (PHYSFS_uint32) br;
+ } /* if */
+ } /* if */
+
+ rc = zlib_err(inflate(&finfo->stream, Z_SYNC_FLUSH));
+ retval += (finfo->stream.total_out - before);
+
+ if (rc != Z_OK)
+ break;
+ } /* while */
+ } /* else */
+
+ if (retval > 0)
+ finfo->uncompressed_position += (PHYSFS_uint32) retval;
+
+ return retval;
+} /* ZIP_read */
+
+
+static PHYSFS_sint64 ZIP_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
+{
+ BAIL_MACRO(PHYSFS_ERR_READ_ONLY, -1);
+} /* ZIP_write */
+
+
+static PHYSFS_sint64 ZIP_tell(PHYSFS_Io *io)
+{
+ return ((ZIPfileinfo *) io->opaque)->uncompressed_position;
+} /* ZIP_tell */
+
+
+static int ZIP_seek(PHYSFS_Io *_io, PHYSFS_uint64 offset)
+{
+ ZIPfileinfo *finfo = (ZIPfileinfo *) _io->opaque;
+ ZIPentry *entry = finfo->entry;
+ PHYSFS_Io *io = finfo->io;
+
+ BAIL_IF_MACRO(offset > entry->uncompressed_size, PHYSFS_ERR_PAST_EOF, 0);
+
+ if (entry->compression_method == COMPMETH_NONE)
+ {
+ const PHYSFS_sint64 newpos = offset + entry->offset;
+ BAIL_IF_MACRO(!io->seek(io, newpos), ERRPASS, 0);
+ finfo->uncompressed_position = (PHYSFS_uint32) offset;
+ } /* if */
+
+ else
+ {
+ /*
+ * If seeking backwards, we need to redecode the file
+ * from the start and throw away the compressed bits until we hit
+ * the offset we need. If seeking forward, we still need to
+ * decode, but we don't rewind first.
+ */
+ if (offset < finfo->uncompressed_position)
+ {
+ /* we do a copy so state is sane if inflateInit2() fails. */
+ z_stream str;
+ initializeZStream(&str);
+ if (zlib_err(inflateInit2(&str, -MAX_WBITS)) != Z_OK)
+ return 0;
+
+ if (!io->seek(io, entry->offset))
+ return 0;
+
+ inflateEnd(&finfo->stream);
+ memcpy(&finfo->stream, &str, sizeof (z_stream));
+ finfo->uncompressed_position = finfo->compressed_position = 0;
+ } /* if */
+
+ while (finfo->uncompressed_position != offset)
+ {
+ PHYSFS_uint8 buf[512];
+ PHYSFS_uint32 maxread;
+
+ maxread = (PHYSFS_uint32) (offset - finfo->uncompressed_position);
+ if (maxread > sizeof (buf))
+ maxread = sizeof (buf);
+
+ if (ZIP_read(_io, buf, maxread) != maxread)
+ return 0;
+ } /* while */
+ } /* else */
+
+ return 1;
+} /* ZIP_seek */
+
+
+static PHYSFS_sint64 ZIP_length(PHYSFS_Io *io)
+{
+ const ZIPfileinfo *finfo = (ZIPfileinfo *) io->opaque;
+ return (PHYSFS_sint64) finfo->entry->uncompressed_size;
+} /* ZIP_length */
+
+
+static PHYSFS_Io *zip_get_io(PHYSFS_Io *io, ZIPinfo *inf, ZIPentry *entry);
+
+static PHYSFS_Io *ZIP_duplicate(PHYSFS_Io *io)
+{
+ ZIPfileinfo *origfinfo = (ZIPfileinfo *) io->opaque;
+ PHYSFS_Io *retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
+ ZIPfileinfo *finfo = (ZIPfileinfo *) allocator.Malloc(sizeof (ZIPfileinfo));
+ GOTO_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, failed);
+ GOTO_IF_MACRO(!finfo, PHYSFS_ERR_OUT_OF_MEMORY, failed);
+ memset(finfo, '\0', sizeof (*finfo));
+
+ finfo->entry = origfinfo->entry;
+ finfo->io = zip_get_io(origfinfo->io, NULL, finfo->entry);
+ GOTO_IF_MACRO(!finfo->io, ERRPASS, failed);
+
+ if (finfo->entry->compression_method != COMPMETH_NONE)
+ {
+ finfo->buffer = (PHYSFS_uint8 *) allocator.Malloc(ZIP_READBUFSIZE);
+ GOTO_IF_MACRO(!finfo->buffer, PHYSFS_ERR_OUT_OF_MEMORY, failed);
+ if (zlib_err(inflateInit2(&finfo->stream, -MAX_WBITS)) != Z_OK)
+ goto failed;
+ } /* if */
+
+ memcpy(retval, io, sizeof (PHYSFS_Io));
+ retval->opaque = finfo;
+ return retval;
+
+failed:
+ if (finfo != NULL)
+ {
+ if (finfo->io != NULL)
+ finfo->io->destroy(finfo->io);
+
+ if (finfo->buffer != NULL)
+ {
+ allocator.Free(finfo->buffer);
+ inflateEnd(&finfo->stream);
+ } /* if */
+
+ allocator.Free(finfo);
+ } /* if */
+
+ if (retval != NULL)
+ allocator.Free(retval);
+
+ return NULL;
+} /* ZIP_duplicate */
+
+static int ZIP_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
+
+static void ZIP_destroy(PHYSFS_Io *io)
+{
+ ZIPfileinfo *finfo = (ZIPfileinfo *) io->opaque;
+ finfo->io->destroy(finfo->io);
+
+ if (finfo->entry->compression_method != COMPMETH_NONE)
+ inflateEnd(&finfo->stream);
+
+ if (finfo->buffer != NULL)
+ allocator.Free(finfo->buffer);
+
+ allocator.Free(finfo);
+ allocator.Free(io);
+} /* ZIP_destroy */
+
+
+static const PHYSFS_Io ZIP_Io =
+{
+ CURRENT_PHYSFS_IO_API_VERSION, NULL,
+ ZIP_read,
+ ZIP_write,
+ ZIP_seek,
+ ZIP_tell,
+ ZIP_length,
+ ZIP_duplicate,
+ ZIP_flush,
+ ZIP_destroy
+};
+
+
+
+static PHYSFS_sint64 zip_find_end_of_central_dir(PHYSFS_Io *io, PHYSFS_sint64 *len)
+{
+ PHYSFS_uint8 buf[256];
+ PHYSFS_uint8 extra[4] = { 0, 0, 0, 0 };
+ PHYSFS_sint32 i = 0;
+ PHYSFS_sint64 filelen;
+ PHYSFS_sint64 filepos;
+ PHYSFS_sint32 maxread;
+ PHYSFS_sint32 totalread = 0;
+ int found = 0;
+
+ filelen = io->length(io);
+ BAIL_IF_MACRO(filelen == -1, ERRPASS, 0);
+
+ /*
+ * Jump to the end of the file and start reading backwards.
+ * The last thing in the file is the zipfile comment, which is variable
+ * length, and the field that specifies its size is before it in the
+ * file (argh!)...this means that we need to scan backwards until we
+ * hit the end-of-central-dir signature. We can then sanity check that
+ * the comment was as big as it should be to make sure we're in the
+ * right place. The comment length field is 16 bits, so we can stop
+ * searching for that signature after a little more than 64k at most,
+ * and call it a corrupted zipfile.
+ */
+
+ if (sizeof (buf) < filelen)
+ {
+ filepos = filelen - sizeof (buf);
+ maxread = sizeof (buf);
+ } /* if */
+ else
+ {
+ filepos = 0;
+ maxread = (PHYSFS_uint32) filelen;
+ } /* else */
+
+ while ((totalread < filelen) && (totalread < 65557))
+ {
+ BAIL_IF_MACRO(!io->seek(io, filepos), ERRPASS, -1);
+
+ /* make sure we catch a signature between buffers. */
+ if (totalread != 0)
+ {
+ if (!__PHYSFS_readAll(io, buf, maxread - 4))
+ return -1;
+ memcpy(&buf[maxread - 4], &extra, sizeof (extra));
+ totalread += maxread - 4;
+ } /* if */
+ else
+ {
+ if (!__PHYSFS_readAll(io, buf, maxread))
+ return -1;
+ totalread += maxread;
+ } /* else */
+
+ memcpy(&extra, buf, sizeof (extra));
+
+ for (i = maxread - 4; i > 0; i--)
+ {
+ if ((buf[i + 0] == 0x50) &&
+ (buf[i + 1] == 0x4B) &&
+ (buf[i + 2] == 0x05) &&
+ (buf[i + 3] == 0x06) )
+ {
+ found = 1; /* that's the signature! */
+ break;
+ } /* if */
+ } /* for */
+
+ if (found)
+ break;
+
+ filepos -= (maxread - 4);
+ if (filepos < 0)
+ filepos = 0;
+ } /* while */
+
+ BAIL_IF_MACRO(!found, PHYSFS_ERR_UNSUPPORTED, -1);
+
+ if (len != NULL)
+ *len = filelen;
+
+ return (filepos + i);
+} /* zip_find_end_of_central_dir */
+
+
+static int isZip(PHYSFS_Io *io)
+{
+ PHYSFS_uint32 sig = 0;
+ int retval = 0;
+
+ /*
+ * The first thing in a zip file might be the signature of the
+ * first local file record, so it makes for a quick determination.
+ */
+ if (readui32(io, &sig))
+ {
+ retval = (sig == ZIP_LOCAL_FILE_SIG);
+ if (!retval)
+ {
+ /*
+ * No sig...might be a ZIP with data at the start
+ * (a self-extracting executable, etc), so we'll have to do
+ * it the hard way...
+ */
+ retval = (zip_find_end_of_central_dir(io, NULL) != -1);
+ } /* if */
+ } /* if */
+
+ return retval;
+} /* isZip */
+
+
+static void zip_free_entries(ZIPentry *entries, PHYSFS_uint64 max)
+{
+ PHYSFS_uint64 i;
+ for (i = 0; i < max; i++)
+ {
+ ZIPentry *entry = &entries[i];
+ if (entry->name != NULL)
+ allocator.Free(entry->name);
+ } /* for */
+
+ allocator.Free(entries);
+} /* zip_free_entries */
+
+
+/*
+ * This will find the ZIPentry associated with a path in platform-independent
+ * notation. Directories don't have ZIPentries associated with them, but
+ * (*isDir) will be set to non-zero if a dir was hit.
+ */
+static ZIPentry *zip_find_entry(const ZIPinfo *info, const char *path,
+ int *isDir)
+{
+ ZIPentry *a = info->entries;
+ PHYSFS_sint32 pathlen = (PHYSFS_sint32) strlen(path);
+ PHYSFS_sint64 lo = 0;
+ PHYSFS_sint64 hi = (PHYSFS_sint64) (info->entryCount - 1);
+ PHYSFS_sint64 middle;
+ const char *thispath = NULL;
+ int rc;
+
+ while (lo <= hi)
+ {
+ middle = lo + ((hi - lo) / 2);
+ thispath = a[middle].name;
+ rc = strncmp(path, thispath, pathlen);
+
+ if (rc > 0)
+ lo = middle + 1;
+
+ else if (rc < 0)
+ hi = middle - 1;
+
+ else /* substring match...might be dir or entry or nothing. */
+ {
+ if (isDir != NULL)
+ {
+ *isDir = (thispath[pathlen] == '/');
+ if (*isDir)
+ return NULL;
+ } /* if */
+
+ if (thispath[pathlen] == '\0') /* found entry? */
+ return &a[middle];
+ /* adjust search params, try again. */
+ else if (thispath[pathlen] > '/')
+ hi = middle - 1;
+ else
+ lo = middle + 1;
+ } /* if */
+ } /* while */
+
+ if (isDir != NULL)
+ *isDir = 0;
+
+ BAIL_MACRO(PHYSFS_ERR_NO_SUCH_PATH, NULL);
+} /* zip_find_entry */
+
+
+/* Convert paths from old, buggy DOS zippers... */
+static void zip_convert_dos_path(ZIPentry *entry, char *path)
+{
+ PHYSFS_uint8 hosttype = (PHYSFS_uint8) ((entry->version >> 8) & 0xFF);
+ if (hosttype == 0) /* FS_FAT_ */
+ {
+ while (*path)
+ {
+ if (*path == '\\')
+ *path = '/';
+ path++;
+ } /* while */
+ } /* if */
+} /* zip_convert_dos_path */
+
+
+static void zip_expand_symlink_path(char *path)
+{
+ char *ptr = path;
+ char *prevptr = path;
+
+ while (1)
+ {
+ ptr = strchr(ptr, '/');
+ if (ptr == NULL)
+ break;
+
+ if (*(ptr + 1) == '.')
+ {
+ if (*(ptr + 2) == '/')
+ {
+ /* current dir in middle of string: ditch it. */
+ memmove(ptr, ptr + 2, strlen(ptr + 2) + 1);
+ } /* else if */
+
+ else if (*(ptr + 2) == '\0')
+ {
+ /* current dir at end of string: ditch it. */
+ *ptr = '\0';
+ } /* else if */
+
+ else if (*(ptr + 2) == '.')
+ {
+ if (*(ptr + 3) == '/')
+ {
+ /* parent dir in middle: move back one, if possible. */
+ memmove(prevptr, ptr + 4, strlen(ptr + 4) + 1);
+ ptr = prevptr;
+ while (prevptr != path)
+ {
+ prevptr--;
+ if (*prevptr == '/')
+ {
+ prevptr++;
+ break;
+ } /* if */
+ } /* while */
+ } /* if */
+
+ if (*(ptr + 3) == '\0')
+ {
+ /* parent dir at end: move back one, if possible. */
+ *prevptr = '\0';
+ } /* if */
+ } /* if */
+ } /* if */
+ else
+ {
+ prevptr = ptr;
+ ptr++;
+ } /* else */
+ } /* while */
+} /* zip_expand_symlink_path */
+
+/* (forward reference: zip_follow_symlink and zip_resolve call each other.) */
+static int zip_resolve(PHYSFS_Io *io, ZIPinfo *info, ZIPentry *entry);
+
+/*
+ * Look for the entry named by (path). If it exists, resolve it, and return
+ * a pointer to that entry. If it's another symlink, keep resolving until you
+ * hit a real file and then return a pointer to the final non-symlink entry.
+ * If there's a problem, return NULL.
+ */
+static ZIPentry *zip_follow_symlink(PHYSFS_Io *io, ZIPinfo *info, char *path)
+{
+ ZIPentry *entry;
+
+ zip_expand_symlink_path(path);
+ entry = zip_find_entry(info, path, NULL);
+ if (entry != NULL)
+ {
+ if (!zip_resolve(io, info, entry)) /* recursive! */
+ entry = NULL;
+ else
+ {
+ if (entry->symlink != NULL)
+ entry = entry->symlink;
+ } /* else */
+ } /* if */
+
+ return entry;
+} /* zip_follow_symlink */
+
+
+static int zip_resolve_symlink(PHYSFS_Io *io, ZIPinfo *info, ZIPentry *entry)
+{
+ const PHYSFS_uint64 size = entry->uncompressed_size;
+ char *path = NULL;
+ int rc = 0;
+
+ /*
+ * We've already parsed the local file header of the symlink at this
+ * point. Now we need to read the actual link from the file data and
+ * follow it.
+ */
+
+ BAIL_IF_MACRO(!io->seek(io, entry->offset), ERRPASS, 0);
+
+ path = (char *) __PHYSFS_smallAlloc(size + 1);
+ BAIL_IF_MACRO(!path, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+
+ if (entry->compression_method == COMPMETH_NONE)
+ rc = __PHYSFS_readAll(io, path, size);
+
+ else /* symlink target path is compressed... */
+ {
+ z_stream stream;
+ const PHYSFS_uint64 complen = entry->compressed_size;
+ PHYSFS_uint8 *compressed = (PHYSFS_uint8*) __PHYSFS_smallAlloc(complen);
+ if (compressed != NULL)
+ {
+ if (__PHYSFS_readAll(io, compressed, complen))
+ {
+ initializeZStream(&stream);
+ stream.next_in = compressed;
+ stream.avail_in = complen;
+ stream.next_out = (unsigned char *) path;
+ stream.avail_out = size;
+ if (zlib_err(inflateInit2(&stream, -MAX_WBITS)) == Z_OK)
+ {
+ rc = zlib_err(inflate(&stream, Z_FINISH));
+ inflateEnd(&stream);
+
+ /* both are acceptable outcomes... */
+ rc = ((rc == Z_OK) || (rc == Z_STREAM_END));
+ } /* if */
+ } /* if */
+ __PHYSFS_smallFree(compressed);
+ } /* if */
+ } /* else */
+
+ if (rc)
+ {
+ path[entry->uncompressed_size] = '\0'; /* null-terminate it. */
+ zip_convert_dos_path(entry, path);
+ entry->symlink = zip_follow_symlink(io, info, path);
+ } /* else */
+
+ __PHYSFS_smallFree(path);
+
+ return (entry->symlink != NULL);
+} /* zip_resolve_symlink */
+
+
+/*
+ * Parse the local file header of an entry, and update entry->offset.
+ */
+static int zip_parse_local(PHYSFS_Io *io, ZIPentry *entry)
+{
+ PHYSFS_uint32 ui32;
+ PHYSFS_uint16 ui16;
+ PHYSFS_uint16 fnamelen;
+ PHYSFS_uint16 extralen;
+
+ /*
+ * crc and (un)compressed_size are always zero if this is a "JAR"
+ * archive created with Sun's Java tools, apparently. We only
+ * consider this archive corrupted if those entries don't match and
+ * aren't zero. That seems to work well.
+ * We also ignore a mismatch if the value is 0xFFFFFFFF here, since it's
+ * possible that's a Zip64 thing.
+ */
+
+ BAIL_IF_MACRO(!io->seek(io, entry->offset), ERRPASS, 0);
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+ BAIL_IF_MACRO(ui32 != ZIP_LOCAL_FILE_SIG, PHYSFS_ERR_CORRUPT, 0);
+ BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
+ BAIL_IF_MACRO(ui16 != entry->version_needed, PHYSFS_ERR_CORRUPT, 0);
+ BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0); /* general bits. */
+ BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
+ BAIL_IF_MACRO(ui16 != entry->compression_method, PHYSFS_ERR_CORRUPT, 0);
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0); /* date/time */
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+ BAIL_IF_MACRO(ui32 && (ui32 != entry->crc), PHYSFS_ERR_CORRUPT, 0);
+
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+ BAIL_IF_MACRO(ui32 && (ui32 != 0xFFFFFFFF) &&
+ (ui32 != entry->compressed_size), PHYSFS_ERR_CORRUPT, 0);
+
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+ BAIL_IF_MACRO(ui32 && (ui32 != 0xFFFFFFFF) &&
+ (ui32 != entry->uncompressed_size), PHYSFS_ERR_CORRUPT, 0);
+
+ BAIL_IF_MACRO(!readui16(io, &fnamelen), ERRPASS, 0);
+ BAIL_IF_MACRO(!readui16(io, &extralen), ERRPASS, 0);
+
+ entry->offset += fnamelen + extralen + 30;
+ return 1;
+} /* zip_parse_local */
+
+
+static int zip_resolve(PHYSFS_Io *io, ZIPinfo *info, ZIPentry *entry)
+{
+ int retval = 1;
+ ZipResolveType resolve_type = entry->resolved;
+
+ /* Don't bother if we've failed to resolve this entry before. */
+ BAIL_IF_MACRO(resolve_type == ZIP_BROKEN_FILE, PHYSFS_ERR_CORRUPT, 0);
+ BAIL_IF_MACRO(resolve_type == ZIP_BROKEN_SYMLINK, PHYSFS_ERR_CORRUPT, 0);
+
+ /* uhoh...infinite symlink loop! */
+ BAIL_IF_MACRO(resolve_type == ZIP_RESOLVING, PHYSFS_ERR_SYMLINK_LOOP, 0);
+
+ /*
+ * We fix up the offset to point to the actual data on the
+ * first open, since we don't want to seek across the whole file on
+ * archive open (can be SLOW on large, CD-stored files), but we
+ * need to check the local file header...not just for corruption,
+ * but since it stores offset info the central directory does not.
+ */
+ if (resolve_type != ZIP_RESOLVED)
+ {
+ entry->resolved = ZIP_RESOLVING;
+
+ retval = zip_parse_local(io, entry);
+ if (retval)
+ {
+ /*
+ * If it's a symlink, find the original file. This will cause
+ * resolution of other entries (other symlinks and, eventually,
+ * the real file) if all goes well.
+ */
+ if (resolve_type == ZIP_UNRESOLVED_SYMLINK)
+ retval = zip_resolve_symlink(io, info, entry);
+ } /* if */
+
+ if (resolve_type == ZIP_UNRESOLVED_SYMLINK)
+ entry->resolved = ((retval) ? ZIP_RESOLVED : ZIP_BROKEN_SYMLINK);
+ else if (resolve_type == ZIP_UNRESOLVED_FILE)
+ entry->resolved = ((retval) ? ZIP_RESOLVED : ZIP_BROKEN_FILE);
+ } /* if */
+
+ return retval;
+} /* zip_resolve */
+
+
+static int zip_version_does_symlinks(PHYSFS_uint32 version)
+{
+ int retval = 0;
+ PHYSFS_uint8 hosttype = (PHYSFS_uint8) ((version >> 8) & 0xFF);
+
+ switch (hosttype)
+ {
+ /*
+ * These are the platforms that can NOT build an archive with
+ * symlinks, according to the Info-ZIP project.
+ */
+ case 0: /* FS_FAT_ */
+ case 1: /* AMIGA_ */
+ case 2: /* VMS_ */
+ case 4: /* VM_CSM_ */
+ case 6: /* FS_HPFS_ */
+ case 11: /* FS_NTFS_ */
+ case 14: /* FS_VFAT_ */
+ case 13: /* ACORN_ */
+ case 15: /* MVS_ */
+ case 18: /* THEOS_ */
+ break; /* do nothing. */
+
+ default: /* assume the rest to be unix-like. */
+ retval = 1;
+ break;
+ } /* switch */
+
+ return retval;
+} /* zip_version_does_symlinks */
+
+
+static int zip_entry_is_symlink(const ZIPentry *entry)
+{
+ return ((entry->resolved == ZIP_UNRESOLVED_SYMLINK) ||
+ (entry->resolved == ZIP_BROKEN_SYMLINK) ||
+ (entry->symlink));
+} /* zip_entry_is_symlink */
+
+
+static int zip_has_symlink_attr(ZIPentry *entry, PHYSFS_uint32 extern_attr)
+{
+ PHYSFS_uint16 xattr = ((extern_attr >> 16) & 0xFFFF);
+ return ( (zip_version_does_symlinks(entry->version)) &&
+ (entry->uncompressed_size > 0) &&
+ ((xattr & UNIX_FILETYPE_MASK) == UNIX_FILETYPE_SYMLINK) );
+} /* zip_has_symlink_attr */
+
+
+static PHYSFS_sint64 zip_dos_time_to_physfs_time(PHYSFS_uint32 dostime)
+{
+ PHYSFS_uint32 dosdate;
+ struct tm unixtime;
+ memset(&unixtime, '\0', sizeof (unixtime));
+
+ dosdate = (PHYSFS_uint32) ((dostime >> 16) & 0xFFFF);
+ dostime &= 0xFFFF;
+
+ /* dissect date */
+ unixtime.tm_year = ((dosdate >> 9) & 0x7F) + 80;
+ unixtime.tm_mon = ((dosdate >> 5) & 0x0F) - 1;
+ unixtime.tm_mday = ((dosdate ) & 0x1F);
+
+ /* dissect time */
+ unixtime.tm_hour = ((dostime >> 11) & 0x1F);
+ unixtime.tm_min = ((dostime >> 5) & 0x3F);
+ unixtime.tm_sec = ((dostime << 1) & 0x3E);
+
+ /* let mktime calculate daylight savings time. */
+ unixtime.tm_isdst = -1;
+
+ return ((PHYSFS_sint64) mktime(&unixtime));
+} /* zip_dos_time_to_physfs_time */
+
+
+static int zip_load_entry(PHYSFS_Io *io, const int zip64, ZIPentry *entry,
+ PHYSFS_uint64 ofs_fixup)
+{
+ PHYSFS_uint16 fnamelen, extralen, commentlen;
+ PHYSFS_uint32 external_attr;
+ PHYSFS_uint32 starting_disk;
+ PHYSFS_uint64 offset;
+ PHYSFS_uint16 ui16;
+ PHYSFS_uint32 ui32;
+ PHYSFS_sint64 si64;
+
+ /* sanity check with central directory signature... */
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+ BAIL_IF_MACRO(ui32 != ZIP_CENTRAL_DIR_SIG, PHYSFS_ERR_CORRUPT, 0);
+
+ /* Get the pertinent parts of the record... */
+ BAIL_IF_MACRO(!readui16(io, &entry->version), ERRPASS, 0);
+ BAIL_IF_MACRO(!readui16(io, &entry->version_needed), ERRPASS, 0);
+ BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0); /* general bits */
+ BAIL_IF_MACRO(!readui16(io, &entry->compression_method), ERRPASS, 0);
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+ entry->last_mod_time = zip_dos_time_to_physfs_time(ui32);
+ BAIL_IF_MACRO(!readui32(io, &entry->crc), ERRPASS, 0);
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+ entry->compressed_size = (PHYSFS_uint64) ui32;
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+ entry->uncompressed_size = (PHYSFS_uint64) ui32;
+ BAIL_IF_MACRO(!readui16(io, &fnamelen), ERRPASS, 0);
+ BAIL_IF_MACRO(!readui16(io, &extralen), ERRPASS, 0);
+ BAIL_IF_MACRO(!readui16(io, &commentlen), ERRPASS, 0);
+ BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
+ starting_disk = (PHYSFS_uint32) ui16;
+ BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0); /* internal file attribs */
+ BAIL_IF_MACRO(!readui32(io, &external_attr), ERRPASS, 0);
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+ offset = (PHYSFS_uint64) ui32;
+
+ entry->symlink = NULL; /* will be resolved later, if necessary. */
+ entry->resolved = (zip_has_symlink_attr(entry, external_attr)) ?
+ ZIP_UNRESOLVED_SYMLINK : ZIP_UNRESOLVED_FILE;
+
+ entry->name = (char *) allocator.Malloc(fnamelen + 1);
+ BAIL_IF_MACRO(entry->name == NULL, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+ if (!__PHYSFS_readAll(io, entry->name, fnamelen))
+ goto zip_load_entry_puked;
+
+ entry->name[fnamelen] = '\0'; /* null-terminate the filename. */
+ zip_convert_dos_path(entry, entry->name);
+
+ si64 = io->tell(io);
+ if (si64 == -1)
+ goto zip_load_entry_puked;
+
+ /*
+ * The actual sizes didn't fit in 32-bits; look for the Zip64
+ * extended information extra field...
+ */
+ if ( (zip64) &&
+ ((offset == 0xFFFFFFFF) ||
+ (starting_disk == 0xFFFFFFFF) ||
+ (entry->compressed_size == 0xFFFFFFFF) ||
+ (entry->uncompressed_size == 0xFFFFFFFF)) )
+ {
+ int found = 0;
+ PHYSFS_uint16 sig, len;
+ while (extralen > 4)
+ {
+ if (!readui16(io, &sig))
+ goto zip_load_entry_puked;
+ else if (!readui16(io, &len))
+ goto zip_load_entry_puked;
+
+ si64 += 4 + len;
+ extralen -= 4 + len;
+ if (sig != ZIP64_EXTENDED_INFO_EXTRA_FIELD_SIG)
+ {
+ if (!io->seek(io, si64))
+ goto zip_load_entry_puked;
+ continue;
+ } /* if */
+
+ found = 1;
+ break;
+ } /* while */
+
+ GOTO_IF_MACRO(!found, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
+
+ if (entry->uncompressed_size == 0xFFFFFFFF)
+ {
+ GOTO_IF_MACRO(len < 8, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
+ if (!readui64(io, &entry->uncompressed_size))
+ goto zip_load_entry_puked;
+ len -= 8;
+ } /* if */
+
+ if (entry->compressed_size == 0xFFFFFFFF)
+ {
+ GOTO_IF_MACRO(len < 8, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
+ if (!readui64(io, &entry->compressed_size))
+ goto zip_load_entry_puked;
+ len -= 8;
+ } /* if */
+
+ if (offset == 0xFFFFFFFF)
+ {
+ GOTO_IF_MACRO(len < 8, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
+ if (!readui64(io, &offset))
+ goto zip_load_entry_puked;
+ len -= 8;
+ } /* if */
+
+ if (starting_disk == 0xFFFFFFFF)
+ {
+ GOTO_IF_MACRO(len < 8, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
+ if (!readui32(io, &starting_disk))
+ goto zip_load_entry_puked;
+ len -= 4;
+ } /* if */
+
+ GOTO_IF_MACRO(len != 0, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
+ } /* if */
+
+ GOTO_IF_MACRO(starting_disk != 0, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
+
+ entry->offset = offset + ofs_fixup;
+
+ /* seek to the start of the next entry in the central directory... */
+ if (!io->seek(io, si64 + extralen + commentlen))
+ goto zip_load_entry_puked;
+
+ return 1; /* success. */
+
+zip_load_entry_puked:
+ allocator.Free(entry->name);
+ return 0; /* failure. */
+} /* zip_load_entry */
+
+
+static int zip_entry_cmp(void *_a, size_t one, size_t two)
+{
+ if (one != two)
+ {
+ const ZIPentry *a = (const ZIPentry *) _a;
+ return strcmp(a[one].name, a[two].name);
+ } /* if */
+
+ return 0;
+} /* zip_entry_cmp */
+
+
+static void zip_entry_swap(void *_a, size_t one, size_t two)
+{
+ if (one != two)
+ {
+ ZIPentry tmp;
+ ZIPentry *first = &(((ZIPentry *) _a)[one]);
+ ZIPentry *second = &(((ZIPentry *) _a)[two]);
+ memcpy(&tmp, first, sizeof (ZIPentry));
+ memcpy(first, second, sizeof (ZIPentry));
+ memcpy(second, &tmp, sizeof (ZIPentry));
+ } /* if */
+} /* zip_entry_swap */
+
+
+static int zip_load_entries(PHYSFS_Io *io, ZIPinfo *info,
+ const PHYSFS_uint64 data_ofs,
+ const PHYSFS_uint64 central_ofs)
+{
+ const PHYSFS_uint64 max = info->entryCount;
+ const int zip64 = info->zip64;
+ PHYSFS_uint64 i;
+
+ BAIL_IF_MACRO(!io->seek(io, central_ofs), ERRPASS, 0);
+
+ info->entries = (ZIPentry *) allocator.Malloc(sizeof (ZIPentry) * max);
+ BAIL_IF_MACRO(!info->entries, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+
+ for (i = 0; i < max; i++)
+ {
+ if (!zip_load_entry(io, zip64, &info->entries[i], data_ofs))
+ {
+ zip_free_entries(info->entries, i);
+ return 0;
+ } /* if */
+ } /* for */
+
+ __PHYSFS_sort(info->entries, (size_t) max, zip_entry_cmp, zip_entry_swap);
+ return 1;
+} /* zip_load_entries */
+
+
+static PHYSFS_sint64 zip64_find_end_of_central_dir(PHYSFS_Io *io,
+ PHYSFS_sint64 _pos,
+ PHYSFS_uint64 offset)
+{
+ /*
+ * Naturally, the offset is useless to us; it is the offset from the
+ * start of file, which is meaningless if we've appended this .zip to
+ * a self-extracting .exe. We need to find this on our own. It should
+ * be directly before the locator record, but the record in question,
+ * like the original end-of-central-directory record, ends with a
+ * variable-length field. Unlike the original, which has to store the
+ * size of that variable-length field in a 16-bit int and thus has to be
+ * within 64k, the new one gets 64-bits.
+ *
+ * Fortunately, the only currently-specified record for that variable
+ * length block is some weird proprietary thing that deals with EBCDIC
+ * and tape backups or something. So we don't seek far.
+ */
+
+ PHYSFS_uint32 ui32;
+ const PHYSFS_uint64 pos = (PHYSFS_uint64) _pos;
+
+ assert(_pos > 0);
+
+ /* Try offset specified in the Zip64 end of central directory locator. */
+ /* This works if the entire PHYSFS_Io is the zip file. */
+ BAIL_IF_MACRO(!io->seek(io, offset), ERRPASS, -1);
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, -1);
+ if (ui32 == ZIP64_END_OF_CENTRAL_DIR_SIG)
+ return offset;
+
+ /* Try 56 bytes before the Zip64 end of central directory locator. */
+ /* This works if the record isn't variable length and is version 1. */
+ if (pos > 56)
+ {
+ BAIL_IF_MACRO(!io->seek(io, pos-56), ERRPASS, -1);
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, -1);
+ if (ui32 == ZIP64_END_OF_CENTRAL_DIR_SIG)
+ return pos-56;
+ } /* if */
+
+ /* Try 84 bytes before the Zip64 end of central directory locator. */
+ /* This works if the record isn't variable length and is version 2. */
+ if (pos > 84)
+ {
+ BAIL_IF_MACRO(!io->seek(io, pos-84), ERRPASS, -1);
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, -1);
+ if (ui32 == ZIP64_END_OF_CENTRAL_DIR_SIG)
+ return pos-84;
+ } /* if */
+
+ /* Ok, brute force: we know it's between (offset) and (pos) somewhere. */
+ /* Just try moving back at most 256k. Oh well. */
+ if ((offset < pos) && (pos > 4))
+ {
+ /* we assume you can eat this stack if you handle Zip64 files. */
+ PHYSFS_uint8 buf[256 * 1024];
+ PHYSFS_uint64 len = pos - offset;
+ PHYSFS_sint32 i;
+
+ if (len > sizeof (buf))
+ len = sizeof (buf);
+
+ BAIL_IF_MACRO(!io->seek(io, pos - len), ERRPASS, -1);
+ BAIL_IF_MACRO(!__PHYSFS_readAll(io, buf, len), ERRPASS, -1);
+ for (i = (PHYSFS_sint32) (len - 4); i >= 0; i--)
+ {
+ if (buf[i] != 0x50)
+ continue;
+ if ( (buf[i+1] == 0x4b) &&
+ (buf[i+2] == 0x06) &&
+ (buf[i+3] == 0x06) )
+ return pos - (len - i);
+ } /* for */
+ } /* if */
+
+ BAIL_MACRO(PHYSFS_ERR_CORRUPT, -1); /* didn't find it. */
+} /* zip64_find_end_of_central_dir */
+
+
+static int zip64_parse_end_of_central_dir(PHYSFS_Io *io, ZIPinfo *info,
+ PHYSFS_uint64 *data_start,
+ PHYSFS_uint64 *dir_ofs,
+ PHYSFS_sint64 pos)
+{
+ PHYSFS_uint64 ui64;
+ PHYSFS_uint32 ui32;
+ PHYSFS_uint16 ui16;
+
+ /* We should be positioned right past the locator signature. */
+
+ if ((pos < 0) || (!io->seek(io, pos)))
+ return 0;
+
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+ if (ui32 != ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIG)
+ return -1; /* it's not a Zip64 archive. Not an error, though! */
+
+ info->zip64 = 1;
+
+ /* number of the disk with the start of the central directory. */
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+ BAIL_IF_MACRO(ui32 != 0, PHYSFS_ERR_CORRUPT, 0);
+
+ /* offset of Zip64 end of central directory record. */
+ BAIL_IF_MACRO(!readui64(io, &ui64), ERRPASS, 0);
+
+ /* total number of disks */
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+ BAIL_IF_MACRO(ui32 != 1, PHYSFS_ERR_CORRUPT, 0);
+
+ pos = zip64_find_end_of_central_dir(io, pos, ui64);
+ if (pos < 0)
+ return 0; /* oh well. */
+
+ /*
+ * For self-extracting archives, etc, there's crapola in the file
+ * before the zipfile records; we calculate how much data there is
+ * prepended by determining how far the zip64-end-of-central-directory
+ * offset is from where it is supposed to be...the difference in bytes
+ * is how much arbitrary data is at the start of the physical file.
+ */
+ assert(((PHYSFS_uint64) pos) >= ui64);
+ *data_start = ((PHYSFS_uint64) pos) - ui64;
+
+ BAIL_IF_MACRO(!io->seek(io, pos), ERRPASS, 0);
+
+ /* check signature again, just in case. */
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+ BAIL_IF_MACRO(ui32 != ZIP64_END_OF_CENTRAL_DIR_SIG, PHYSFS_ERR_CORRUPT, 0);
+
+ /* size of Zip64 end of central directory record. */
+ BAIL_IF_MACRO(!readui64(io, &ui64), ERRPASS, 0);
+
+ /* version made by. */
+ BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
+
+ /* version needed to extract. */
+ BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
+
+ /* number of this disk. */
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+ BAIL_IF_MACRO(ui32 != 0, PHYSFS_ERR_CORRUPT, 0);
+
+ /* number of disk with start of central directory record. */
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+ BAIL_IF_MACRO(ui32 != 0, PHYSFS_ERR_CORRUPT, 0);
+
+ /* total number of entries in the central dir on this disk */
+ BAIL_IF_MACRO(!readui64(io, &ui64), ERRPASS, 0);
+
+ /* total number of entries in the central dir */
+ BAIL_IF_MACRO(!readui64(io, &info->entryCount), ERRPASS, 0);
+ BAIL_IF_MACRO(ui64 != info->entryCount, PHYSFS_ERR_CORRUPT, 0);
+
+ /* size of the central directory */
+ BAIL_IF_MACRO(!readui64(io, &ui64), ERRPASS, 0);
+
+ /* offset of central directory */
+ BAIL_IF_MACRO(!readui64(io, dir_ofs), ERRPASS, 0);
+
+ /* Since we know the difference, fix up the central dir offset... */
+ *dir_ofs += *data_start;
+
+ /*
+ * There are more fields here, for encryption and feature-specific things,
+ * but we don't care about any of them at the moment.
+ */
+
+ return 1; /* made it. */
+} /* zip64_parse_end_of_central_dir */
+
+
+static int zip_parse_end_of_central_dir(PHYSFS_Io *io, ZIPinfo *info,
+ PHYSFS_uint64 *data_start,
+ PHYSFS_uint64 *dir_ofs)
+{
+ PHYSFS_uint16 entryCount16;
+ PHYSFS_uint32 offset32;
+ PHYSFS_uint32 ui32;
+ PHYSFS_uint16 ui16;
+ PHYSFS_sint64 len;
+ PHYSFS_sint64 pos;
+ int rc;
+
+ /* find the end-of-central-dir record, and seek to it. */
+ pos = zip_find_end_of_central_dir(io, &len);
+ BAIL_IF_MACRO(pos == -1, ERRPASS, 0);
+ BAIL_IF_MACRO(!io->seek(io, pos), ERRPASS, 0);
+
+ /* check signature again, just in case. */
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+ BAIL_IF_MACRO(ui32 != ZIP_END_OF_CENTRAL_DIR_SIG, PHYSFS_ERR_CORRUPT, 0);
+
+ /* Seek back to see if "Zip64 end of central directory locator" exists. */
+ /* this record is 20 bytes before end-of-central-dir */
+ rc = zip64_parse_end_of_central_dir(io, info, data_start, dir_ofs, pos-20);
+ BAIL_IF_MACRO(rc == 0, ERRPASS, 0);
+ if (rc == 1)
+ return 1; /* we're done here. */
+
+ assert(rc == -1); /* no error, just not a Zip64 archive. */
+
+ /* Not Zip64? Seek back to where we were and keep processing. */
+ BAIL_IF_MACRO(!io->seek(io, pos + 4), ERRPASS, 0);
+
+ /* number of this disk */
+ BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
+ BAIL_IF_MACRO(ui16 != 0, PHYSFS_ERR_CORRUPT, 0);
+
+ /* number of the disk with the start of the central directory */
+ BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
+ BAIL_IF_MACRO(ui16 != 0, PHYSFS_ERR_CORRUPT, 0);
+
+ /* total number of entries in the central dir on this disk */
+ BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
+
+ /* total number of entries in the central dir */
+ BAIL_IF_MACRO(!readui16(io, &entryCount16), ERRPASS, 0);
+ BAIL_IF_MACRO(ui16 != entryCount16, PHYSFS_ERR_CORRUPT, 0);
+
+ info->entryCount = entryCount16;
+
+ /* size of the central directory */
+ BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+
+ /* offset of central directory */
+ BAIL_IF_MACRO(!readui32(io, &offset32), ERRPASS, 0);
+ *dir_ofs = (PHYSFS_uint64) offset32;
+ BAIL_IF_MACRO(pos < (*dir_ofs + ui32), PHYSFS_ERR_CORRUPT, 0);
+
+ /*
+ * For self-extracting archives, etc, there's crapola in the file
+ * before the zipfile records; we calculate how much data there is
+ * prepended by determining how far the central directory offset is
+ * from where it is supposed to be (start of end-of-central-dir minus
+ * sizeof central dir)...the difference in bytes is how much arbitrary
+ * data is at the start of the physical file.
+ */
+ *data_start = (PHYSFS_uint64) (pos - (*dir_ofs + ui32));
+
+ /* Now that we know the difference, fix up the central dir offset... */
+ *dir_ofs += *data_start;
+
+ /* zipfile comment length */
+ BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
+
+ /*
+ * Make sure that the comment length matches to the end of file...
+ * If it doesn't, we're either in the wrong part of the file, or the
+ * file is corrupted, but we give up either way.
+ */
+ BAIL_IF_MACRO((pos + 22 + ui16) != len, PHYSFS_ERR_CORRUPT, 0);
+
+ return 1; /* made it. */
+} /* zip_parse_end_of_central_dir */
+
+
+static void *ZIP_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
+{
+ ZIPinfo *info = NULL;
+ PHYSFS_uint64 data_start;
+ PHYSFS_uint64 cent_dir_ofs;
+
+ assert(io != NULL); /* shouldn't ever happen. */
+
+ BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
+ BAIL_IF_MACRO(!isZip(io), ERRPASS, NULL);
+
+ info = (ZIPinfo *) allocator.Malloc(sizeof (ZIPinfo));
+ BAIL_IF_MACRO(!info, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ memset(info, '\0', sizeof (ZIPinfo));
+ info->io = io;
+
+ if (!zip_parse_end_of_central_dir(io, info, &data_start, ¢_dir_ofs))
+ goto ZIP_openarchive_failed;
+
+ if (!zip_load_entries(io, info, data_start, cent_dir_ofs))
+ goto ZIP_openarchive_failed;
+
+ return info;
+
+ZIP_openarchive_failed:
+ if (info != NULL)
+ allocator.Free(info);
+
+ return NULL;
+} /* ZIP_openArchive */
+
+
+static PHYSFS_sint64 zip_find_start_of_dir(ZIPinfo *info, const char *path,
+ int stop_on_first_find)
+{
+ PHYSFS_sint64 lo = 0;
+ PHYSFS_sint64 hi = (PHYSFS_sint64) (info->entryCount - 1);
+ PHYSFS_sint64 middle;
+ PHYSFS_uint32 dlen = (PHYSFS_uint32) strlen(path);
+ PHYSFS_sint64 retval = -1;
+ const char *name;
+ int rc;
+
+ if (*path == '\0') /* root dir? */
+ return 0;
+
+ if ((dlen > 0) && (path[dlen - 1] == '/')) /* ignore trailing slash. */
+ dlen--;
+
+ while (lo <= hi)
+ {
+ middle = lo + ((hi - lo) / 2);
+ name = info->entries[middle].name;
+ rc = strncmp(path, name, dlen);
+ if (rc == 0)
+ {
+ char ch = name[dlen];
+ if ('/' < ch) /* make sure this isn't just a substr match. */
+ rc = -1;
+ else if ('/' > ch)
+ rc = 1;
+ else
+ {
+ if (stop_on_first_find) /* Just checking dir's existance? */
+ return middle;
+
+ if (name[dlen + 1] == '\0') /* Skip initial dir entry. */
+ return (middle + 1);
+
+ /* there might be more entries earlier in the list. */
+ retval = middle;
+ hi = middle - 1;
+ } /* else */
+ } /* if */
+
+ if (rc > 0)
+ lo = middle + 1;
+ else
+ hi = middle - 1;
+ } /* while */
+
+ return retval;
+} /* zip_find_start_of_dir */
+
+
+/*
+ * Moved to seperate function so we can use alloca then immediately throw
+ * away the allocated stack space...
+ */
+static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata,
+ const char *odir, const char *str, PHYSFS_sint32 ln)
+{
+ char *newstr = __PHYSFS_smallAlloc(ln + 1);
+ if (newstr == NULL)
+ return;
+
+ memcpy(newstr, str, ln);
+ newstr[ln] = '\0';
+ cb(callbackdata, odir, newstr);
+ __PHYSFS_smallFree(newstr);
+} /* doEnumCallback */
+
+
+static void ZIP_enumerateFiles(PHYSFS_Dir *opaque, const char *dname,
+ int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+ const char *origdir, void *callbackdata)
+{
+ ZIPinfo *info = ((ZIPinfo *) opaque);
+ PHYSFS_sint32 dlen, dlen_inc;
+ PHYSFS_sint64 i, max;
+
+ i = zip_find_start_of_dir(info, dname, 0);
+ if (i == -1) /* no such directory. */
+ return;
+
+ dlen = (PHYSFS_sint32) strlen(dname);
+ if ((dlen > 0) && (dname[dlen - 1] == '/')) /* ignore trailing slash. */
+ dlen--;
+
+ dlen_inc = ((dlen > 0) ? 1 : 0) + dlen;
+ max = (PHYSFS_sint64) info->entryCount;
+ while (i < max)
+ {
+ char *e = info->entries[i].name;
+ if ((dlen) && ((strncmp(e, dname, dlen) != 0) || (e[dlen] != '/')))
+ break; /* past end of this dir; we're done. */
+
+ if ((omitSymLinks) && (zip_entry_is_symlink(&info->entries[i])))
+ i++;
+ else
+ {
+ char *add = e + dlen_inc;
+ char *ptr = strchr(add, '/');
+ PHYSFS_sint32 ln = (PHYSFS_sint32) ((ptr) ? ptr-add : strlen(add));
+ doEnumCallback(cb, callbackdata, origdir, add, ln);
+ ln += dlen_inc; /* point past entry to children... */
+
+ /* increment counter and skip children of subdirs... */
+ while ((++i < max) && (ptr != NULL))
+ {
+ char *e_new = info->entries[i].name;
+ if ((strncmp(e, e_new, ln) != 0) || (e_new[ln] != '/'))
+ break;
+ } /* while */
+ } /* else */
+ } /* while */
+} /* ZIP_enumerateFiles */
+
+
+static PHYSFS_Io *zip_get_io(PHYSFS_Io *io, ZIPinfo *inf, ZIPentry *entry)
+{
+ int success;
+ PHYSFS_Io *retval = io->duplicate(io);
+ BAIL_IF_MACRO(!retval, ERRPASS, NULL);
+
+ /* !!! FIXME: if you open a dir here, it should bail ERR_NOT_A_FILE */
+
+ /* (inf) can be NULL if we already resolved. */
+ success = (inf == NULL) || zip_resolve(retval, inf, entry);
+ if (success)
+ {
+ PHYSFS_sint64 offset;
+ offset = ((entry->symlink) ? entry->symlink->offset : entry->offset);
+ success = retval->seek(retval, offset);
+ } /* if */
+
+ if (!success)
+ {
+ retval->destroy(retval);
+ retval = NULL;
+ } /* if */
+
+ return retval;
+} /* zip_get_io */
+
+
+static PHYSFS_Io *ZIP_openRead(PHYSFS_Dir *opaque, const char *fnm,
+ int *fileExists)
+{
+ PHYSFS_Io *retval = NULL;
+ ZIPinfo *info = (ZIPinfo *) opaque;
+ ZIPentry *entry = zip_find_entry(info, fnm, NULL);
+ ZIPfileinfo *finfo = NULL;
+
+ *fileExists = (entry != NULL);
+ BAIL_IF_MACRO(!entry, ERRPASS, NULL);
+
+ retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
+ GOTO_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
+
+ finfo = (ZIPfileinfo *) allocator.Malloc(sizeof (ZIPfileinfo));
+ GOTO_IF_MACRO(!finfo, PHYSFS_ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
+ memset(finfo, '\0', sizeof (ZIPfileinfo));
+
+ finfo->io = zip_get_io(info->io, info, entry);
+ GOTO_IF_MACRO(!finfo->io, ERRPASS, ZIP_openRead_failed);
+ finfo->entry = ((entry->symlink != NULL) ? entry->symlink : entry);
+ initializeZStream(&finfo->stream);
+
+ if (finfo->entry->compression_method != COMPMETH_NONE)
+ {
+ finfo->buffer = (PHYSFS_uint8 *) allocator.Malloc(ZIP_READBUFSIZE);
+ if (!finfo->buffer)
+ GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
+ else if (zlib_err(inflateInit2(&finfo->stream, -MAX_WBITS)) != Z_OK)
+ goto ZIP_openRead_failed;
+ } /* if */
+
+ memcpy(retval, &ZIP_Io, sizeof (PHYSFS_Io));
+ retval->opaque = finfo;
+
+ return retval;
+
+ZIP_openRead_failed:
+ if (finfo != NULL)
+ {
+ if (finfo->io != NULL)
+ finfo->io->destroy(finfo->io);
+
+ if (finfo->buffer != NULL)
+ {
+ allocator.Free(finfo->buffer);
+ inflateEnd(&finfo->stream);
+ } /* if */
+
+ allocator.Free(finfo);
+ } /* if */
+
+ if (retval != NULL)
+ allocator.Free(retval);
+
+ return NULL;
+} /* ZIP_openRead */
+
+
+static PHYSFS_Io *ZIP_openWrite(PHYSFS_Dir *opaque, const char *filename)
+{
+ BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
+} /* ZIP_openWrite */
+
+
+static PHYSFS_Io *ZIP_openAppend(PHYSFS_Dir *opaque, const char *filename)
+{
+ BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
+} /* ZIP_openAppend */
+
+
+static void ZIP_closeArchive(PHYSFS_Dir *opaque)
+{
+ ZIPinfo *zi = (ZIPinfo *) (opaque);
+ zi->io->destroy(zi->io);
+ zip_free_entries(zi->entries, zi->entryCount);
+ allocator.Free(zi);
+} /* ZIP_closeArchive */
+
+
+static int ZIP_remove(PHYSFS_Dir *opaque, const char *name)
+{
+ BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
+} /* ZIP_remove */
+
+
+static int ZIP_mkdir(PHYSFS_Dir *opaque, const char *name)
+{
+ BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
+} /* ZIP_mkdir */
+
+
+static int ZIP_stat(PHYSFS_Dir *opaque, const char *filename, int *exists,
+ PHYSFS_Stat *stat)
+{
+ int isDir = 0;
+ const ZIPinfo *info = (const ZIPinfo *) opaque;
+ const ZIPentry *entry = zip_find_entry(info, filename, &isDir);
+
+ /* !!! FIXME: does this need to resolve entries here? */
+
+ *exists = isDir || (entry != 0);
+ if (!*exists)
+ return 0;
+
+ if (isDir)
+ {
+ stat->filesize = 0;
+ stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
+ } /* if */
+
+ else if (zip_entry_is_symlink(entry))
+ {
+ stat->filesize = 0;
+ stat->filetype = PHYSFS_FILETYPE_SYMLINK;
+ } /* else if */
+
+ else
+ {
+ stat->filesize = (PHYSFS_sint64) entry->uncompressed_size;
+ stat->filetype = PHYSFS_FILETYPE_REGULAR;
+ } /* else */
+
+ stat->modtime = ((entry) ? entry->last_mod_time : 0);
+ stat->createtime = stat->modtime;
+ stat->accesstime = 0;
+ stat->readonly = 1; /* .zip files are always read only */
+
+ return 1;
+} /* ZIP_stat */
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_ZIP =
+{
+ {
+ "ZIP",
+ "PkZip/WinZip/Info-Zip compatible",
+ "Ryan C. Gordon ",
+ "http://icculus.org/physfs/",
+ },
+ ZIP_openArchive, /* openArchive() method */
+ ZIP_enumerateFiles, /* enumerateFiles() method */
+ ZIP_openRead, /* openRead() method */
+ ZIP_openWrite, /* openWrite() method */
+ ZIP_openAppend, /* openAppend() method */
+ ZIP_remove, /* remove() method */
+ ZIP_mkdir, /* mkdir() method */
+ ZIP_closeArchive, /* closeArchive() method */
+ ZIP_stat /* stat() method */
+};
+
+#endif /* defined PHYSFS_SUPPORTS_ZIP */
+
+/* end of zip.c ... */
+
diff -r 404ddce27b23 -r c13ebed437cb misc/libphysfs/physfs.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/physfs.c Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,2744 @@
+/**
+ * PhysicsFS; a portable, flexible file i/o abstraction.
+ *
+ * Documentation is in physfs.h. It's verbose, honest. :)
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ * This file written by Ryan C. Gordon.
+ */
+
+/* !!! FIXME: ERR_PAST_EOF shouldn't trigger for reads. Just return zero. */
+/* !!! FIXME: use snprintf(), not sprintf(). */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+
+typedef struct __PHYSFS_DIRHANDLE__
+{
+ void *opaque; /* Instance data unique to the archiver. */
+ char *dirName; /* Path to archive in platform-dependent notation. */
+ char *mountPoint; /* Mountpoint in virtual file tree. */
+ const PHYSFS_Archiver *funcs; /* Ptr to archiver info for this handle. */
+ struct __PHYSFS_DIRHANDLE__ *next; /* linked list stuff. */
+} DirHandle;
+
+
+typedef struct __PHYSFS_FILEHANDLE__
+{
+ PHYSFS_Io *io; /* Instance data unique to the archiver for this file. */
+ PHYSFS_uint8 forReading; /* Non-zero if reading, zero if write/append */
+ const DirHandle *dirHandle; /* Archiver instance that created this */
+ PHYSFS_uint8 *buffer; /* Buffer, if set (NULL otherwise). Don't touch! */
+ PHYSFS_uint32 bufsize; /* Bufsize, if set (0 otherwise). Don't touch! */
+ PHYSFS_uint32 buffill; /* Buffer fill size. Don't touch! */
+ PHYSFS_uint32 bufpos; /* Buffer position. Don't touch! */
+ struct __PHYSFS_FILEHANDLE__ *next; /* linked list stuff. */
+} FileHandle;
+
+
+typedef struct __PHYSFS_ERRSTATETYPE__
+{
+ void *tid;
+ PHYSFS_ErrorCode code;
+ struct __PHYSFS_ERRSTATETYPE__ *next;
+} ErrState;
+
+
+/* The various i/o drivers...some of these may not be compiled in. */
+extern const PHYSFS_Archiver __PHYSFS_Archiver_ZIP;
+extern const PHYSFS_Archiver __PHYSFS_Archiver_LZMA;
+extern const PHYSFS_Archiver __PHYSFS_Archiver_GRP;
+extern const PHYSFS_Archiver __PHYSFS_Archiver_QPAK;
+extern const PHYSFS_Archiver __PHYSFS_Archiver_HOG;
+extern const PHYSFS_Archiver __PHYSFS_Archiver_MVL;
+extern const PHYSFS_Archiver __PHYSFS_Archiver_WAD;
+extern const PHYSFS_Archiver __PHYSFS_Archiver_DIR;
+extern const PHYSFS_Archiver __PHYSFS_Archiver_ISO9660;
+
+static const PHYSFS_Archiver *staticArchivers[] =
+{
+#if PHYSFS_SUPPORTS_ZIP
+ &__PHYSFS_Archiver_ZIP,
+#endif
+#if PHYSFS_SUPPORTS_7Z
+ &__PHYSFS_Archiver_LZMA,
+#endif
+#if PHYSFS_SUPPORTS_GRP
+ &__PHYSFS_Archiver_GRP,
+#endif
+#if PHYSFS_SUPPORTS_QPAK
+ &__PHYSFS_Archiver_QPAK,
+#endif
+#if PHYSFS_SUPPORTS_HOG
+ &__PHYSFS_Archiver_HOG,
+#endif
+#if PHYSFS_SUPPORTS_MVL
+ &__PHYSFS_Archiver_MVL,
+#endif
+#if PHYSFS_SUPPORTS_WAD
+ &__PHYSFS_Archiver_WAD,
+#endif
+#if PHYSFS_SUPPORTS_ISO9660
+ &__PHYSFS_Archiver_ISO9660,
+#endif
+ NULL
+};
+
+
+
+/* General PhysicsFS state ... */
+static int initialized = 0;
+static ErrState *errorStates = NULL;
+static DirHandle *searchPath = NULL;
+static DirHandle *writeDir = NULL;
+static FileHandle *openWriteList = NULL;
+static FileHandle *openReadList = NULL;
+static char *baseDir = NULL;
+static char *userDir = NULL;
+static char *prefDir = NULL;
+static int allowSymLinks = 0;
+static const PHYSFS_Archiver **archivers = NULL;
+static const PHYSFS_ArchiveInfo **archiveInfo = NULL;
+
+/* mutexes ... */
+static void *errorLock = NULL; /* protects error message list. */
+static void *stateLock = NULL; /* protects other PhysFS static state. */
+
+/* allocator ... */
+static int externalAllocator = 0;
+PHYSFS_Allocator allocator;
+
+
+/* PHYSFS_Io implementation for i/o to physical filesystem... */
+
+/* !!! FIXME: maybe refcount the paths in a string pool? */
+typedef struct __PHYSFS_NativeIoInfo
+{
+ void *handle;
+ const char *path;
+ int mode; /* 'r', 'w', or 'a' */
+} NativeIoInfo;
+
+static PHYSFS_sint64 nativeIo_read(PHYSFS_Io *io, void *buf, PHYSFS_uint64 len)
+{
+ NativeIoInfo *info = (NativeIoInfo *) io->opaque;
+ return __PHYSFS_platformRead(info->handle, buf, len);
+} /* nativeIo_read */
+
+static PHYSFS_sint64 nativeIo_write(PHYSFS_Io *io, const void *buffer,
+ PHYSFS_uint64 len)
+{
+ NativeIoInfo *info = (NativeIoInfo *) io->opaque;
+ return __PHYSFS_platformWrite(info->handle, buffer, len);
+} /* nativeIo_write */
+
+static int nativeIo_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
+{
+ NativeIoInfo *info = (NativeIoInfo *) io->opaque;
+ return __PHYSFS_platformSeek(info->handle, offset);
+} /* nativeIo_seek */
+
+static PHYSFS_sint64 nativeIo_tell(PHYSFS_Io *io)
+{
+ NativeIoInfo *info = (NativeIoInfo *) io->opaque;
+ return __PHYSFS_platformTell(info->handle);
+} /* nativeIo_tell */
+
+static PHYSFS_sint64 nativeIo_length(PHYSFS_Io *io)
+{
+ NativeIoInfo *info = (NativeIoInfo *) io->opaque;
+ return __PHYSFS_platformFileLength(info->handle);
+} /* nativeIo_length */
+
+static PHYSFS_Io *nativeIo_duplicate(PHYSFS_Io *io)
+{
+ NativeIoInfo *info = (NativeIoInfo *) io->opaque;
+ return __PHYSFS_createNativeIo(info->path, info->mode);
+} /* nativeIo_duplicate */
+
+static int nativeIo_flush(PHYSFS_Io *io)
+{
+ return __PHYSFS_platformFlush(io->opaque);
+} /* nativeIo_flush */
+
+static void nativeIo_destroy(PHYSFS_Io *io)
+{
+ NativeIoInfo *info = (NativeIoInfo *) io->opaque;
+ __PHYSFS_platformClose(info->handle);
+ allocator.Free((void *) info->path);
+ allocator.Free(info);
+ allocator.Free(io);
+} /* nativeIo_destroy */
+
+static const PHYSFS_Io __PHYSFS_nativeIoInterface =
+{
+ CURRENT_PHYSFS_IO_API_VERSION, NULL,
+ nativeIo_read,
+ nativeIo_write,
+ nativeIo_seek,
+ nativeIo_tell,
+ nativeIo_length,
+ nativeIo_duplicate,
+ nativeIo_flush,
+ nativeIo_destroy
+};
+
+PHYSFS_Io *__PHYSFS_createNativeIo(const char *path, const int mode)
+{
+ PHYSFS_Io *io = NULL;
+ NativeIoInfo *info = NULL;
+ void *handle = NULL;
+ char *pathdup = NULL;
+
+ assert((mode == 'r') || (mode == 'w') || (mode == 'a'));
+
+ io = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
+ GOTO_IF_MACRO(!io, PHYSFS_ERR_OUT_OF_MEMORY, createNativeIo_failed);
+ info = (NativeIoInfo *) allocator.Malloc(sizeof (NativeIoInfo));
+ GOTO_IF_MACRO(!info, PHYSFS_ERR_OUT_OF_MEMORY, createNativeIo_failed);
+ pathdup = (char *) allocator.Malloc(strlen(path) + 1);
+ GOTO_IF_MACRO(!pathdup, PHYSFS_ERR_OUT_OF_MEMORY, createNativeIo_failed);
+
+ if (mode == 'r')
+ handle = __PHYSFS_platformOpenRead(path);
+ else if (mode == 'w')
+ handle = __PHYSFS_platformOpenWrite(path);
+ else if (mode == 'a')
+ handle = __PHYSFS_platformOpenAppend(path);
+
+ GOTO_IF_MACRO(!handle, ERRPASS, createNativeIo_failed);
+
+ strcpy(pathdup, path);
+ info->handle = handle;
+ info->path = pathdup;
+ info->mode = mode;
+ memcpy(io, &__PHYSFS_nativeIoInterface, sizeof (*io));
+ io->opaque = info;
+ return io;
+
+createNativeIo_failed:
+ if (handle != NULL) __PHYSFS_platformClose(handle);
+ if (pathdup != NULL) allocator.Free(pathdup);
+ if (info != NULL) allocator.Free(info);
+ if (io != NULL) allocator.Free(io);
+ return NULL;
+} /* __PHYSFS_createNativeIo */
+
+
+/* PHYSFS_Io implementation for i/o to a memory buffer... */
+
+typedef struct __PHYSFS_MemoryIoInfo
+{
+ const PHYSFS_uint8 *buf;
+ PHYSFS_uint64 len;
+ PHYSFS_uint64 pos;
+ PHYSFS_Io *parent;
+ volatile PHYSFS_uint32 refcount;
+ void (*destruct)(void *);
+} MemoryIoInfo;
+
+static PHYSFS_sint64 memoryIo_read(PHYSFS_Io *io, void *buf, PHYSFS_uint64 len)
+{
+ MemoryIoInfo *info = (MemoryIoInfo *) io->opaque;
+ const PHYSFS_uint64 avail = info->len - info->pos;
+ assert(avail <= info->len);
+
+ if (avail == 0)
+ return 0; /* we're at EOF; nothing to do. */
+
+ if (len > avail)
+ len = avail;
+
+ memcpy(buf, info->buf + info->pos, (size_t) len);
+ info->pos += len;
+ return len;
+} /* memoryIo_read */
+
+static PHYSFS_sint64 memoryIo_write(PHYSFS_Io *io, const void *buffer,
+ PHYSFS_uint64 len)
+{
+ BAIL_MACRO(PHYSFS_ERR_OPEN_FOR_READING, -1);
+} /* memoryIo_write */
+
+static int memoryIo_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
+{
+ MemoryIoInfo *info = (MemoryIoInfo *) io->opaque;
+ BAIL_IF_MACRO(offset > info->len, PHYSFS_ERR_PAST_EOF, 0);
+ info->pos = offset;
+ return 1;
+} /* memoryIo_seek */
+
+static PHYSFS_sint64 memoryIo_tell(PHYSFS_Io *io)
+{
+ const MemoryIoInfo *info = (MemoryIoInfo *) io->opaque;
+ return (PHYSFS_sint64) info->pos;
+} /* memoryIo_tell */
+
+static PHYSFS_sint64 memoryIo_length(PHYSFS_Io *io)
+{
+ const MemoryIoInfo *info = (MemoryIoInfo *) io->opaque;
+ return (PHYSFS_sint64) info->len;
+} /* memoryIo_length */
+
+static PHYSFS_Io *memoryIo_duplicate(PHYSFS_Io *io)
+{
+ MemoryIoInfo *info = (MemoryIoInfo *) io->opaque;
+ MemoryIoInfo *newinfo = NULL;
+ PHYSFS_Io *parent = info->parent;
+ PHYSFS_Io *retval = NULL;
+
+ /* avoid deep copies. */
+ assert((!parent) || (!((MemoryIoInfo *) parent->opaque)->parent) );
+
+ /* share the buffer between duplicates. */
+ if (parent != NULL) /* dup the parent, increment its refcount. */
+ return parent->duplicate(parent);
+
+ /* we're the parent. */
+
+ retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
+ BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ newinfo = (MemoryIoInfo *) allocator.Malloc(sizeof (MemoryIoInfo));
+ if (!newinfo)
+ {
+ allocator.Free(retval);
+ BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ } /* if */
+
+ /* !!! FIXME: want lockless atomic increment. */
+ __PHYSFS_platformGrabMutex(stateLock);
+ info->refcount++;
+ __PHYSFS_platformReleaseMutex(stateLock);
+
+ memset(newinfo, '\0', sizeof (*info));
+ newinfo->buf = info->buf;
+ newinfo->len = info->len;
+ newinfo->pos = 0;
+ newinfo->parent = io;
+ newinfo->refcount = 0;
+ newinfo->destruct = NULL;
+
+ memcpy(retval, io, sizeof (*retval));
+ retval->opaque = newinfo;
+ return retval;
+} /* memoryIo_duplicate */
+
+static int memoryIo_flush(PHYSFS_Io *io) { return 1; /* it's read-only. */ }
+
+static void memoryIo_destroy(PHYSFS_Io *io)
+{
+ MemoryIoInfo *info = (MemoryIoInfo *) io->opaque;
+ PHYSFS_Io *parent = info->parent;
+ int should_die = 0;
+
+ if (parent != NULL)
+ {
+ assert(info->buf == ((MemoryIoInfo *) info->parent->opaque)->buf);
+ assert(info->len == ((MemoryIoInfo *) info->parent->opaque)->len);
+ assert(info->refcount == 0);
+ assert(info->destruct == NULL);
+ allocator.Free(info);
+ allocator.Free(io);
+ parent->destroy(parent); /* decrements refcount. */
+ return;
+ } /* if */
+
+ /* we _are_ the parent. */
+ assert(info->refcount > 0); /* even in a race, we hold a reference. */
+
+ /* !!! FIXME: want lockless atomic decrement. */
+ __PHYSFS_platformGrabMutex(stateLock);
+ info->refcount--;
+ should_die = (info->refcount == 0);
+ __PHYSFS_platformReleaseMutex(stateLock);
+
+ if (should_die)
+ {
+ void (*destruct)(void *) = info->destruct;
+ void *buf = (void *) info->buf;
+ io->opaque = NULL; /* kill this here in case of race. */
+ allocator.Free(info);
+ allocator.Free(io);
+ if (destruct != NULL)
+ destruct(buf);
+ } /* if */
+} /* memoryIo_destroy */
+
+
+static const PHYSFS_Io __PHYSFS_memoryIoInterface =
+{
+ CURRENT_PHYSFS_IO_API_VERSION, NULL,
+ memoryIo_read,
+ memoryIo_write,
+ memoryIo_seek,
+ memoryIo_tell,
+ memoryIo_length,
+ memoryIo_duplicate,
+ memoryIo_flush,
+ memoryIo_destroy
+};
+
+PHYSFS_Io *__PHYSFS_createMemoryIo(const void *buf, PHYSFS_uint64 len,
+ void (*destruct)(void *))
+{
+ PHYSFS_Io *io = NULL;
+ MemoryIoInfo *info = NULL;
+
+ io = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
+ GOTO_IF_MACRO(!io, PHYSFS_ERR_OUT_OF_MEMORY, createMemoryIo_failed);
+ info = (MemoryIoInfo *) allocator.Malloc(sizeof (MemoryIoInfo));
+ GOTO_IF_MACRO(!info, PHYSFS_ERR_OUT_OF_MEMORY, createMemoryIo_failed);
+
+ memset(info, '\0', sizeof (*info));
+ info->buf = (const PHYSFS_uint8 *) buf;
+ info->len = len;
+ info->pos = 0;
+ info->parent = NULL;
+ info->refcount = 1;
+ info->destruct = destruct;
+
+ memcpy(io, &__PHYSFS_memoryIoInterface, sizeof (*io));
+ io->opaque = info;
+ return io;
+
+createMemoryIo_failed:
+ if (info != NULL) allocator.Free(info);
+ if (io != NULL) allocator.Free(io);
+ return NULL;
+} /* __PHYSFS_createMemoryIo */
+
+
+/* PHYSFS_Io implementation for i/o to a PHYSFS_File... */
+
+static PHYSFS_sint64 handleIo_read(PHYSFS_Io *io, void *buf, PHYSFS_uint64 len)
+{
+ return PHYSFS_readBytes((PHYSFS_File *) io->opaque, buf, len);
+} /* handleIo_read */
+
+static PHYSFS_sint64 handleIo_write(PHYSFS_Io *io, const void *buffer,
+ PHYSFS_uint64 len)
+{
+ return PHYSFS_writeBytes((PHYSFS_File *) io->opaque, buffer, len);
+} /* handleIo_write */
+
+static int handleIo_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
+{
+ return PHYSFS_seek((PHYSFS_File *) io->opaque, offset);
+} /* handleIo_seek */
+
+static PHYSFS_sint64 handleIo_tell(PHYSFS_Io *io)
+{
+ return PHYSFS_tell((PHYSFS_File *) io->opaque);
+} /* handleIo_tell */
+
+static PHYSFS_sint64 handleIo_length(PHYSFS_Io *io)
+{
+ return PHYSFS_fileLength((PHYSFS_File *) io->opaque);
+} /* handleIo_length */
+
+static PHYSFS_Io *handleIo_duplicate(PHYSFS_Io *io)
+{
+ /*
+ * There's no duplicate at the PHYSFS_File level, so we break the
+ * abstraction. We're allowed to: we're physfs.c!
+ */
+ FileHandle *origfh = (FileHandle *) io->opaque;
+ FileHandle *newfh = (FileHandle *) allocator.Malloc(sizeof (FileHandle));
+ PHYSFS_Io *retval = NULL;
+
+ GOTO_IF_MACRO(!newfh, PHYSFS_ERR_OUT_OF_MEMORY, handleIo_dupe_failed);
+ memset(newfh, '\0', sizeof (*newfh));
+
+ retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
+ GOTO_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, handleIo_dupe_failed);
+
+#if 0 /* we don't buffer the duplicate, at least not at the moment. */
+ if (origfh->buffer != NULL)
+ {
+ newfh->buffer = (PHYSFS_uint8 *) allocator.Malloc(origfh->bufsize);
+ if (!newfh->buffer)
+ GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, handleIo_dupe_failed);
+ newfh->bufsize = origfh->bufsize;
+ } /* if */
+#endif
+
+ newfh->io = origfh->io->duplicate(origfh->io);
+ GOTO_IF_MACRO(!newfh->io, ERRPASS, handleIo_dupe_failed);
+
+ newfh->forReading = origfh->forReading;
+ newfh->dirHandle = origfh->dirHandle;
+
+ __PHYSFS_platformGrabMutex(stateLock);
+ if (newfh->forReading)
+ {
+ newfh->next = openReadList;
+ openReadList = newfh;
+ } /* if */
+ else
+ {
+ newfh->next = openWriteList;
+ openWriteList = newfh;
+ } /* else */
+ __PHYSFS_platformReleaseMutex(stateLock);
+
+ memcpy(retval, io, sizeof (PHYSFS_Io));
+ retval->opaque = newfh;
+ return retval;
+
+handleIo_dupe_failed:
+ if (newfh)
+ {
+ if (newfh->io != NULL) newfh->io->destroy(newfh->io);
+ if (newfh->buffer != NULL) allocator.Free(newfh->buffer);
+ allocator.Free(newfh);
+ } /* if */
+
+ return NULL;
+} /* handleIo_duplicate */
+
+static int handleIo_flush(PHYSFS_Io *io)
+{
+ return PHYSFS_flush((PHYSFS_File *) io->opaque);
+} /* handleIo_flush */
+
+static void handleIo_destroy(PHYSFS_Io *io)
+{
+ if (io->opaque != NULL)
+ PHYSFS_close((PHYSFS_File *) io->opaque);
+ allocator.Free(io);
+} /* handleIo_destroy */
+
+static const PHYSFS_Io __PHYSFS_handleIoInterface =
+{
+ CURRENT_PHYSFS_IO_API_VERSION, NULL,
+ handleIo_read,
+ handleIo_write,
+ handleIo_seek,
+ handleIo_tell,
+ handleIo_length,
+ handleIo_duplicate,
+ handleIo_flush,
+ handleIo_destroy
+};
+
+static PHYSFS_Io *__PHYSFS_createHandleIo(PHYSFS_File *f)
+{
+ PHYSFS_Io *io = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
+ BAIL_IF_MACRO(!io, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ memcpy(io, &__PHYSFS_handleIoInterface, sizeof (*io));
+ io->opaque = f;
+ return io;
+} /* __PHYSFS_createHandleIo */
+
+
+/* functions ... */
+
+typedef struct
+{
+ char **list;
+ PHYSFS_uint32 size;
+ PHYSFS_ErrorCode errcode;
+} EnumStringListCallbackData;
+
+static void enumStringListCallback(void *data, const char *str)
+{
+ void *ptr;
+ char *newstr;
+ EnumStringListCallbackData *pecd = (EnumStringListCallbackData *) data;
+
+ if (pecd->errcode)
+ return;
+
+ ptr = allocator.Realloc(pecd->list, (pecd->size + 2) * sizeof (char *));
+ newstr = (char *) allocator.Malloc(strlen(str) + 1);
+ if (ptr != NULL)
+ pecd->list = (char **) ptr;
+
+ if ((ptr == NULL) || (newstr == NULL))
+ {
+ pecd->errcode = PHYSFS_ERR_OUT_OF_MEMORY;
+ pecd->list[pecd->size] = NULL;
+ PHYSFS_freeList(pecd->list);
+ return;
+ } /* if */
+
+ strcpy(newstr, str);
+ pecd->list[pecd->size] = newstr;
+ pecd->size++;
+} /* enumStringListCallback */
+
+
+static char **doEnumStringList(void (*func)(PHYSFS_StringCallback, void *))
+{
+ EnumStringListCallbackData ecd;
+ memset(&ecd, '\0', sizeof (ecd));
+ ecd.list = (char **) allocator.Malloc(sizeof (char *));
+ BAIL_IF_MACRO(!ecd.list, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ func(enumStringListCallback, &ecd);
+
+ if (ecd.errcode)
+ {
+ __PHYSFS_setError(ecd.errcode);
+ return NULL;
+ } /* if */
+
+ ecd.list[ecd.size] = NULL;
+ return ecd.list;
+} /* doEnumStringList */
+
+
+static void __PHYSFS_bubble_sort(void *a, size_t lo, size_t hi,
+ int (*cmpfn)(void *, size_t, size_t),
+ void (*swapfn)(void *, size_t, size_t))
+{
+ size_t i;
+ int sorted;
+
+ do
+ {
+ sorted = 1;
+ for (i = lo; i < hi; i++)
+ {
+ if (cmpfn(a, i, i + 1) > 0)
+ {
+ swapfn(a, i, i + 1);
+ sorted = 0;
+ } /* if */
+ } /* for */
+ } while (!sorted);
+} /* __PHYSFS_bubble_sort */
+
+
+static void __PHYSFS_quick_sort(void *a, size_t lo, size_t hi,
+ int (*cmpfn)(void *, size_t, size_t),
+ void (*swapfn)(void *, size_t, size_t))
+{
+ size_t i;
+ size_t j;
+ size_t v;
+
+ if ((hi - lo) <= PHYSFS_QUICKSORT_THRESHOLD)
+ __PHYSFS_bubble_sort(a, lo, hi, cmpfn, swapfn);
+ else
+ {
+ i = (hi + lo) / 2;
+
+ if (cmpfn(a, lo, i) > 0) swapfn(a, lo, i);
+ if (cmpfn(a, lo, hi) > 0) swapfn(a, lo, hi);
+ if (cmpfn(a, i, hi) > 0) swapfn(a, i, hi);
+
+ j = hi - 1;
+ swapfn(a, i, j);
+ i = lo;
+ v = j;
+ while (1)
+ {
+ while(cmpfn(a, ++i, v) < 0) { /* do nothing */ }
+ while(cmpfn(a, --j, v) > 0) { /* do nothing */ }
+ if (j < i)
+ break;
+ swapfn(a, i, j);
+ } /* while */
+ if (i != (hi-1))
+ swapfn(a, i, hi-1);
+ __PHYSFS_quick_sort(a, lo, j, cmpfn, swapfn);
+ __PHYSFS_quick_sort(a, i+1, hi, cmpfn, swapfn);
+ } /* else */
+} /* __PHYSFS_quick_sort */
+
+
+void __PHYSFS_sort(void *entries, size_t max,
+ int (*cmpfn)(void *, size_t, size_t),
+ void (*swapfn)(void *, size_t, size_t))
+{
+ /*
+ * Quicksort w/ Bubblesort fallback algorithm inspired by code from here:
+ * http://www.cs.ubc.ca/spider/harrison/Java/sorting-demo.html
+ */
+ if (max > 0)
+ __PHYSFS_quick_sort(entries, 0, max - 1, cmpfn, swapfn);
+} /* __PHYSFS_sort */
+
+
+static ErrState *findErrorForCurrentThread(void)
+{
+ ErrState *i;
+ void *tid;
+
+ if (errorLock != NULL)
+ __PHYSFS_platformGrabMutex(errorLock);
+
+ if (errorStates != NULL)
+ {
+ tid = __PHYSFS_platformGetThreadID();
+
+ for (i = errorStates; i != NULL; i = i->next)
+ {
+ if (i->tid == tid)
+ {
+ if (errorLock != NULL)
+ __PHYSFS_platformReleaseMutex(errorLock);
+ return i;
+ } /* if */
+ } /* for */
+ } /* if */
+
+ if (errorLock != NULL)
+ __PHYSFS_platformReleaseMutex(errorLock);
+
+ return NULL; /* no error available. */
+} /* findErrorForCurrentThread */
+
+
+void __PHYSFS_setError(const PHYSFS_ErrorCode errcode)
+{
+ ErrState *err;
+
+ if (!errcode)
+ return;
+
+ err = findErrorForCurrentThread();
+ if (err == NULL)
+ {
+ err = (ErrState *) allocator.Malloc(sizeof (ErrState));
+ if (err == NULL)
+ return; /* uhh...? */
+
+ memset(err, '\0', sizeof (ErrState));
+ err->tid = __PHYSFS_platformGetThreadID();
+
+ if (errorLock != NULL)
+ __PHYSFS_platformGrabMutex(errorLock);
+
+ err->next = errorStates;
+ errorStates = err;
+
+ if (errorLock != NULL)
+ __PHYSFS_platformReleaseMutex(errorLock);
+ } /* if */
+
+ err->code = errcode;
+} /* __PHYSFS_setError */
+
+
+PHYSFS_ErrorCode PHYSFS_getLastErrorCode(void)
+{
+ ErrState *err = findErrorForCurrentThread();
+ const PHYSFS_ErrorCode retval = (err) ? err->code : PHYSFS_ERR_OK;
+ if (err)
+ err->code = PHYSFS_ERR_OK;
+ return retval;
+} /* PHYSFS_getLastErrorCode */
+
+
+PHYSFS_DECL const char *PHYSFS_getErrorByCode(PHYSFS_ErrorCode code)
+{
+ switch (code)
+ {
+ case PHYSFS_ERR_OK: return "no error";
+ case PHYSFS_ERR_OTHER_ERROR: return "unknown error";
+ case PHYSFS_ERR_OUT_OF_MEMORY: return "out of memory";
+ case PHYSFS_ERR_NOT_INITIALIZED: return "not initialized";
+ case PHYSFS_ERR_IS_INITIALIZED: return "already initialized";
+ case PHYSFS_ERR_ARGV0_IS_NULL: return "argv[0] is NULL";
+ case PHYSFS_ERR_UNSUPPORTED: return "unsupported";
+ case PHYSFS_ERR_PAST_EOF: return "past end of file";
+ case PHYSFS_ERR_FILES_STILL_OPEN: return "files still open";
+ case PHYSFS_ERR_INVALID_ARGUMENT: return "invalid argument";
+ case PHYSFS_ERR_NOT_MOUNTED: return "not mounted";
+ case PHYSFS_ERR_NO_SUCH_PATH: return "no such path";
+ case PHYSFS_ERR_SYMLINK_FORBIDDEN: return "symlinks are forbidden";
+ case PHYSFS_ERR_NO_WRITE_DIR: return "write directory is not set";
+ case PHYSFS_ERR_OPEN_FOR_READING: return "file open for reading";
+ case PHYSFS_ERR_OPEN_FOR_WRITING: return "file open for writing";
+ case PHYSFS_ERR_NOT_A_FILE: return "not a file";
+ case PHYSFS_ERR_READ_ONLY: return "read-only filesystem";
+ case PHYSFS_ERR_CORRUPT: return "corrupted";
+ case PHYSFS_ERR_SYMLINK_LOOP: return "infinite symbolic link loop";
+ case PHYSFS_ERR_IO: return "i/o error";
+ case PHYSFS_ERR_PERMISSION: return "permission denied";
+ case PHYSFS_ERR_NO_SPACE: return "no space available for writing";
+ case PHYSFS_ERR_BAD_FILENAME: return "filename is illegal or insecure";
+ case PHYSFS_ERR_BUSY: return "tried to modify a file the OS needs";
+ case PHYSFS_ERR_DIR_NOT_EMPTY: return "directory isn't empty";
+ case PHYSFS_ERR_OS_ERROR: return "OS reported an error";
+ } /* switch */
+
+ return NULL; /* don't know this error code. */
+} /* PHYSFS_getErrorByCode */
+
+
+void PHYSFS_setErrorCode(PHYSFS_ErrorCode code)
+{
+ __PHYSFS_setError(code);
+} /* PHYSFS_setErrorCode */
+
+
+const char *PHYSFS_getLastError(void)
+{
+ const PHYSFS_ErrorCode err = PHYSFS_getLastErrorCode();
+ return (err) ? PHYSFS_getErrorByCode(err) : NULL;
+} /* PHYSFS_getLastError */
+
+
+/* MAKE SURE that errorLock is held before calling this! */
+static void freeErrorStates(void)
+{
+ ErrState *i;
+ ErrState *next;
+
+ for (i = errorStates; i != NULL; i = next)
+ {
+ next = i->next;
+ allocator.Free(i);
+ } /* for */
+
+ errorStates = NULL;
+} /* freeErrorStates */
+
+
+void PHYSFS_getLinkedVersion(PHYSFS_Version *ver)
+{
+ if (ver != NULL)
+ {
+ ver->major = PHYSFS_VER_MAJOR;
+ ver->minor = PHYSFS_VER_MINOR;
+ ver->patch = PHYSFS_VER_PATCH;
+ } /* if */
+} /* PHYSFS_getLinkedVersion */
+
+
+static const char *find_filename_extension(const char *fname)
+{
+ const char *retval = NULL;
+ if (fname != NULL)
+ {
+ const char *p = strchr(fname, '.');
+ retval = p;
+
+ while (p != NULL)
+ {
+ p = strchr(p + 1, '.');
+ if (p != NULL)
+ retval = p;
+ } /* while */
+
+ if (retval != NULL)
+ retval++; /* skip '.' */
+ } /* if */
+
+ return retval;
+} /* find_filename_extension */
+
+
+static DirHandle *tryOpenDir(PHYSFS_Io *io, const PHYSFS_Archiver *funcs,
+ const char *d, int forWriting)
+{
+ DirHandle *retval = NULL;
+ void *opaque = NULL;
+
+ if (io != NULL)
+ BAIL_IF_MACRO(!io->seek(io, 0), ERRPASS, NULL);
+
+ opaque = funcs->openArchive(io, d, forWriting);
+ if (opaque != NULL)
+ {
+ retval = (DirHandle *) allocator.Malloc(sizeof (DirHandle));
+ if (retval == NULL)
+ funcs->closeArchive(opaque);
+ else
+ {
+ memset(retval, '\0', sizeof (DirHandle));
+ retval->mountPoint = NULL;
+ retval->funcs = funcs;
+ retval->opaque = opaque;
+ } /* else */
+ } /* if */
+
+ return retval;
+} /* tryOpenDir */
+
+
+static DirHandle *openDirectory(PHYSFS_Io *io, const char *d, int forWriting)
+{
+ DirHandle *retval = NULL;
+ const PHYSFS_Archiver **i;
+ const char *ext;
+
+ assert((io != NULL) || (d != NULL));
+
+ if (io == NULL)
+ {
+ /* DIR gets first shot (unlike the rest, it doesn't deal with files). */
+ retval = tryOpenDir(io, &__PHYSFS_Archiver_DIR, d, forWriting);
+ if (retval != NULL)
+ return retval;
+
+ io = __PHYSFS_createNativeIo(d, forWriting ? 'w' : 'r');
+ BAIL_IF_MACRO(!io, ERRPASS, 0);
+ } /* if */
+
+ ext = find_filename_extension(d);
+ if (ext != NULL)
+ {
+ /* Look for archivers with matching file extensions first... */
+ for (i = archivers; (*i != NULL) && (retval == NULL); i++)
+ {
+ if (__PHYSFS_stricmpASCII(ext, (*i)->info.extension) == 0)
+ retval = tryOpenDir(io, *i, d, forWriting);
+ } /* for */
+
+ /* failing an exact file extension match, try all the others... */
+ for (i = archivers; (*i != NULL) && (retval == NULL); i++)
+ {
+ if (__PHYSFS_stricmpASCII(ext, (*i)->info.extension) != 0)
+ retval = tryOpenDir(io, *i, d, forWriting);
+ } /* for */
+ } /* if */
+
+ else /* no extension? Try them all. */
+ {
+ for (i = archivers; (*i != NULL) && (retval == NULL); i++)
+ retval = tryOpenDir(io, *i, d, forWriting);
+ } /* else */
+
+ BAIL_IF_MACRO(!retval, PHYSFS_ERR_UNSUPPORTED, NULL);
+ return retval;
+} /* openDirectory */
+
+
+/*
+ * Make a platform-independent path string sane. Doesn't actually check the
+ * file hierarchy, it just cleans up the string.
+ * (dst) must be a buffer at least as big as (src), as this is where the
+ * cleaned up string is deposited.
+ * If there are illegal bits in the path (".." entries, etc) then we
+ * return zero and (dst) is undefined. Non-zero if the path was sanitized.
+ */
+static int sanitizePlatformIndependentPath(const char *src, char *dst)
+{
+ char *prev;
+ char ch;
+
+ while (*src == '/') /* skip initial '/' chars... */
+ src++;
+
+ prev = dst;
+ do
+ {
+ ch = *(src++);
+
+ if ((ch == ':') || (ch == '\\')) /* illegal chars in a physfs path. */
+ BAIL_MACRO(PHYSFS_ERR_BAD_FILENAME, 0);
+
+ if (ch == '/') /* path separator. */
+ {
+ *dst = '\0'; /* "." and ".." are illegal pathnames. */
+ if ((strcmp(prev, ".") == 0) || (strcmp(prev, "..") == 0))
+ BAIL_MACRO(PHYSFS_ERR_BAD_FILENAME, 0);
+
+ while (*src == '/') /* chop out doubles... */
+ src++;
+
+ if (*src == '\0') /* ends with a pathsep? */
+ break; /* we're done, don't add final pathsep to dst. */
+
+ prev = dst + 1;
+ } /* if */
+
+ *(dst++) = ch;
+ } while (ch != '\0');
+
+ return 1;
+} /* sanitizePlatformIndependentPath */
+
+
+/*
+ * Figure out if (fname) is part of (h)'s mountpoint. (fname) must be an
+ * output from sanitizePlatformIndependentPath(), so that it is in a known
+ * state.
+ *
+ * This only finds legitimate segments of a mountpoint. If the mountpoint is
+ * "/a/b/c" and (fname) is "/a/b/c", "/", or "/a/b/c/d", then the results are
+ * all zero. "/a/b" will succeed, though.
+ */
+static int partOfMountPoint(DirHandle *h, char *fname)
+{
+ /* !!! FIXME: This code feels gross. */
+ int rc;
+ size_t len, mntpntlen;
+
+ if (h->mountPoint == NULL)
+ return 0;
+ else if (*fname == '\0')
+ return 1;
+
+ len = strlen(fname);
+ mntpntlen = strlen(h->mountPoint);
+ if (len > mntpntlen) /* can't be a subset of mountpoint. */
+ return 0;
+
+ /* if true, must be not a match or a complete match, but not a subset. */
+ if ((len + 1) == mntpntlen)
+ return 0;
+
+ rc = strncmp(fname, h->mountPoint, len); /* !!! FIXME: case insensitive? */
+ if (rc != 0)
+ return 0; /* not a match. */
+
+ /* make sure /a/b matches /a/b/ and not /a/bc ... */
+ return h->mountPoint[len] == '/';
+} /* partOfMountPoint */
+
+
+static DirHandle *createDirHandle(PHYSFS_Io *io, const char *newDir,
+ const char *mountPoint, int forWriting)
+{
+ DirHandle *dirHandle = NULL;
+ char *tmpmntpnt = NULL;
+
+ if (mountPoint != NULL)
+ {
+ const size_t len = strlen(mountPoint) + 1;
+ tmpmntpnt = (char *) __PHYSFS_smallAlloc(len);
+ GOTO_IF_MACRO(!tmpmntpnt, PHYSFS_ERR_OUT_OF_MEMORY, badDirHandle);
+ if (!sanitizePlatformIndependentPath(mountPoint, tmpmntpnt))
+ goto badDirHandle;
+ mountPoint = tmpmntpnt; /* sanitized version. */
+ } /* if */
+
+ dirHandle = openDirectory(io, newDir, forWriting);
+ GOTO_IF_MACRO(!dirHandle, ERRPASS, badDirHandle);
+
+ if (newDir == NULL)
+ dirHandle->dirName = NULL;
+ else
+ {
+ dirHandle->dirName = (char *) allocator.Malloc(strlen(newDir) + 1);
+ if (!dirHandle->dirName)
+ GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, badDirHandle);
+ strcpy(dirHandle->dirName, newDir);
+ } /* else */
+
+ if ((mountPoint != NULL) && (*mountPoint != '\0'))
+ {
+ dirHandle->mountPoint = (char *)allocator.Malloc(strlen(mountPoint)+2);
+ if (!dirHandle->mountPoint)
+ GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, badDirHandle);
+ strcpy(dirHandle->mountPoint, mountPoint);
+ strcat(dirHandle->mountPoint, "/");
+ } /* if */
+
+ __PHYSFS_smallFree(tmpmntpnt);
+ return dirHandle;
+
+badDirHandle:
+ if (dirHandle != NULL)
+ {
+ dirHandle->funcs->closeArchive(dirHandle->opaque);
+ allocator.Free(dirHandle->dirName);
+ allocator.Free(dirHandle->mountPoint);
+ allocator.Free(dirHandle);
+ } /* if */
+
+ __PHYSFS_smallFree(tmpmntpnt);
+ return NULL;
+} /* createDirHandle */
+
+
+/* MAKE SURE you've got the stateLock held before calling this! */
+static int freeDirHandle(DirHandle *dh, FileHandle *openList)
+{
+ FileHandle *i;
+
+ if (dh == NULL)
+ return 1;
+
+ for (i = openList; i != NULL; i = i->next)
+ BAIL_IF_MACRO(i->dirHandle == dh, PHYSFS_ERR_FILES_STILL_OPEN, 0);
+
+ dh->funcs->closeArchive(dh->opaque);
+ allocator.Free(dh->dirName);
+ allocator.Free(dh->mountPoint);
+ allocator.Free(dh);
+ return 1;
+} /* freeDirHandle */
+
+
+static char *calculateBaseDir(const char *argv0)
+{
+ const char dirsep = __PHYSFS_platformDirSeparator;
+ char *retval = NULL;
+ char *ptr = NULL;
+
+ /* Give the platform layer first shot at this. */
+ retval = __PHYSFS_platformCalcBaseDir(argv0);
+ if (retval != NULL)
+ return retval;
+
+ /* We need argv0 to go on. */
+ BAIL_IF_MACRO(argv0 == NULL, PHYSFS_ERR_ARGV0_IS_NULL, NULL);
+
+ ptr = strrchr(argv0, dirsep);
+ if (ptr != NULL)
+ {
+ const size_t size = ((size_t) (ptr - argv0)) + 1;
+ retval = (char *) allocator.Malloc(size + 1);
+ BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ memcpy(retval, argv0, size);
+ retval[size] = '\0';
+ return retval;
+ } /* if */
+
+ /* argv0 wasn't helpful. */
+ BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, NULL);
+} /* calculateBaseDir */
+
+
+static int initializeMutexes(void)
+{
+ errorLock = __PHYSFS_platformCreateMutex();
+ if (errorLock == NULL)
+ goto initializeMutexes_failed;
+
+ stateLock = __PHYSFS_platformCreateMutex();
+ if (stateLock == NULL)
+ goto initializeMutexes_failed;
+
+ return 1; /* success. */
+
+initializeMutexes_failed:
+ if (errorLock != NULL)
+ __PHYSFS_platformDestroyMutex(errorLock);
+
+ if (stateLock != NULL)
+ __PHYSFS_platformDestroyMutex(stateLock);
+
+ errorLock = stateLock = NULL;
+ return 0; /* failed. */
+} /* initializeMutexes */
+
+
+static void setDefaultAllocator(void);
+
+static int initStaticArchivers(void)
+{
+ const size_t numStaticArchivers = __PHYSFS_ARRAYLEN(staticArchivers);
+ const size_t len = numStaticArchivers * sizeof (void *);
+ size_t i;
+
+ assert(numStaticArchivers > 0); /* seriously, none at all?! */
+ assert(staticArchivers[numStaticArchivers - 1] == NULL);
+
+ archiveInfo = (const PHYSFS_ArchiveInfo **) allocator.Malloc(len);
+ BAIL_IF_MACRO(!archiveInfo, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+ archivers = (const PHYSFS_Archiver **) allocator.Malloc(len);
+ BAIL_IF_MACRO(!archivers, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+
+ for (i = 0; i < numStaticArchivers - 1; i++)
+ archiveInfo[i] = &staticArchivers[i]->info;
+ archiveInfo[numStaticArchivers - 1] = NULL;
+
+ memcpy(archivers, staticArchivers, len);
+
+ return 1;
+} /* initStaticArchivers */
+
+
+static int doDeinit(void);
+
+int PHYSFS_init(const char *argv0)
+{
+ BAIL_IF_MACRO(initialized, PHYSFS_ERR_IS_INITIALIZED, 0);
+
+ if (!externalAllocator)
+ setDefaultAllocator();
+
+ if ((allocator.Init != NULL) && (!allocator.Init())) return 0;
+
+ if (!__PHYSFS_platformInit())
+ {
+ if (allocator.Deinit != NULL) allocator.Deinit();
+ return 0;
+ } /* if */
+
+ /* everything below here can be cleaned up safely by doDeinit(). */
+
+ if (!initializeMutexes()) goto initFailed;
+
+ baseDir = calculateBaseDir(argv0);
+ if (!baseDir) goto initFailed;
+
+ userDir = __PHYSFS_platformCalcUserDir();
+ if (!userDir) goto initFailed;
+
+ /* Platform layer is required to append a dirsep. */
+ assert(baseDir[strlen(baseDir) - 1] == __PHYSFS_platformDirSeparator);
+ assert(userDir[strlen(userDir) - 1] == __PHYSFS_platformDirSeparator);
+
+ if (!initStaticArchivers()) goto initFailed;
+
+ initialized = 1;
+
+ /* This makes sure that the error subsystem is initialized. */
+ __PHYSFS_setError(PHYSFS_getLastErrorCode());
+
+ return 1;
+
+initFailed:
+ doDeinit();
+ return 0;
+} /* PHYSFS_init */
+
+
+/* MAKE SURE you hold stateLock before calling this! */
+static int closeFileHandleList(FileHandle **list)
+{
+ FileHandle *i;
+ FileHandle *next = NULL;
+
+ for (i = *list; i != NULL; i = next)
+ {
+ PHYSFS_Io *io = i->io;
+ next = i->next;
+
+ if (!io->flush(io))
+ {
+ *list = i;
+ return 0;
+ } /* if */
+
+ io->destroy(io);
+ allocator.Free(i);
+ } /* for */
+
+ *list = NULL;
+ return 1;
+} /* closeFileHandleList */
+
+
+/* MAKE SURE you hold the stateLock before calling this! */
+static void freeSearchPath(void)
+{
+ DirHandle *i;
+ DirHandle *next = NULL;
+
+ closeFileHandleList(&openReadList);
+
+ if (searchPath != NULL)
+ {
+ for (i = searchPath; i != NULL; i = next)
+ {
+ next = i->next;
+ freeDirHandle(i, openReadList);
+ } /* for */
+ searchPath = NULL;
+ } /* if */
+} /* freeSearchPath */
+
+
+static int doDeinit(void)
+{
+ BAIL_IF_MACRO(!__PHYSFS_platformDeinit(), ERRPASS, 0);
+
+ closeFileHandleList(&openWriteList);
+ BAIL_IF_MACRO(!PHYSFS_setWriteDir(NULL), PHYSFS_ERR_FILES_STILL_OPEN, 0);
+
+ freeSearchPath();
+ freeErrorStates();
+
+ if (baseDir != NULL)
+ {
+ allocator.Free(baseDir);
+ baseDir = NULL;
+ } /* if */
+
+ if (userDir != NULL)
+ {
+ allocator.Free(userDir);
+ userDir = NULL;
+ } /* if */
+
+ if (prefDir != NULL)
+ {
+ allocator.Free(prefDir);
+ prefDir = NULL;
+ } /* if */
+
+ if (archiveInfo != NULL)
+ {
+ allocator.Free(archiveInfo);
+ archiveInfo = NULL;
+ } /* if */
+
+ if (archivers != NULL)
+ {
+ allocator.Free(archivers);
+ archivers = NULL;
+ } /* if */
+
+ allowSymLinks = 0;
+ initialized = 0;
+
+ if (errorLock) __PHYSFS_platformDestroyMutex(errorLock);
+ if (stateLock) __PHYSFS_platformDestroyMutex(stateLock);
+
+ if (allocator.Deinit != NULL)
+ allocator.Deinit();
+
+ errorLock = stateLock = NULL;
+ return 1;
+} /* doDeinit */
+
+
+int PHYSFS_deinit(void)
+{
+ BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, 0);
+ return doDeinit();
+} /* PHYSFS_deinit */
+
+
+int PHYSFS_isInit(void)
+{
+ return initialized;
+} /* PHYSFS_isInit */
+
+
+const PHYSFS_ArchiveInfo **PHYSFS_supportedArchiveTypes(void)
+{
+ BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, NULL);
+ return archiveInfo;
+} /* PHYSFS_supportedArchiveTypes */
+
+
+void PHYSFS_freeList(void *list)
+{
+ void **i;
+ if (list != NULL)
+ {
+ for (i = (void **) list; *i != NULL; i++)
+ allocator.Free(*i);
+
+ allocator.Free(list);
+ } /* if */
+} /* PHYSFS_freeList */
+
+
+const char *PHYSFS_getDirSeparator(void)
+{
+ static char retval[2] = { __PHYSFS_platformDirSeparator, '\0' };
+ return retval;
+} /* PHYSFS_getDirSeparator */
+
+
+char **PHYSFS_getCdRomDirs(void)
+{
+ return doEnumStringList(__PHYSFS_platformDetectAvailableCDs);
+} /* PHYSFS_getCdRomDirs */
+
+
+void PHYSFS_getCdRomDirsCallback(PHYSFS_StringCallback callback, void *data)
+{
+ __PHYSFS_platformDetectAvailableCDs(callback, data);
+} /* PHYSFS_getCdRomDirsCallback */
+
+
+const char *PHYSFS_getPrefDir(const char *org, const char *app)
+{
+ const char dirsep = __PHYSFS_platformDirSeparator;
+ PHYSFS_Stat statbuf;
+ char *ptr = NULL;
+ char *endstr = NULL;
+ int exists = 0;
+
+ BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, 0);
+ BAIL_IF_MACRO(!org, PHYSFS_ERR_INVALID_ARGUMENT, NULL);
+ BAIL_IF_MACRO(*org == '\0', PHYSFS_ERR_INVALID_ARGUMENT, NULL);
+ BAIL_IF_MACRO(!app, PHYSFS_ERR_INVALID_ARGUMENT, NULL);
+ BAIL_IF_MACRO(*app == '\0', PHYSFS_ERR_INVALID_ARGUMENT, NULL);
+
+ allocator.Free(prefDir);
+ prefDir = __PHYSFS_platformCalcPrefDir(org, app);
+ BAIL_IF_MACRO(!prefDir, ERRPASS, NULL);
+
+ assert(strlen(prefDir) > 0);
+ endstr = prefDir + (strlen(prefDir) - 1);
+ assert(*endstr == dirsep);
+ *endstr = '\0'; /* mask out the final dirsep for now. */
+
+ if (!__PHYSFS_platformStat(prefDir, &exists, &statbuf))
+ {
+ for (ptr = strchr(prefDir, dirsep); ptr; ptr = strchr(ptr+1, dirsep))
+ {
+ *ptr = '\0';
+ __PHYSFS_platformMkDir(prefDir);
+ *ptr = dirsep;
+ } /* for */
+
+ if (!__PHYSFS_platformMkDir(prefDir))
+ {
+ allocator.Free(prefDir);
+ prefDir = NULL;
+ } /* if */
+ } /* if */
+
+ *endstr = dirsep; /* readd the final dirsep. */
+
+ return prefDir;
+} /* PHYSFS_getPrefDir */
+
+
+const char *PHYSFS_getBaseDir(void)
+{
+ return baseDir; /* this is calculated in PHYSFS_init()... */
+} /* PHYSFS_getBaseDir */
+
+
+const char *__PHYSFS_getUserDir(void) /* not deprecated internal version. */
+{
+ return userDir; /* this is calculated in PHYSFS_init()... */
+} /* __PHYSFS_getUserDir */
+
+
+const char *PHYSFS_getUserDir(void)
+{
+ return __PHYSFS_getUserDir();
+} /* PHYSFS_getUserDir */
+
+
+const char *PHYSFS_getWriteDir(void)
+{
+ const char *retval = NULL;
+
+ __PHYSFS_platformGrabMutex(stateLock);
+ if (writeDir != NULL)
+ retval = writeDir->dirName;
+ __PHYSFS_platformReleaseMutex(stateLock);
+
+ return retval;
+} /* PHYSFS_getWriteDir */
+
+
+int PHYSFS_setWriteDir(const char *newDir)
+{
+ int retval = 1;
+
+ __PHYSFS_platformGrabMutex(stateLock);
+
+ if (writeDir != NULL)
+ {
+ BAIL_IF_MACRO_MUTEX(!freeDirHandle(writeDir, openWriteList), ERRPASS,
+ stateLock, 0);
+ writeDir = NULL;
+ } /* if */
+
+ if (newDir != NULL)
+ {
+ /* !!! FIXME: PHYSFS_Io shouldn't be NULL */
+ writeDir = createDirHandle(NULL, newDir, NULL, 1);
+ retval = (writeDir != NULL);
+ } /* if */
+
+ __PHYSFS_platformReleaseMutex(stateLock);
+
+ return retval;
+} /* PHYSFS_setWriteDir */
+
+
+static int doMount(PHYSFS_Io *io, const char *fname,
+ const char *mountPoint, int appendToPath)
+{
+ DirHandle *dh;
+ DirHandle *prev = NULL;
+ DirHandle *i;
+
+ if (mountPoint == NULL)
+ mountPoint = "/";
+
+ __PHYSFS_platformGrabMutex(stateLock);
+
+ if (fname != NULL)
+ {
+ for (i = searchPath; i != NULL; i = i->next)
+ {
+ /* already in search path? */
+ if ((i->dirName != NULL) && (strcmp(fname, i->dirName) == 0))
+ BAIL_MACRO_MUTEX(ERRPASS, stateLock, 1);
+ prev = i;
+ } /* for */
+ } /* if */
+
+ dh = createDirHandle(io, fname, mountPoint, 0);
+ BAIL_IF_MACRO_MUTEX(!dh, ERRPASS, stateLock, 0);
+
+ if (appendToPath)
+ {
+ if (prev == NULL)
+ searchPath = dh;
+ else
+ prev->next = dh;
+ } /* if */
+ else
+ {
+ dh->next = searchPath;
+ searchPath = dh;
+ } /* else */
+
+ __PHYSFS_platformReleaseMutex(stateLock);
+ return 1;
+} /* doMount */
+
+
+int PHYSFS_mountIo(PHYSFS_Io *io, const char *fname,
+ const char *mountPoint, int appendToPath)
+{
+ BAIL_IF_MACRO(!io, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+ BAIL_IF_MACRO(io->version != 0, PHYSFS_ERR_UNSUPPORTED, 0);
+ return doMount(io, fname, mountPoint, appendToPath);
+} /* PHYSFS_mountIo */
+
+
+int PHYSFS_mountMemory(const void *buf, PHYSFS_uint64 len, void (*del)(void *),
+ const char *fname, const char *mountPoint,
+ int appendToPath)
+{
+ int retval = 0;
+ PHYSFS_Io *io = NULL;
+
+ BAIL_IF_MACRO(!buf, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+
+ io = __PHYSFS_createMemoryIo(buf, len, del);
+ BAIL_IF_MACRO(!io, ERRPASS, 0);
+ retval = doMount(io, fname, mountPoint, appendToPath);
+ if (!retval)
+ {
+ /* docs say not to call (del) in case of failure, so cheat. */
+ MemoryIoInfo *info = (MemoryIoInfo *) io->opaque;
+ info->destruct = NULL;
+ io->destroy(io);
+ } /* if */
+
+ return retval;
+} /* PHYSFS_mountMemory */
+
+
+int PHYSFS_mountHandle(PHYSFS_File *file, const char *fname,
+ const char *mountPoint, int appendToPath)
+{
+ int retval = 0;
+ PHYSFS_Io *io = NULL;
+
+ BAIL_IF_MACRO(file == NULL, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+
+ io = __PHYSFS_createHandleIo(file);
+ BAIL_IF_MACRO(!io, ERRPASS, 0);
+ retval = doMount(io, fname, mountPoint, appendToPath);
+ if (!retval)
+ {
+ /* docs say not to destruct in case of failure, so cheat. */
+ io->opaque = NULL;
+ io->destroy(io);
+ } /* if */
+
+ return retval;
+} /* PHYSFS_mountHandle */
+
+
+int PHYSFS_mount(const char *newDir, const char *mountPoint, int appendToPath)
+{
+ BAIL_IF_MACRO(!newDir, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+ return doMount(NULL, newDir, mountPoint, appendToPath);
+} /* PHYSFS_mount */
+
+
+int PHYSFS_addToSearchPath(const char *newDir, int appendToPath)
+{
+ return doMount(NULL, newDir, NULL, appendToPath);
+} /* PHYSFS_addToSearchPath */
+
+
+int PHYSFS_removeFromSearchPath(const char *oldDir)
+{
+ return PHYSFS_unmount(oldDir);
+} /* PHYSFS_removeFromSearchPath */
+
+
+int PHYSFS_unmount(const char *oldDir)
+{
+ DirHandle *i;
+ DirHandle *prev = NULL;
+ DirHandle *next = NULL;
+
+ BAIL_IF_MACRO(oldDir == NULL, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+
+ __PHYSFS_platformGrabMutex(stateLock);
+ for (i = searchPath; i != NULL; i = i->next)
+ {
+ if (strcmp(i->dirName, oldDir) == 0)
+ {
+ next = i->next;
+ BAIL_IF_MACRO_MUTEX(!freeDirHandle(i, openReadList), ERRPASS,
+ stateLock, 0);
+
+ if (prev == NULL)
+ searchPath = next;
+ else
+ prev->next = next;
+
+ BAIL_MACRO_MUTEX(ERRPASS, stateLock, 1);
+ } /* if */
+ prev = i;
+ } /* for */
+
+ BAIL_MACRO_MUTEX(PHYSFS_ERR_NOT_MOUNTED, stateLock, 0);
+} /* PHYSFS_unmount */
+
+
+char **PHYSFS_getSearchPath(void)
+{
+ return doEnumStringList(PHYSFS_getSearchPathCallback);
+} /* PHYSFS_getSearchPath */
+
+
+const char *PHYSFS_getMountPoint(const char *dir)
+{
+ DirHandle *i;
+ __PHYSFS_platformGrabMutex(stateLock);
+ for (i = searchPath; i != NULL; i = i->next)
+ {
+ if (strcmp(i->dirName, dir) == 0)
+ {
+ const char *retval = ((i->mountPoint) ? i->mountPoint : "/");
+ __PHYSFS_platformReleaseMutex(stateLock);
+ return retval;
+ } /* if */
+ } /* for */
+ __PHYSFS_platformReleaseMutex(stateLock);
+
+ BAIL_MACRO(PHYSFS_ERR_NOT_MOUNTED, NULL);
+} /* PHYSFS_getMountPoint */
+
+
+void PHYSFS_getSearchPathCallback(PHYSFS_StringCallback callback, void *data)
+{
+ DirHandle *i;
+
+ __PHYSFS_platformGrabMutex(stateLock);
+
+ for (i = searchPath; i != NULL; i = i->next)
+ callback(data, i->dirName);
+
+ __PHYSFS_platformReleaseMutex(stateLock);
+} /* PHYSFS_getSearchPathCallback */
+
+
+/* Split out to avoid stack allocation in a loop. */
+static void setSaneCfgAddPath(const char *i, const size_t l, const char *dirsep,
+ int archivesFirst)
+{
+ const char *d = PHYSFS_getRealDir(i);
+ const size_t allocsize = strlen(d) + strlen(dirsep) + l + 1;
+ char *str = (char *) __PHYSFS_smallAlloc(allocsize);
+ if (str != NULL)
+ {
+ sprintf(str, "%s%s%s", d, dirsep, i);
+ PHYSFS_mount(str, NULL, archivesFirst == 0);
+ __PHYSFS_smallFree(str);
+ } /* if */
+} /* setSaneCfgAddPath */
+
+
+int PHYSFS_setSaneConfig(const char *organization, const char *appName,
+ const char *archiveExt, int includeCdRoms,
+ int archivesFirst)
+{
+ const char *dirsep = PHYSFS_getDirSeparator();
+ const char *basedir;
+ const char *prefdir;
+
+ BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, 0);
+
+ prefdir = PHYSFS_getPrefDir(organization, appName);
+ BAIL_IF_MACRO(!prefdir, ERRPASS, 0);
+
+ basedir = PHYSFS_getBaseDir();
+ BAIL_IF_MACRO(!basedir, ERRPASS, 0);
+
+ BAIL_IF_MACRO(!PHYSFS_setWriteDir(prefdir), PHYSFS_ERR_NO_WRITE_DIR, 0);
+
+ /* Put write dir first in search path... */
+ PHYSFS_mount(prefdir, NULL, 0);
+
+ /* Put base path on search path... */
+ PHYSFS_mount(basedir, NULL, 1);
+
+ /* handle CD-ROMs... */
+ if (includeCdRoms)
+ {
+ char **cds = PHYSFS_getCdRomDirs();
+ char **i;
+ for (i = cds; *i != NULL; i++)
+ PHYSFS_mount(*i, NULL, 1);
+ PHYSFS_freeList(cds);
+ } /* if */
+
+ /* Root out archives, and add them to search path... */
+ if (archiveExt != NULL)
+ {
+ char **rc = PHYSFS_enumerateFiles("/");
+ char **i;
+ size_t extlen = strlen(archiveExt);
+ char *ext;
+
+ for (i = rc; *i != NULL; i++)
+ {
+ size_t l = strlen(*i);
+ if ((l > extlen) && ((*i)[l - extlen - 1] == '.'))
+ {
+ ext = (*i) + (l - extlen);
+ if (__PHYSFS_stricmpASCII(ext, archiveExt) == 0)
+ setSaneCfgAddPath(*i, l, dirsep, archivesFirst);
+ } /* if */
+ } /* for */
+
+ PHYSFS_freeList(rc);
+ } /* if */
+
+ return 1;
+} /* PHYSFS_setSaneConfig */
+
+
+void PHYSFS_permitSymbolicLinks(int allow)
+{
+ allowSymLinks = allow;
+} /* PHYSFS_permitSymbolicLinks */
+
+
+int PHYSFS_symbolicLinksPermitted(void)
+{
+ return allowSymLinks;
+} /* PHYSFS_symbolicLinksPermitted */
+
+
+/*
+ * Verify that (fname) (in platform-independent notation), in relation
+ * to (h) is secure. That means that each element of fname is checked
+ * for symlinks (if they aren't permitted). This also allows for quick
+ * rejection of files that exist outside an archive's mountpoint.
+ *
+ * With some exceptions (like PHYSFS_mkdir(), which builds multiple subdirs
+ * at a time), you should always pass zero for "allowMissing" for efficiency.
+ *
+ * (fname) must point to an output from sanitizePlatformIndependentPath(),
+ * since it will make sure that path names are in the right format for
+ * passing certain checks. It will also do checks for "insecure" pathnames
+ * like ".." which should be done once instead of once per archive. This also
+ * gives us license to treat (fname) as scratch space in this function.
+ *
+ * Returns non-zero if string is safe, zero if there's a security issue.
+ * PHYSFS_getLastError() will specify what was wrong. (*fname) will be
+ * updated to point past any mount point elements so it is prepared to
+ * be used with the archiver directly.
+ */
+static int verifyPath(DirHandle *h, char **_fname, int allowMissing)
+{
+ char *fname = *_fname;
+ int retval = 1;
+ char *start;
+ char *end;
+
+ if (*fname == '\0') /* quick rejection. */
+ return 1;
+
+ /* !!! FIXME: This codeblock sucks. */
+ if (h->mountPoint != NULL) /* NULL mountpoint means "/". */
+ {
+ size_t mntpntlen = strlen(h->mountPoint);
+ size_t len = strlen(fname);
+ assert(mntpntlen > 1); /* root mount points should be NULL. */
+ /* not under the mountpoint, so skip this archive. */
+ BAIL_IF_MACRO(len < mntpntlen-1, PHYSFS_ERR_NO_SUCH_PATH, 0);
+ /* !!! FIXME: Case insensitive? */
+ retval = strncmp(h->mountPoint, fname, mntpntlen-1);
+ BAIL_IF_MACRO(retval != 0, PHYSFS_ERR_NO_SUCH_PATH, 0);
+ if (len > mntpntlen-1) /* corner case... */
+ BAIL_IF_MACRO(fname[mntpntlen-1]!='/', PHYSFS_ERR_NO_SUCH_PATH, 0);
+ fname += mntpntlen-1; /* move to start of actual archive path. */
+ if (*fname == '/')
+ fname++;
+ *_fname = fname; /* skip mountpoint for later use. */
+ retval = 1; /* may be reset, below. */
+ } /* if */
+
+ start = fname;
+ if (!allowSymLinks)
+ {
+ while (1)
+ {
+ PHYSFS_Stat statbuf;
+ int rc = 0;
+ end = strchr(start, '/');
+
+ if (end != NULL) *end = '\0';
+ rc = h->funcs->stat(h->opaque, fname, &retval, &statbuf);
+ if (rc)
+ rc = (statbuf.filetype == PHYSFS_FILETYPE_SYMLINK);
+ if (end != NULL) *end = '/';
+
+ /* insecure path (has a disallowed symlink in it)? */
+ BAIL_IF_MACRO(rc, PHYSFS_ERR_SYMLINK_FORBIDDEN, 0);
+
+ /* break out early if path element is missing. */
+ if (!retval)
+ {
+ /*
+ * We need to clear it if it's the last element of the path,
+ * since this might be a non-existant file we're opening
+ * for writing...
+ */
+ if ((end == NULL) || (allowMissing))
+ retval = 1;
+ break;
+ } /* if */
+
+ if (end == NULL)
+ break;
+
+ start = end + 1;
+ } /* while */
+ } /* if */
+
+ return retval;
+} /* verifyPath */
+
+
+static int doMkdir(const char *_dname, char *dname)
+{
+ DirHandle *h;
+ char *start;
+ char *end;
+ int retval = 0;
+ int exists = 1; /* force existance check on first path element. */
+
+ BAIL_IF_MACRO(!sanitizePlatformIndependentPath(_dname, dname), ERRPASS, 0);
+
+ __PHYSFS_platformGrabMutex(stateLock);
+ BAIL_IF_MACRO_MUTEX(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, stateLock, 0);
+ h = writeDir;
+ BAIL_IF_MACRO_MUTEX(!verifyPath(h, &dname, 1), ERRPASS, stateLock, 0);
+
+ start = dname;
+ while (1)
+ {
+ end = strchr(start, '/');
+ if (end != NULL)
+ *end = '\0';
+
+ /* only check for existance if all parent dirs existed, too... */
+ if (exists)
+ {
+ PHYSFS_Stat statbuf;
+ const int rc = h->funcs->stat(h->opaque, dname, &exists, &statbuf);
+ retval = ((rc) && (statbuf.filetype == PHYSFS_FILETYPE_DIRECTORY));
+ } /* if */
+
+ if (!exists)
+ retval = h->funcs->mkdir(h->opaque, dname);
+
+ if (!retval)
+ break;
+
+ if (end == NULL)
+ break;
+
+ *end = '/';
+ start = end + 1;
+ } /* while */
+
+ __PHYSFS_platformReleaseMutex(stateLock);
+ return retval;
+} /* doMkdir */
+
+
+int PHYSFS_mkdir(const char *_dname)
+{
+ int retval = 0;
+ char *dname;
+ size_t len;
+
+ BAIL_IF_MACRO(!_dname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+ len = strlen(_dname) + 1;
+ dname = (char *) __PHYSFS_smallAlloc(len);
+ BAIL_IF_MACRO(!dname, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+ retval = doMkdir(_dname, dname);
+ __PHYSFS_smallFree(dname);
+ return retval;
+} /* PHYSFS_mkdir */
+
+
+static int doDelete(const char *_fname, char *fname)
+{
+ int retval;
+ DirHandle *h;
+ BAIL_IF_MACRO(!sanitizePlatformIndependentPath(_fname, fname), ERRPASS, 0);
+
+ __PHYSFS_platformGrabMutex(stateLock);
+
+ BAIL_IF_MACRO_MUTEX(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, stateLock, 0);
+ h = writeDir;
+ BAIL_IF_MACRO_MUTEX(!verifyPath(h, &fname, 0), ERRPASS, stateLock, 0);
+ retval = h->funcs->remove(h->opaque, fname);
+
+ __PHYSFS_platformReleaseMutex(stateLock);
+ return retval;
+} /* doDelete */
+
+
+int PHYSFS_delete(const char *_fname)
+{
+ int retval;
+ char *fname;
+ size_t len;
+
+ BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+ len = strlen(_fname) + 1;
+ fname = (char *) __PHYSFS_smallAlloc(len);
+ BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+ retval = doDelete(_fname, fname);
+ __PHYSFS_smallFree(fname);
+ return retval;
+} /* PHYSFS_delete */
+
+
+const char *PHYSFS_getRealDir(const char *_fname)
+{
+ const char *retval = NULL;
+ char *fname = NULL;
+ size_t len;
+
+ BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, NULL);
+ len = strlen(_fname) + 1;
+ fname = __PHYSFS_smallAlloc(len);
+ BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ if (sanitizePlatformIndependentPath(_fname, fname))
+ {
+ DirHandle *i;
+ __PHYSFS_platformGrabMutex(stateLock);
+ for (i = searchPath; i != NULL; i = i->next)
+ {
+ char *arcfname = fname;
+ if (partOfMountPoint(i, arcfname))
+ {
+ retval = i->dirName;
+ break;
+ } /* if */
+ else if (verifyPath(i, &arcfname, 0))
+ {
+ PHYSFS_Stat statbuf;
+ int exists = 0;
+ if (i->funcs->stat(i->opaque, arcfname, &exists, &statbuf))
+ {
+ if (exists)
+ retval = i->dirName;
+ break;
+ } /* if */
+ } /* if */
+ } /* for */
+ __PHYSFS_platformReleaseMutex(stateLock);
+ } /* if */
+
+ __PHYSFS_smallFree(fname);
+ return retval;
+} /* PHYSFS_getRealDir */
+
+
+static int locateInStringList(const char *str,
+ char **list,
+ PHYSFS_uint32 *pos)
+{
+ PHYSFS_uint32 len = *pos;
+ PHYSFS_uint32 half_len;
+ PHYSFS_uint32 lo = 0;
+ PHYSFS_uint32 middle;
+ int cmp;
+
+ while (len > 0)
+ {
+ half_len = len >> 1;
+ middle = lo + half_len;
+ cmp = strcmp(list[middle], str);
+
+ if (cmp == 0) /* it's in the list already. */
+ return 1;
+ else if (cmp > 0)
+ len = half_len;
+ else
+ {
+ lo = middle + 1;
+ len -= half_len + 1;
+ } /* else */
+ } /* while */
+
+ *pos = lo;
+ return 0;
+} /* locateInStringList */
+
+
+static void enumFilesCallback(void *data, const char *origdir, const char *str)
+{
+ PHYSFS_uint32 pos;
+ void *ptr;
+ char *newstr;
+ EnumStringListCallbackData *pecd = (EnumStringListCallbackData *) data;
+
+ /*
+ * See if file is in the list already, and if not, insert it in there
+ * alphabetically...
+ */
+ pos = pecd->size;
+ if (locateInStringList(str, pecd->list, &pos))
+ return; /* already in the list. */
+
+ ptr = allocator.Realloc(pecd->list, (pecd->size + 2) * sizeof (char *));
+ newstr = (char *) allocator.Malloc(strlen(str) + 1);
+ if (ptr != NULL)
+ pecd->list = (char **) ptr;
+
+ if ((ptr == NULL) || (newstr == NULL))
+ return; /* better luck next time. */
+
+ strcpy(newstr, str);
+
+ if (pos != pecd->size)
+ {
+ memmove(&pecd->list[pos+1], &pecd->list[pos],
+ sizeof (char *) * ((pecd->size) - pos));
+ } /* if */
+
+ pecd->list[pos] = newstr;
+ pecd->size++;
+} /* enumFilesCallback */
+
+
+char **PHYSFS_enumerateFiles(const char *path)
+{
+ EnumStringListCallbackData ecd;
+ memset(&ecd, '\0', sizeof (ecd));
+ ecd.list = (char **) allocator.Malloc(sizeof (char *));
+ BAIL_IF_MACRO(!ecd.list, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ PHYSFS_enumerateFilesCallback(path, enumFilesCallback, &ecd);
+ ecd.list[ecd.size] = NULL;
+ return ecd.list;
+} /* PHYSFS_enumerateFiles */
+
+
+/*
+ * Broke out to seperate function so we can use stack allocation gratuitously.
+ */
+static void enumerateFromMountPoint(DirHandle *i, const char *arcfname,
+ PHYSFS_EnumFilesCallback callback,
+ const char *_fname, void *data)
+{
+ const size_t len = strlen(arcfname);
+ char *ptr = NULL;
+ char *end = NULL;
+ const size_t slen = strlen(i->mountPoint) + 1;
+ char *mountPoint = (char *) __PHYSFS_smallAlloc(slen);
+
+ if (mountPoint == NULL)
+ return; /* oh well. */
+
+ strcpy(mountPoint, i->mountPoint);
+ ptr = mountPoint + ((len) ? len + 1 : 0);
+ end = strchr(ptr, '/');
+ assert(end); /* should always find a terminating '/'. */
+ *end = '\0';
+ callback(data, _fname, ptr);
+ __PHYSFS_smallFree(mountPoint);
+} /* enumerateFromMountPoint */
+
+
+/* !!! FIXME: this should report error conditions. */
+void PHYSFS_enumerateFilesCallback(const char *_fname,
+ PHYSFS_EnumFilesCallback callback,
+ void *data)
+{
+ size_t len;
+ char *fname;
+
+ BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, ) /*0*/;
+ BAIL_IF_MACRO(!callback, PHYSFS_ERR_INVALID_ARGUMENT, ) /*0*/;
+
+ len = strlen(_fname) + 1;
+ fname = (char *) __PHYSFS_smallAlloc(len);
+ BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, ) /*0*/;
+
+ if (sanitizePlatformIndependentPath(_fname, fname))
+ {
+ DirHandle *i;
+ int noSyms;
+
+ __PHYSFS_platformGrabMutex(stateLock);
+ noSyms = !allowSymLinks;
+ for (i = searchPath; i != NULL; i = i->next)
+ {
+ char *arcfname = fname;
+ if (partOfMountPoint(i, arcfname))
+ enumerateFromMountPoint(i, arcfname, callback, _fname, data);
+
+ else if (verifyPath(i, &arcfname, 0))
+ {
+ i->funcs->enumerateFiles(i->opaque, arcfname, noSyms,
+ callback, _fname, data);
+ } /* else if */
+ } /* for */
+ __PHYSFS_platformReleaseMutex(stateLock);
+ } /* if */
+
+ __PHYSFS_smallFree(fname);
+} /* PHYSFS_enumerateFilesCallback */
+
+
+int PHYSFS_exists(const char *fname)
+{
+ return (PHYSFS_getRealDir(fname) != NULL);
+} /* PHYSFS_exists */
+
+
+PHYSFS_sint64 PHYSFS_getLastModTime(const char *fname)
+{
+ PHYSFS_Stat statbuf;
+ BAIL_IF_MACRO(!PHYSFS_stat(fname, &statbuf), ERRPASS, -1);
+ return statbuf.modtime;
+} /* PHYSFS_getLastModTime */
+
+
+int PHYSFS_isDirectory(const char *fname)
+{
+ PHYSFS_Stat statbuf;
+ BAIL_IF_MACRO(!PHYSFS_stat(fname, &statbuf), ERRPASS, 0);
+ return (statbuf.filetype == PHYSFS_FILETYPE_DIRECTORY);
+} /* PHYSFS_isDirectory */
+
+
+int PHYSFS_isSymbolicLink(const char *fname)
+{
+ PHYSFS_Stat statbuf;
+ BAIL_IF_MACRO(!PHYSFS_stat(fname, &statbuf), ERRPASS, 0);
+ return (statbuf.filetype == PHYSFS_FILETYPE_SYMLINK);
+} /* PHYSFS_isSymbolicLink */
+
+
+static PHYSFS_File *doOpenWrite(const char *_fname, int appending)
+{
+ FileHandle *fh = NULL;
+ size_t len;
+ char *fname;
+
+ BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+ len = strlen(_fname) + 1;
+ fname = (char *) __PHYSFS_smallAlloc(len);
+ BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+
+ if (sanitizePlatformIndependentPath(_fname, fname))
+ {
+ PHYSFS_Io *io = NULL;
+ DirHandle *h = NULL;
+ const PHYSFS_Archiver *f;
+
+ __PHYSFS_platformGrabMutex(stateLock);
+
+ GOTO_IF_MACRO(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, doOpenWriteEnd);
+
+ h = writeDir;
+ GOTO_IF_MACRO(!verifyPath(h, &fname, 0), ERRPASS, doOpenWriteEnd);
+
+ f = h->funcs;
+ if (appending)
+ io = f->openAppend(h->opaque, fname);
+ else
+ io = f->openWrite(h->opaque, fname);
+
+ GOTO_IF_MACRO(!io, ERRPASS, doOpenWriteEnd);
+
+ fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle));
+ if (fh == NULL)
+ {
+ io->destroy(io);
+ GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, doOpenWriteEnd);
+ } /* if */
+ else
+ {
+ memset(fh, '\0', sizeof (FileHandle));
+ fh->io = io;
+ fh->dirHandle = h;
+ fh->next = openWriteList;
+ openWriteList = fh;
+ } /* else */
+
+ doOpenWriteEnd:
+ __PHYSFS_platformReleaseMutex(stateLock);
+ } /* if */
+
+ __PHYSFS_smallFree(fname);
+ return ((PHYSFS_File *) fh);
+} /* doOpenWrite */
+
+
+PHYSFS_File *PHYSFS_openWrite(const char *filename)
+{
+ return doOpenWrite(filename, 0);
+} /* PHYSFS_openWrite */
+
+
+PHYSFS_File *PHYSFS_openAppend(const char *filename)
+{
+ return doOpenWrite(filename, 1);
+} /* PHYSFS_openAppend */
+
+
+PHYSFS_File *PHYSFS_openRead(const char *_fname)
+{
+ FileHandle *fh = NULL;
+ char *fname;
+ size_t len;
+
+ BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+ len = strlen(_fname) + 1;
+ fname = (char *) __PHYSFS_smallAlloc(len);
+ BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+
+ if (sanitizePlatformIndependentPath(_fname, fname))
+ {
+ int fileExists = 0;
+ DirHandle *i = NULL;
+ PHYSFS_Io *io = NULL;
+
+ __PHYSFS_platformGrabMutex(stateLock);
+
+ GOTO_IF_MACRO(!searchPath, PHYSFS_ERR_NO_SUCH_PATH, openReadEnd);
+
+ for (i = searchPath; (i != NULL) && (!fileExists); i = i->next)
+ {
+ char *arcfname = fname;
+ if (verifyPath(i, &arcfname, 0))
+ {
+ io = i->funcs->openRead(i->opaque, arcfname, &fileExists);
+ if (io)
+ break;
+ } /* if */
+ } /* for */
+
+ GOTO_IF_MACRO(!io, ERRPASS, openReadEnd);
+
+ fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle));
+ if (fh == NULL)
+ {
+ io->destroy(io);
+ GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, openReadEnd);
+ } /* if */
+
+ memset(fh, '\0', sizeof (FileHandle));
+ fh->io = io;
+ fh->forReading = 1;
+ fh->dirHandle = i;
+ fh->next = openReadList;
+ openReadList = fh;
+
+ openReadEnd:
+ __PHYSFS_platformReleaseMutex(stateLock);
+ } /* if */
+
+ __PHYSFS_smallFree(fname);
+ return ((PHYSFS_File *) fh);
+} /* PHYSFS_openRead */
+
+
+static int closeHandleInOpenList(FileHandle **list, FileHandle *handle)
+{
+ FileHandle *prev = NULL;
+ FileHandle *i;
+ int rc = 1;
+
+ for (i = *list; i != NULL; i = i->next)
+ {
+ if (i == handle) /* handle is in this list? */
+ {
+ PHYSFS_Io *io = handle->io;
+ PHYSFS_uint8 *tmp = handle->buffer;
+ rc = PHYSFS_flush((PHYSFS_File *) handle);
+ if (!rc)
+ return -1;
+ io->destroy(io);
+
+ if (tmp != NULL) /* free any associated buffer. */
+ allocator.Free(tmp);
+
+ if (prev == NULL)
+ *list = handle->next;
+ else
+ prev->next = handle->next;
+
+ allocator.Free(handle);
+ return 1;
+ } /* if */
+ prev = i;
+ } /* for */
+
+ return 0;
+} /* closeHandleInOpenList */
+
+
+int PHYSFS_close(PHYSFS_File *_handle)
+{
+ FileHandle *handle = (FileHandle *) _handle;
+ int rc;
+
+ __PHYSFS_platformGrabMutex(stateLock);
+
+ /* -1 == close failure. 0 == not found. 1 == success. */
+ rc = closeHandleInOpenList(&openReadList, handle);
+ BAIL_IF_MACRO_MUTEX(rc == -1, ERRPASS, stateLock, 0);
+ if (!rc)
+ {
+ rc = closeHandleInOpenList(&openWriteList, handle);
+ BAIL_IF_MACRO_MUTEX(rc == -1, ERRPASS, stateLock, 0);
+ } /* if */
+
+ __PHYSFS_platformReleaseMutex(stateLock);
+ BAIL_IF_MACRO(!rc, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+ return 1;
+} /* PHYSFS_close */
+
+
+static PHYSFS_sint64 doBufferedRead(FileHandle *fh, void *buffer,
+ PHYSFS_uint64 len)
+{
+ PHYSFS_Io *io = NULL;
+ PHYSFS_sint64 retval = 0;
+ PHYSFS_uint32 buffered = 0;
+ PHYSFS_sint64 rc = 0;
+
+ if (len == 0)
+ return 0;
+
+ buffered = fh->buffill - fh->bufpos;
+ if (buffered >= len) /* totally in the buffer, just copy and return! */
+ {
+ memcpy(buffer, fh->buffer + fh->bufpos, (size_t) len);
+ fh->bufpos += (PHYSFS_uint32) len;
+ return (PHYSFS_sint64) len;
+ } /* else if */
+
+ if (buffered > 0) /* partially in the buffer... */
+ {
+ memcpy(buffer, fh->buffer + fh->bufpos, (size_t) buffered);
+ buffer = ((PHYSFS_uint8 *) buffer) + buffered;
+ len -= buffered;
+ retval = buffered;
+ fh->buffill = fh->bufpos = 0;
+ } /* if */
+
+ /* if you got here, the buffer is drained and we still need bytes. */
+ assert(len > 0);
+
+ io = fh->io;
+ if (len >= fh->bufsize) /* need more than the buffer takes. */
+ {
+ /* leave buffer empty, go right to output instead. */
+ rc = io->read(io, buffer, len);
+ if (rc < 0)
+ return ((retval == 0) ? rc : retval);
+ return retval + rc;
+ } /* if */
+
+ /* need less than buffer can take. Fill buffer. */
+ rc = io->read(io, fh->buffer, fh->bufsize);
+ if (rc < 0)
+ return ((retval == 0) ? rc : retval);
+
+ assert(fh->bufpos == 0);
+ fh->buffill = (PHYSFS_uint32) rc;
+ rc = doBufferedRead(fh, buffer, len); /* go from the start, again. */
+ if (rc < 0)
+ return ((retval == 0) ? rc : retval);
+
+ return retval + rc;
+} /* doBufferedRead */
+
+
+PHYSFS_sint64 PHYSFS_read(PHYSFS_File *handle, void *buffer,
+ PHYSFS_uint32 size, PHYSFS_uint32 count)
+{
+ const PHYSFS_uint64 len = ((PHYSFS_uint64) size) * ((PHYSFS_uint64) count);
+ const PHYSFS_sint64 retval = PHYSFS_readBytes(handle, buffer, len);
+ return ( (retval <= 0) ? retval : (retval / ((PHYSFS_sint64) size)) );
+} /* PHYSFS_read */
+
+
+PHYSFS_sint64 PHYSFS_readBytes(PHYSFS_File *handle, void *buffer,
+ PHYSFS_uint64 len)
+{
+ FileHandle *fh = (FileHandle *) handle;
+
+#ifdef PHYSFS_NO_64BIT_SUPPORT
+ const PHYSFS_uint64 maxlen = __PHYSFS_UI64(0x7FFFFFFF);
+#else
+ const PHYSFS_uint64 maxlen = __PHYSFS_UI64(0x7FFFFFFFFFFFFFFF);
+#endif
+
+ if (!__PHYSFS_ui64FitsAddressSpace(len))
+ BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1);
+
+ BAIL_IF_MACRO(len > maxlen, PHYSFS_ERR_INVALID_ARGUMENT, -1);
+ BAIL_IF_MACRO(!fh->forReading, PHYSFS_ERR_OPEN_FOR_WRITING, -1);
+ BAIL_IF_MACRO(len == 0, ERRPASS, 0);
+ if (fh->buffer)
+ return doBufferedRead(fh, buffer, len);
+
+ return fh->io->read(fh->io, buffer, len);
+} /* PHYSFS_readBytes */
+
+
+static PHYSFS_sint64 doBufferedWrite(PHYSFS_File *handle, const void *buffer,
+ PHYSFS_uint64 len)
+{
+ FileHandle *fh = (FileHandle *) handle;
+
+ /* whole thing fits in the buffer? */
+ if ( (((PHYSFS_uint64) fh->buffill) + len) < fh->bufsize )
+ {
+ memcpy(fh->buffer + fh->buffill, buffer, (size_t) len);
+ fh->buffill += (PHYSFS_uint32) len;
+ return (PHYSFS_sint64) len;
+ } /* if */
+
+ /* would overflow buffer. Flush and then write the new objects, too. */
+ BAIL_IF_MACRO(!PHYSFS_flush(handle), ERRPASS, -1);
+ return fh->io->write(fh->io, buffer, len);
+} /* doBufferedWrite */
+
+
+PHYSFS_sint64 PHYSFS_write(PHYSFS_File *handle, const void *buffer,
+ PHYSFS_uint32 size, PHYSFS_uint32 count)
+{
+ const PHYSFS_uint64 len = ((PHYSFS_uint64) size) * ((PHYSFS_uint64) count);
+ const PHYSFS_sint64 retval = PHYSFS_writeBytes(handle, buffer, len);
+ return ( (retval <= 0) ? retval : (retval / ((PHYSFS_sint64) size)) );
+} /* PHYSFS_write */
+
+
+PHYSFS_sint64 PHYSFS_writeBytes(PHYSFS_File *handle, const void *buffer,
+ PHYSFS_uint64 len)
+{
+ FileHandle *fh = (FileHandle *) handle;
+
+#ifdef PHYSFS_NO_64BIT_SUPPORT
+ const PHYSFS_uint64 maxlen = __PHYSFS_UI64(0x7FFFFFFF);
+#else
+ const PHYSFS_uint64 maxlen = __PHYSFS_UI64(0x7FFFFFFFFFFFFFFF);
+#endif
+
+ if (!__PHYSFS_ui64FitsAddressSpace(len))
+ BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1);
+
+ BAIL_IF_MACRO(len > maxlen, PHYSFS_ERR_INVALID_ARGUMENT, -1);
+ BAIL_IF_MACRO(fh->forReading, PHYSFS_ERR_OPEN_FOR_READING, -1);
+ BAIL_IF_MACRO(len == 0, ERRPASS, 0);
+ if (fh->buffer)
+ return doBufferedWrite(handle, buffer, len);
+
+ return fh->io->write(fh->io, buffer, len);
+} /* PHYSFS_write */
+
+
+int PHYSFS_eof(PHYSFS_File *handle)
+{
+ FileHandle *fh = (FileHandle *) handle;
+
+ if (!fh->forReading) /* never EOF on files opened for write/append. */
+ return 0;
+
+ /* can't be eof if buffer isn't empty */
+ if (fh->bufpos == fh->buffill)
+ {
+ /* check the Io. */
+ PHYSFS_Io *io = fh->io;
+ const PHYSFS_sint64 pos = io->tell(io);
+ const PHYSFS_sint64 len = io->length(io);
+ if ((pos < 0) || (len < 0))
+ return 0; /* beats me. */
+ return (pos >= len);
+ } /* if */
+
+ return 0;
+} /* PHYSFS_eof */
+
+
+PHYSFS_sint64 PHYSFS_tell(PHYSFS_File *handle)
+{
+ FileHandle *fh = (FileHandle *) handle;
+ const PHYSFS_sint64 pos = fh->io->tell(fh->io);
+ const PHYSFS_sint64 retval = fh->forReading ?
+ (pos - fh->buffill) + fh->bufpos :
+ (pos + fh->buffill);
+ return retval;
+} /* PHYSFS_tell */
+
+
+int PHYSFS_seek(PHYSFS_File *handle, PHYSFS_uint64 pos)
+{
+ FileHandle *fh = (FileHandle *) handle;
+ BAIL_IF_MACRO(!PHYSFS_flush(handle), ERRPASS, 0);
+
+ if (fh->buffer && fh->forReading)
+ {
+ /* avoid throwing away our precious buffer if seeking within it. */
+ PHYSFS_sint64 offset = pos - PHYSFS_tell(handle);
+ if ( /* seeking within the already-buffered range? */
+ ((offset >= 0) && (offset <= fh->buffill - fh->bufpos)) /* fwd */
+ || ((offset < 0) && (-offset <= fh->bufpos)) /* backward */ )
+ {
+ fh->bufpos += (PHYSFS_uint32) offset;
+ return 1; /* successful seek */
+ } /* if */
+ } /* if */
+
+ /* we have to fall back to a 'raw' seek. */
+ fh->buffill = fh->bufpos = 0;
+ return fh->io->seek(fh->io, pos);
+} /* PHYSFS_seek */
+
+
+PHYSFS_sint64 PHYSFS_fileLength(PHYSFS_File *handle)
+{
+ PHYSFS_Io *io = ((FileHandle *) handle)->io;
+ return io->length(io);
+} /* PHYSFS_filelength */
+
+
+int PHYSFS_setBuffer(PHYSFS_File *handle, PHYSFS_uint64 _bufsize)
+{
+ FileHandle *fh = (FileHandle *) handle;
+ PHYSFS_uint32 bufsize;
+
+ /* !!! FIXME: actually, why use 32 bits here? */
+ /*BAIL_IF_MACRO(_bufsize > 0xFFFFFFFF, "buffer must fit in 32-bits", 0);*/
+ BAIL_IF_MACRO(_bufsize > 0xFFFFFFFF, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+ bufsize = (PHYSFS_uint32) _bufsize;
+
+ BAIL_IF_MACRO(!PHYSFS_flush(handle), ERRPASS, 0);
+
+ /*
+ * For reads, we need to move the file pointer to where it would be
+ * if we weren't buffering, so that the next read will get the
+ * right chunk of stuff from the file. PHYSFS_flush() handles writes.
+ */
+ if ((fh->forReading) && (fh->buffill != fh->bufpos))
+ {
+ PHYSFS_uint64 pos;
+ const PHYSFS_sint64 curpos = fh->io->tell(fh->io);
+ BAIL_IF_MACRO(curpos == -1, ERRPASS, 0);
+ pos = ((curpos - fh->buffill) + fh->bufpos);
+ BAIL_IF_MACRO(!fh->io->seek(fh->io, pos), ERRPASS, 0);
+ } /* if */
+
+ if (bufsize == 0) /* delete existing buffer. */
+ {
+ if (fh->buffer)
+ {
+ allocator.Free(fh->buffer);
+ fh->buffer = NULL;
+ } /* if */
+ } /* if */
+
+ else
+ {
+ PHYSFS_uint8 *newbuf;
+ newbuf = (PHYSFS_uint8 *) allocator.Realloc(fh->buffer, bufsize);
+ BAIL_IF_MACRO(!newbuf, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+ fh->buffer = newbuf;
+ } /* else */
+
+ fh->bufsize = bufsize;
+ fh->buffill = fh->bufpos = 0;
+ return 1;
+} /* PHYSFS_setBuffer */
+
+
+int PHYSFS_flush(PHYSFS_File *handle)
+{
+ FileHandle *fh = (FileHandle *) handle;
+ PHYSFS_Io *io;
+ PHYSFS_sint64 rc;
+
+ if ((fh->forReading) || (fh->bufpos == fh->buffill))
+ return 1; /* open for read or buffer empty are successful no-ops. */
+
+ /* dump buffer to disk. */
+ io = fh->io;
+ rc = io->write(io, fh->buffer + fh->bufpos, fh->buffill - fh->bufpos);
+ BAIL_IF_MACRO(rc <= 0, ERRPASS, 0);
+ fh->bufpos = fh->buffill = 0;
+ return io->flush(io);
+} /* PHYSFS_flush */
+
+
+int PHYSFS_stat(const char *_fname, PHYSFS_Stat *stat)
+{
+ int retval = 0;
+ char *fname;
+ size_t len;
+
+ BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, -1);
+ BAIL_IF_MACRO(!stat, PHYSFS_ERR_INVALID_ARGUMENT, -1);
+ len = strlen(_fname) + 1;
+ fname = (char *) __PHYSFS_smallAlloc(len);
+ BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, -1);
+
+ /* set some sane defaults... */
+ stat->filesize = -1;
+ stat->modtime = -1;
+ stat->createtime = -1;
+ stat->accesstime = -1;
+ stat->filetype = PHYSFS_FILETYPE_OTHER;
+ stat->readonly = 1; /* !!! FIXME */
+
+ if (sanitizePlatformIndependentPath(_fname, fname))
+ {
+ if (*fname == '\0')
+ {
+ stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
+ stat->readonly = !writeDir; /* Writeable if we have a writeDir */
+ retval = 1;
+ } /* if */
+ else
+ {
+ DirHandle *i;
+ int exists = 0;
+ __PHYSFS_platformGrabMutex(stateLock);
+ for (i = searchPath; ((i != NULL) && (!exists)); i = i->next)
+ {
+ char *arcfname = fname;
+ exists = partOfMountPoint(i, arcfname);
+ if (exists)
+ {
+ stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
+ stat->readonly = 1; /* !!! FIXME */
+ retval = 1;
+ } /* if */
+ else if (verifyPath(i, &arcfname, 0))
+ {
+ /* !!! FIXME: this test is wrong and should be elsewhere. */
+ stat->readonly = !(writeDir &&
+ (strcmp(writeDir->dirName, i->dirName) == 0));
+ retval = i->funcs->stat(i->opaque, arcfname, &exists, stat);
+ } /* else if */
+ } /* for */
+ __PHYSFS_platformReleaseMutex(stateLock);
+ } /* else */
+ } /* if */
+
+ __PHYSFS_smallFree(fname);
+ return retval;
+} /* PHYSFS_stat */
+
+
+int __PHYSFS_readAll(PHYSFS_Io *io, void *buf, const PHYSFS_uint64 len)
+{
+ return (io->read(io, buf, len) == len);
+} /* __PHYSFS_readAll */
+
+
+void *__PHYSFS_initSmallAlloc(void *ptr, PHYSFS_uint64 len)
+{
+ void *useHeap = ((ptr == NULL) ? ((void *) 1) : ((void *) 0));
+ if (useHeap) /* too large for stack allocation or alloca() failed. */
+ ptr = allocator.Malloc(len+sizeof (void *));
+
+ if (ptr != NULL)
+ {
+ void **retval = (void **) ptr;
+ /*printf("%s alloc'd (%d) bytes at (%p).\n",
+ useHeap ? "heap" : "stack", (int) len, ptr);*/
+ *retval = useHeap;
+ return retval + 1;
+ } /* if */
+
+ return NULL; /* allocation failed. */
+} /* __PHYSFS_initSmallAlloc */
+
+
+void __PHYSFS_smallFree(void *ptr)
+{
+ if (ptr != NULL)
+ {
+ void **block = ((void **) ptr) - 1;
+ const int useHeap = (*block != 0);
+ if (useHeap)
+ allocator.Free(block);
+ /*printf("%s free'd (%p).\n", useHeap ? "heap" : "stack", block);*/
+ } /* if */
+} /* __PHYSFS_smallFree */
+
+
+int PHYSFS_setAllocator(const PHYSFS_Allocator *a)
+{
+ BAIL_IF_MACRO(initialized, PHYSFS_ERR_IS_INITIALIZED, 0);
+ externalAllocator = (a != NULL);
+ if (externalAllocator)
+ memcpy(&allocator, a, sizeof (PHYSFS_Allocator));
+
+ return 1;
+} /* PHYSFS_setAllocator */
+
+
+const PHYSFS_Allocator *PHYSFS_getAllocator(void)
+{
+ BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, NULL);
+ return &allocator;
+} /* PHYSFS_getAllocator */
+
+
+static void *mallocAllocatorMalloc(PHYSFS_uint64 s)
+{
+ if (!__PHYSFS_ui64FitsAddressSpace(s))
+ BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ #undef malloc
+ return malloc((size_t) s);
+} /* mallocAllocatorMalloc */
+
+
+static void *mallocAllocatorRealloc(void *ptr, PHYSFS_uint64 s)
+{
+ if (!__PHYSFS_ui64FitsAddressSpace(s))
+ BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ #undef realloc
+ return realloc(ptr, (size_t) s);
+} /* mallocAllocatorRealloc */
+
+
+static void mallocAllocatorFree(void *ptr)
+{
+ #undef free
+ free(ptr);
+} /* mallocAllocatorFree */
+
+
+static void setDefaultAllocator(void)
+{
+ assert(!externalAllocator);
+ if (!__PHYSFS_platformSetDefaultAllocator(&allocator))
+ {
+ allocator.Init = NULL;
+ allocator.Deinit = NULL;
+ allocator.Malloc = mallocAllocatorMalloc;
+ allocator.Realloc = mallocAllocatorRealloc;
+ allocator.Free = mallocAllocatorFree;
+ } /* if */
+} /* setDefaultAllocator */
+
+/* end of physfs.c ... */
+
diff -r 404ddce27b23 -r c13ebed437cb misc/libphysfs/physfs.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/physfs.h Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,3324 @@
+/**
+ * \file physfs.h
+ *
+ * Main header file for PhysicsFS.
+ */
+
+/**
+ * \mainpage PhysicsFS
+ *
+ * The latest version of PhysicsFS can be found at:
+ * http://icculus.org/physfs/
+ *
+ * PhysicsFS; a portable, flexible file i/o abstraction.
+ *
+ * This API gives you access to a system file system in ways superior to the
+ * stdio or system i/o calls. The brief benefits:
+ *
+ * - It's portable.
+ * - It's safe. No file access is permitted outside the specified dirs.
+ * - It's flexible. Archives (.ZIP files) can be used transparently as
+ * directory structures.
+ *
+ * This system is largely inspired by Quake 3's PK3 files and the related
+ * fs_* cvars. If you've ever tinkered with these, then this API will be
+ * familiar to you.
+ *
+ * With PhysicsFS, you have a single writing directory and multiple
+ * directories (the "search path") for reading. You can think of this as a
+ * filesystem within a filesystem. If (on Windows) you were to set the
+ * writing directory to "C:\MyGame\MyWritingDirectory", then no PHYSFS calls
+ * could touch anything above this directory, including the "C:\MyGame" and
+ * "C:\" directories. This prevents an application's internal scripting
+ * language from piddling over c:\\config.sys, for example. If you'd rather
+ * give PHYSFS full access to the system's REAL file system, set the writing
+ * dir to "C:\", but that's generally A Bad Thing for several reasons.
+ *
+ * Drive letters are hidden in PhysicsFS once you set up your initial paths.
+ * The search path creates a single, hierarchical directory structure.
+ * Not only does this lend itself well to general abstraction with archives,
+ * it also gives better support to operating systems like MacOS and Unix.
+ * Generally speaking, you shouldn't ever hardcode a drive letter; not only
+ * does this hurt portability to non-Microsoft OSes, but it limits your win32
+ * users to a single drive, too. Use the PhysicsFS abstraction functions and
+ * allow user-defined configuration options, too. When opening a file, you
+ * specify it like it was on a Unix filesystem: if you want to write to
+ * "C:\MyGame\MyConfigFiles\game.cfg", then you might set the write dir to
+ * "C:\MyGame" and then open "MyConfigFiles/game.cfg". This gives an
+ * abstraction across all platforms. Specifying a file in this way is termed
+ * "platform-independent notation" in this documentation. Specifying a
+ * a filename in a form such as "C:\mydir\myfile" or
+ * "MacOS hard drive:My Directory:My File" is termed "platform-dependent
+ * notation". The only time you use platform-dependent notation is when
+ * setting up your write directory and search path; after that, all file
+ * access into those directories are done with platform-independent notation.
+ *
+ * All files opened for writing are opened in relation to the write directory,
+ * which is the root of the writable filesystem. When opening a file for
+ * reading, PhysicsFS goes through the search path. This is NOT the
+ * same thing as the PATH environment variable. An application using
+ * PhysicsFS specifies directories to be searched which may be actual
+ * directories, or archive files that contain files and subdirectories of
+ * their own. See the end of these docs for currently supported archive
+ * formats.
+ *
+ * Once the search path is defined, you may open files for reading. If you've
+ * got the following search path defined (to use a win32 example again):
+ *
+ * - C:\\mygame
+ * - C:\\mygame\\myuserfiles
+ * - D:\\mygamescdromdatafiles
+ * - C:\\mygame\\installeddatafiles.zip
+ *
+ * Then a call to PHYSFS_openRead("textfiles/myfile.txt") (note the directory
+ * separator, lack of drive letter, and lack of dir separator at the start of
+ * the string; this is platform-independent notation) will check for
+ * C:\\mygame\\textfiles\\myfile.txt, then
+ * C:\\mygame\\myuserfiles\\textfiles\\myfile.txt, then
+ * D:\\mygamescdromdatafiles\\textfiles\\myfile.txt, then, finally, for
+ * textfiles\\myfile.txt inside of C:\\mygame\\installeddatafiles.zip.
+ * Remember that most archive types and platform filesystems store their
+ * filenames in a case-sensitive manner, so you should be careful to specify
+ * it correctly.
+ *
+ * Files opened through PhysicsFS may NOT contain "." or ".." or ":" as dir
+ * elements. Not only are these meaningless on MacOS Classic and/or Unix,
+ * they are a security hole. Also, symbolic links (which can be found in
+ * some archive types and directly in the filesystem on Unix platforms) are
+ * NOT followed until you call PHYSFS_permitSymbolicLinks(). That's left to
+ * your own discretion, as following a symlink can allow for access outside
+ * the write dir and search paths. For portability, there is no mechanism for
+ * creating new symlinks in PhysicsFS.
+ *
+ * The write dir is not included in the search path unless you specifically
+ * add it. While you CAN change the write dir as many times as you like,
+ * you should probably set it once and stick to it. Remember that your
+ * program will not have permission to write in every directory on Unix and
+ * NT systems.
+ *
+ * All files are opened in binary mode; there is no endline conversion for
+ * textfiles. Other than that, PhysicsFS has some convenience functions for
+ * platform-independence. There is a function to tell you the current
+ * platform's dir separator ("\\" on windows, "/" on Unix, ":" on MacOS),
+ * which is needed only to set up your search/write paths. There is a
+ * function to tell you what CD-ROM drives contain accessible discs, and a
+ * function to recommend a good search path, etc.
+ *
+ * A recommended order for the search path is the write dir, then the base dir,
+ * then the cdrom dir, then any archives discovered. Quake 3 does something
+ * like this, but moves the archives to the start of the search path. Build
+ * Engine games, like Duke Nukem 3D and Blood, place the archives last, and
+ * use the base dir for both searching and writing. There is a helper
+ * function (PHYSFS_setSaneConfig()) that puts together a basic configuration
+ * for you, based on a few parameters. Also see the comments on
+ * PHYSFS_getBaseDir(), and PHYSFS_getPrefDir() for info on what those
+ * are and how they can help you determine an optimal search path.
+ *
+ * PhysicsFS 2.0 adds the concept of "mounting" archives to arbitrary points
+ * in the search path. If a zipfile contains "maps/level.map" and you mount
+ * that archive at "mods/mymod", then you would have to open
+ * "mods/mymod/maps/level.map" to access the file, even though "mods/mymod"
+ * isn't actually specified in the .zip file. Unlike the Unix mentality of
+ * mounting a filesystem, "mods/mymod" doesn't actually have to exist when
+ * mounting the zipfile. It's a "virtual" directory. The mounting mechanism
+ * allows the developer to seperate archives in the tree and avoid trampling
+ * over files when added new archives, such as including mod support in a
+ * game...keeping external content on a tight leash in this manner can be of
+ * utmost importance to some applications.
+ *
+ * PhysicsFS is mostly thread safe. The error messages returned by
+ * PHYSFS_getLastError() are unique by thread, and library-state-setting
+ * functions are mutex'd. For efficiency, individual file accesses are
+ * not locked, so you can not safely read/write/seek/close/etc the same
+ * file from two threads at the same time. Other race conditions are bugs
+ * that should be reported/patched.
+ *
+ * While you CAN use stdio/syscall file access in a program that has PHYSFS_*
+ * calls, doing so is not recommended, and you can not use system
+ * filehandles with PhysicsFS and vice versa.
+ *
+ * Note that archives need not be named as such: if you have a ZIP file and
+ * rename it with a .PKG extension, the file will still be recognized as a
+ * ZIP archive by PhysicsFS; the file's contents are used to determine its
+ * type where possible.
+ *
+ * Currently supported archive types:
+ * - .ZIP (pkZip/WinZip/Info-ZIP compatible)
+ * - .7Z (7zip archives)
+ * - .ISO (ISO9660 files, CD-ROM images)
+ * - .GRP (Build Engine groupfile archives)
+ * - .PAK (Quake I/II archive format)
+ * - .HOG (Descent I/II HOG file archives)
+ * - .MVL (Descent II movielib archives)
+ * - .WAD (DOOM engine archives)
+ *
+ *
+ * String policy for PhysicsFS 2.0 and later:
+ *
+ * PhysicsFS 1.0 could only deal with null-terminated ASCII strings. All high
+ * ASCII chars resulted in undefined behaviour, and there was no Unicode
+ * support at all. PhysicsFS 2.0 supports Unicode without breaking binary
+ * compatibility with the 1.0 API by using UTF-8 encoding of all strings
+ * passed in and out of the library.
+ *
+ * All strings passed through PhysicsFS are in null-terminated UTF-8 format.
+ * This means that if all you care about is English (ASCII characters <= 127)
+ * then you just use regular C strings. If you care about Unicode (and you
+ * should!) then you need to figure out what your platform wants, needs, and
+ * offers. If you are on Windows before Win2000 and build with Unicode
+ * support, your TCHAR strings are two bytes per character (this is called
+ * "UCS-2 encoding"). Any modern Windows uses UTF-16, which is two bytes
+ * per character for most characters, but some characters are four. You
+ * should convert them to UTF-8 before handing them to PhysicsFS with
+ * PHYSFS_utf8FromUtf16(), which handles both UTF-16 and UCS-2. If you're
+ * using Unix or Mac OS X, your wchar_t strings are four bytes per character
+ * ("UCS-4 encoding"). Use PHYSFS_utf8FromUcs4(). Mac OS X can give you UTF-8
+ * directly from a CFString or NSString, and many Unixes generally give you C
+ * strings in UTF-8 format everywhere. If you have a single-byte high ASCII
+ * charset, like so-many European "codepages" you may be out of luck. We'll
+ * convert from "Latin1" to UTF-8 only, and never back to Latin1. If you're
+ * above ASCII 127, all bets are off: move to Unicode or use your platform's
+ * facilities. Passing a C string with high-ASCII data that isn't UTF-8
+ * encoded will NOT do what you expect!
+ *
+ * Naturally, there's also PHYSFS_utf8ToUcs2(), PHYSFS_utf8ToUtf16(), and
+ * PHYSFS_utf8ToUcs4() to get data back into a format you like. Behind the
+ * scenes, PhysicsFS will use Unicode where possible: the UTF-8 strings on
+ * Windows will be converted and used with the multibyte Windows APIs, for
+ * example.
+ *
+ * PhysicsFS offers basic encoding conversion support, but not a whole string
+ * library. Get your stuff into whatever format you can work with.
+ *
+ * All platforms supported by PhysicsFS 2.1 and later fully support Unicode.
+ * We have dropped platforms that don't (OS/2, Mac OS 9, Windows 95, etc), as
+ * even an OS that's over a decade old should be expected to handle this well.
+ * If you absolutely must support one of these platforms, you should use an
+ * older release of PhysicsFS.
+ *
+ * Many game-specific archivers are seriously unprepared for Unicode (the
+ * Descent HOG/MVL and Build Engine GRP archivers, for example, only offer a
+ * DOS 8.3 filename, for example). Nothing can be done for these, but they
+ * tend to be legacy formats for existing content that was all ASCII (and
+ * thus, valid UTF-8) anyhow. Other formats, like .ZIP, don't explicitly
+ * offer Unicode support, but unofficially expect filenames to be UTF-8
+ * encoded, and thus Just Work. Most everything does the right thing without
+ * bothering you, but it's good to be aware of these nuances in case they
+ * don't.
+ *
+ *
+ * Other stuff:
+ *
+ * Please see the file LICENSE.txt in the source's root directory for
+ * licensing and redistribution rights.
+ *
+ * Please see the file CREDITS.txt in the source's "docs" directory for
+ * a more or less complete list of who's responsible for this.
+ *
+ * \author Ryan C. Gordon.
+ */
+
+#ifndef _INCLUDE_PHYSFS_H_
+#define _INCLUDE_PHYSFS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(PHYSFS_DECL)
+/* do nothing. */
+#elif (defined SWIG)
+#define PHYSFS_DECL extern
+#elif (defined _MSC_VER)
+#define PHYSFS_DECL __declspec(dllexport)
+#elif (defined __SUNPRO_C)
+#define PHYSFS_DECL __global
+#elif ((__GNUC__ >= 3) && (!__EMX__) && (!sun))
+#define PHYSFS_DECL __attribute__((visibility("default")))
+#else
+#define PHYSFS_DECL
+#endif
+
+#if defined(PHYSFS_DEPRECATED)
+/* do nothing. */
+#elif (defined SWIG) /* ignore deprecated, since bindings use everything. */
+#define PHYSFS_DEPRECATED
+#elif (__GNUC__ >= 4) /* technically, this arrived in gcc 3.1, but oh well. */
+#define PHYSFS_DEPRECATED __attribute__((deprecated))
+#else
+#define PHYSFS_DEPRECATED
+#endif
+
+#if 0 /* !!! FIXME: look into this later. */
+#if defined(PHYSFS_CALL)
+/* do nothing. */
+#elif defined(__WIN32__) && !defined(__GNUC__)
+#define PHYSFS_CALL __cdecl
+#else
+#define PHYSFS_CALL
+#endif
+#endif
+
+/**
+ * \typedef PHYSFS_uint8
+ * \brief An unsigned, 8-bit integer type.
+ */
+typedef unsigned char PHYSFS_uint8;
+
+/**
+ * \typedef PHYSFS_sint8
+ * \brief A signed, 8-bit integer type.
+ */
+typedef signed char PHYSFS_sint8;
+
+/**
+ * \typedef PHYSFS_uint16
+ * \brief An unsigned, 16-bit integer type.
+ */
+typedef unsigned short PHYSFS_uint16;
+
+/**
+ * \typedef PHYSFS_sint16
+ * \brief A signed, 16-bit integer type.
+ */
+typedef signed short PHYSFS_sint16;
+
+/**
+ * \typedef PHYSFS_uint32
+ * \brief An unsigned, 32-bit integer type.
+ */
+typedef unsigned int PHYSFS_uint32;
+
+/**
+ * \typedef PHYSFS_sint32
+ * \brief A signed, 32-bit integer type.
+ */
+typedef signed int PHYSFS_sint32;
+
+/**
+ * \typedef PHYSFS_uint64
+ * \brief An unsigned, 64-bit integer type.
+ * \warning on platforms without any sort of 64-bit datatype, this is
+ * equivalent to PHYSFS_uint32!
+ */
+
+/**
+ * \typedef PHYSFS_sint64
+ * \brief A signed, 64-bit integer type.
+ * \warning on platforms without any sort of 64-bit datatype, this is
+ * equivalent to PHYSFS_sint32!
+ */
+
+
+#if (defined PHYSFS_NO_64BIT_SUPPORT) /* oh well. */
+typedef PHYSFS_uint32 PHYSFS_uint64;
+typedef PHYSFS_sint32 PHYSFS_sint64;
+#elif (defined _MSC_VER)
+typedef signed __int64 PHYSFS_sint64;
+typedef unsigned __int64 PHYSFS_uint64;
+#else
+typedef unsigned long long PHYSFS_uint64;
+typedef signed long long PHYSFS_sint64;
+#endif
+
+
+#ifndef SWIG
+#ifndef DOXYGEN_SHOULD_IGNORE_THIS
+/* Make sure the types really have the right sizes */
+#define PHYSFS_COMPILE_TIME_ASSERT(name, x) \
+ typedef int PHYSFS_dummy_ ## name[(x) * 2 - 1]
+
+PHYSFS_COMPILE_TIME_ASSERT(uint8, sizeof(PHYSFS_uint8) == 1);
+PHYSFS_COMPILE_TIME_ASSERT(sint8, sizeof(PHYSFS_sint8) == 1);
+PHYSFS_COMPILE_TIME_ASSERT(uint16, sizeof(PHYSFS_uint16) == 2);
+PHYSFS_COMPILE_TIME_ASSERT(sint16, sizeof(PHYSFS_sint16) == 2);
+PHYSFS_COMPILE_TIME_ASSERT(uint32, sizeof(PHYSFS_uint32) == 4);
+PHYSFS_COMPILE_TIME_ASSERT(sint32, sizeof(PHYSFS_sint32) == 4);
+
+#ifndef PHYSFS_NO_64BIT_SUPPORT
+PHYSFS_COMPILE_TIME_ASSERT(uint64, sizeof(PHYSFS_uint64) == 8);
+PHYSFS_COMPILE_TIME_ASSERT(sint64, sizeof(PHYSFS_sint64) == 8);
+#endif
+
+#undef PHYSFS_COMPILE_TIME_ASSERT
+
+#endif /* DOXYGEN_SHOULD_IGNORE_THIS */
+#endif /* SWIG */
+
+
+/**
+ * \struct PHYSFS_File
+ * \brief A PhysicsFS file handle.
+ *
+ * You get a pointer to one of these when you open a file for reading,
+ * writing, or appending via PhysicsFS.
+ *
+ * As you can see from the lack of meaningful fields, you should treat this
+ * as opaque data. Don't try to manipulate the file handle, just pass the
+ * pointer you got, unmolested, to various PhysicsFS APIs.
+ *
+ * \sa PHYSFS_openRead
+ * \sa PHYSFS_openWrite
+ * \sa PHYSFS_openAppend
+ * \sa PHYSFS_close
+ * \sa PHYSFS_read
+ * \sa PHYSFS_write
+ * \sa PHYSFS_seek
+ * \sa PHYSFS_tell
+ * \sa PHYSFS_eof
+ * \sa PHYSFS_setBuffer
+ * \sa PHYSFS_flush
+ */
+typedef struct PHYSFS_File
+{
+ void *opaque; /**< That's all you get. Don't touch. */
+} PHYSFS_File;
+
+
+/**
+ * \def PHYSFS_file
+ * \brief 1.0 API compatibility define.
+ *
+ * PHYSFS_file is identical to PHYSFS_File. This #define is here for backwards
+ * compatibility with the 1.0 API, which had an inconsistent capitalization
+ * convention in this case. New code should use PHYSFS_File, as this #define
+ * may go away someday.
+ *
+ * \sa PHYSFS_File
+ */
+#define PHYSFS_file PHYSFS_File
+
+
+/**
+ * \struct PHYSFS_ArchiveInfo
+ * \brief Information on various PhysicsFS-supported archives.
+ *
+ * This structure gives you details on what sort of archives are supported
+ * by this implementation of PhysicsFS. Archives tend to be things like
+ * ZIP files and such.
+ *
+ * \warning Not all binaries are created equal! PhysicsFS can be built with
+ * or without support for various archives. You can check with
+ * PHYSFS_supportedArchiveTypes() to see if your archive type is
+ * supported.
+ *
+ * \sa PHYSFS_supportedArchiveTypes
+ */
+typedef struct PHYSFS_ArchiveInfo
+{
+ const char *extension; /**< Archive file extension: "ZIP", for example. */
+ const char *description; /**< Human-readable archive description. */
+ const char *author; /**< Person who did support for this archive. */
+ const char *url; /**< URL related to this archive */
+} PHYSFS_ArchiveInfo;
+
+
+/**
+ * \struct PHYSFS_Version
+ * \brief Information the version of PhysicsFS in use.
+ *
+ * Represents the library's version as three levels: major revision
+ * (increments with massive changes, additions, and enhancements),
+ * minor revision (increments with backwards-compatible changes to the
+ * major revision), and patchlevel (increments with fixes to the minor
+ * revision).
+ *
+ * \sa PHYSFS_VERSION
+ * \sa PHYSFS_getLinkedVersion
+ */
+typedef struct PHYSFS_Version
+{
+ PHYSFS_uint8 major; /**< major revision */
+ PHYSFS_uint8 minor; /**< minor revision */
+ PHYSFS_uint8 patch; /**< patchlevel */
+} PHYSFS_Version;
+
+
+#ifndef SWIG /* not available from scripting languages. */
+
+#ifndef DOXYGEN_SHOULD_IGNORE_THIS
+#define PHYSFS_VER_MAJOR 2
+#define PHYSFS_VER_MINOR 1
+#define PHYSFS_VER_PATCH 0
+#endif /* DOXYGEN_SHOULD_IGNORE_THIS */
+
+
+/* PhysicsFS state stuff ... */
+
+/**
+ * \def PHYSFS_VERSION(x)
+ * \brief Macro to determine PhysicsFS version program was compiled against.
+ *
+ * This macro fills in a PHYSFS_Version structure with the version of the
+ * library you compiled against. This is determined by what header the
+ * compiler uses. Note that if you dynamically linked the library, you might
+ * have a slightly newer or older version at runtime. That version can be
+ * determined with PHYSFS_getLinkedVersion(), which, unlike PHYSFS_VERSION,
+ * is not a macro.
+ *
+ * \param x A pointer to a PHYSFS_Version struct to initialize.
+ *
+ * \sa PHYSFS_Version
+ * \sa PHYSFS_getLinkedVersion
+ */
+#define PHYSFS_VERSION(x) \
+{ \
+ (x)->major = PHYSFS_VER_MAJOR; \
+ (x)->minor = PHYSFS_VER_MINOR; \
+ (x)->patch = PHYSFS_VER_PATCH; \
+}
+
+#endif /* SWIG */
+
+
+/**
+ * \fn void PHYSFS_getLinkedVersion(PHYSFS_Version *ver)
+ * \brief Get the version of PhysicsFS that is linked against your program.
+ *
+ * If you are using a shared library (DLL) version of PhysFS, then it is
+ * possible that it will be different than the version you compiled against.
+ *
+ * This is a real function; the macro PHYSFS_VERSION tells you what version
+ * of PhysFS you compiled against:
+ *
+ * \code
+ * PHYSFS_Version compiled;
+ * PHYSFS_Version linked;
+ *
+ * PHYSFS_VERSION(&compiled);
+ * PHYSFS_getLinkedVersion(&linked);
+ * printf("We compiled against PhysFS version %d.%d.%d ...\n",
+ * compiled.major, compiled.minor, compiled.patch);
+ * printf("But we linked against PhysFS version %d.%d.%d.\n",
+ * linked.major, linked.minor, linked.patch);
+ * \endcode
+ *
+ * This function may be called safely at any time, even before PHYSFS_init().
+ *
+ * \sa PHYSFS_VERSION
+ */
+PHYSFS_DECL void PHYSFS_getLinkedVersion(PHYSFS_Version *ver);
+
+
+/**
+ * \fn int PHYSFS_init(const char *argv0)
+ * \brief Initialize the PhysicsFS library.
+ *
+ * This must be called before any other PhysicsFS function.
+ *
+ * This should be called prior to any attempts to change your process's
+ * current working directory.
+ *
+ * \param argv0 the argv[0] string passed to your program's mainline.
+ * This may be NULL on most platforms (such as ones without a
+ * standard main() function), but you should always try to pass
+ * something in here. Unix-like systems such as Linux _need_ to
+ * pass argv[0] from main() in here.
+ * \return nonzero on success, zero on error. Specifics of the error can be
+ * gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_deinit
+ * \sa PHYSFS_isInit
+ */
+PHYSFS_DECL int PHYSFS_init(const char *argv0);
+
+
+/**
+ * \fn int PHYSFS_deinit(void)
+ * \brief Deinitialize the PhysicsFS library.
+ *
+ * This closes any files opened via PhysicsFS, blanks the search/write paths,
+ * frees memory, and invalidates all of your file handles.
+ *
+ * Note that this call can FAIL if there's a file open for writing that
+ * refuses to close (for example, the underlying operating system was
+ * buffering writes to network filesystem, and the fileserver has crashed,
+ * or a hard drive has failed, etc). It is usually best to close all write
+ * handles yourself before calling this function, so that you can gracefully
+ * handle a specific failure.
+ *
+ * Once successfully deinitialized, PHYSFS_init() can be called again to
+ * restart the subsystem. All default API states are restored at this
+ * point, with the exception of any custom allocator you might have
+ * specified, which survives between initializations.
+ *
+ * \return nonzero on success, zero on error. Specifics of the error can be
+ * gleaned from PHYSFS_getLastError(). If failure, state of PhysFS is
+ * undefined, and probably badly screwed up.
+ *
+ * \sa PHYSFS_init
+ * \sa PHYSFS_isInit
+ */
+PHYSFS_DECL int PHYSFS_deinit(void);
+
+
+/**
+ * \fn const PHYSFS_ArchiveInfo **PHYSFS_supportedArchiveTypes(void)
+ * \brief Get a list of supported archive types.
+ *
+ * Get a list of archive types supported by this implementation of PhysicFS.
+ * These are the file formats usable for search path entries. This is for
+ * informational purposes only. Note that the extension listed is merely
+ * convention: if we list "ZIP", you can open a PkZip-compatible archive
+ * with an extension of "XYZ", if you like.
+ *
+ * The returned value is an array of pointers to PHYSFS_ArchiveInfo structures,
+ * with a NULL entry to signify the end of the list:
+ *
+ * \code
+ * PHYSFS_ArchiveInfo **i;
+ *
+ * for (i = PHYSFS_supportedArchiveTypes(); *i != NULL; i++)
+ * {
+ * printf("Supported archive: [%s], which is [%s].\n",
+ * (*i)->extension, (*i)->description);
+ * }
+ * \endcode
+ *
+ * The return values are pointers to internal memory, and should
+ * be considered READ ONLY, and never freed. The returned values are
+ * valid until the next call to PHYSFS_deinit().
+ *
+ * \return READ ONLY Null-terminated array of READ ONLY structures.
+ */
+PHYSFS_DECL const PHYSFS_ArchiveInfo **PHYSFS_supportedArchiveTypes(void);
+
+
+/**
+ * \fn void PHYSFS_freeList(void *listVar)
+ * \brief Deallocate resources of lists returned by PhysicsFS.
+ *
+ * Certain PhysicsFS functions return lists of information that are
+ * dynamically allocated. Use this function to free those resources.
+ *
+ * It is safe to pass a NULL here, but doing so will cause a crash in versions
+ * before PhysicsFS 2.1.0.
+ *
+ * \param listVar List of information specified as freeable by this function.
+ * Passing NULL is safe; it is a valid no-op.
+ *
+ * \sa PHYSFS_getCdRomDirs
+ * \sa PHYSFS_enumerateFiles
+ * \sa PHYSFS_getSearchPath
+ */
+PHYSFS_DECL void PHYSFS_freeList(void *listVar);
+
+
+/**
+ * \fn const char *PHYSFS_getLastError(void)
+ * \brief Get human-readable error information.
+ *
+ * \warning As of PhysicsFS 2.1, this function has been nerfed.
+ * Before PhysicsFS 2.1, this function was the only way to get
+ * error details beyond a given function's basic return value.
+ * This was meant to be a human-readable string in one of several
+ * languages, and was not useful for application parsing. This was
+ * a problem, because the developer and not the user chose the
+ * language at compile time, and the PhysicsFS maintainers had
+ * to (poorly) maintain a significant amount of localization work.
+ * The app couldn't parse the strings, even if they counted on a
+ * specific language, since some were dynamically generated.
+ * In 2.1 and later, this always returns a static string in
+ * English; you may use it as a key string for your own
+ * localizations if you like, as we'll promise not to change
+ * existing error strings. Also, if your application wants to
+ * look at specific errors, we now offer a better option:
+ * use PHYSFS_getLastErrorCode() instead.
+ *
+ * Get the last PhysicsFS error message as a human-readable, null-terminated
+ * string. This will return NULL if there's been no error since the last call
+ * to this function. The pointer returned by this call points to an internal
+ * buffer. Each thread has a unique error state associated with it, but each
+ * time a new error message is set, it will overwrite the previous one
+ * associated with that thread. It is safe to call this function at anytime,
+ * even before PHYSFS_init().
+ *
+ * PHYSFS_getLastError() and PHYSFS_getLastErrorCode() both reset the same
+ * thread-specific error state. Calling one will wipe out the other's
+ * data. If you need both, call PHYSFS_getLastErrorCode(), then pass that
+ * value to PHYSFS_getErrorByCode().
+ *
+ * As of PhysicsFS 2.1, this function only presents text in the English
+ * language, but the strings are static, so you can use them as keys into
+ * your own localization dictionary. These strings are meant to be passed on
+ * directly to the user.
+ *
+ * Generally, applications should only concern themselves with whether a
+ * given function failed; however, if your code require more specifics, you
+ * should use PHYSFS_getLastErrorCode() instead of this function.
+ *
+ * \return READ ONLY string of last error message.
+ *
+ * \sa PHYSFS_getLastErrorCode
+ * \sa PHYSFS_getErrorByCode
+ */
+PHYSFS_DECL const char *PHYSFS_getLastError(void);
+
+
+/**
+ * \fn const char *PHYSFS_getDirSeparator(void)
+ * \brief Get platform-dependent dir separator string.
+ *
+ * This returns "\\" on win32, "/" on Unix, and ":" on MacOS. It may be more
+ * than one character, depending on the platform, and your code should take
+ * that into account. Note that this is only useful for setting up the
+ * search/write paths, since access into those dirs always use '/'
+ * (platform-independent notation) to separate directories. This is also
+ * handy for getting platform-independent access when using stdio calls.
+ *
+ * \return READ ONLY null-terminated string of platform's dir separator.
+ */
+PHYSFS_DECL const char *PHYSFS_getDirSeparator(void);
+
+
+/**
+ * \fn void PHYSFS_permitSymbolicLinks(int allow)
+ * \brief Enable or disable following of symbolic links.
+ *
+ * Some physical filesystems and archives contain files that are just pointers
+ * to other files. On the physical filesystem, opening such a link will
+ * (transparently) open the file that is pointed to.
+ *
+ * By default, PhysicsFS will check if a file is really a symlink during open
+ * calls and fail if it is. Otherwise, the link could take you outside the
+ * write and search paths, and compromise security.
+ *
+ * If you want to take that risk, call this function with a non-zero parameter.
+ * Note that this is more for sandboxing a program's scripting language, in
+ * case untrusted scripts try to compromise the system. Generally speaking,
+ * a user could very well have a legitimate reason to set up a symlink, so
+ * unless you feel there's a specific danger in allowing them, you should
+ * permit them.
+ *
+ * Symlinks are only explicitly checked when dealing with filenames
+ * in platform-independent notation. That is, when setting up your
+ * search and write paths, etc, symlinks are never checked for.
+ *
+ * Please note that PHYSFS_stat() will always check the path specified; if
+ * that path is a symlink, it will not be followed in any case. If symlinks
+ * aren't permitted through this function, PHYSFS_stat() ignores them, and
+ * would treat the query as if the path didn't exist at all.
+ *
+ * Symbolic link permission can be enabled or disabled at any time after
+ * you've called PHYSFS_init(), and is disabled by default.
+ *
+ * \param allow nonzero to permit symlinks, zero to deny linking.
+ *
+ * \sa PHYSFS_symbolicLinksPermitted
+ */
+PHYSFS_DECL void PHYSFS_permitSymbolicLinks(int allow);
+
+
+/* !!! FIXME: const this? */
+/**
+ * \fn char **PHYSFS_getCdRomDirs(void)
+ * \brief Get an array of paths to available CD-ROM drives.
+ *
+ * The dirs returned are platform-dependent ("D:\" on Win32, "/cdrom" or
+ * whatnot on Unix). Dirs are only returned if there is a disc ready and
+ * accessible in the drive. So if you've got two drives (D: and E:), and only
+ * E: has a disc in it, then that's all you get. If the user inserts a disc
+ * in D: and you call this function again, you get both drives. If, on a
+ * Unix box, the user unmounts a disc and remounts it elsewhere, the next
+ * call to this function will reflect that change.
+ *
+ * This function refers to "CD-ROM" media, but it really means "inserted disc
+ * media," such as DVD-ROM, HD-DVD, CDRW, and Blu-Ray discs. It looks for
+ * filesystems, and as such won't report an audio CD, unless there's a
+ * mounted filesystem track on it.
+ *
+ * The returned value is an array of strings, with a NULL entry to signify the
+ * end of the list:
+ *
+ * \code
+ * char **cds = PHYSFS_getCdRomDirs();
+ * char **i;
+ *
+ * for (i = cds; *i != NULL; i++)
+ * printf("cdrom dir [%s] is available.\n", *i);
+ *
+ * PHYSFS_freeList(cds);
+ * \endcode
+ *
+ * This call may block while drives spin up. Be forewarned.
+ *
+ * When you are done with the returned information, you may dispose of the
+ * resources by calling PHYSFS_freeList() with the returned pointer.
+ *
+ * \return Null-terminated array of null-terminated strings.
+ *
+ * \sa PHYSFS_getCdRomDirsCallback
+ */
+PHYSFS_DECL char **PHYSFS_getCdRomDirs(void);
+
+
+/**
+ * \fn const char *PHYSFS_getBaseDir(void)
+ * \brief Get the path where the application resides.
+ *
+ * Helper function.
+ *
+ * Get the "base dir". This is the directory where the application was run
+ * from, which is probably the installation directory, and may or may not
+ * be the process's current working directory.
+ *
+ * You should probably use the base dir in your search path.
+ *
+ * \return READ ONLY string of base dir in platform-dependent notation.
+ *
+ * \sa PHYSFS_getPrefDir
+ */
+PHYSFS_DECL const char *PHYSFS_getBaseDir(void);
+
+
+/**
+ * \fn const char *PHYSFS_getUserDir(void)
+ * \brief Get the path where user's home directory resides.
+ *
+ * \deprecated As of PhysicsFS 2.1, you probably want PHYSFS_getPrefDir().
+ *
+ * Helper function.
+ *
+ * Get the "user dir". This is meant to be a suggestion of where a specific
+ * user of the system can store files. On Unix, this is her home directory.
+ * On systems with no concept of multiple home directories (MacOS, win95),
+ * this will default to something like "C:\mybasedir\users\username"
+ * where "username" will either be the login name, or "default" if the
+ * platform doesn't support multiple users, either.
+ *
+ * \return READ ONLY string of user dir in platform-dependent notation.
+ *
+ * \sa PHYSFS_getBaseDir
+ * \sa PHYSFS_getPrefDir
+ */
+PHYSFS_DECL const char *PHYSFS_getUserDir(void) PHYSFS_DEPRECATED;
+
+
+/**
+ * \fn const char *PHYSFS_getWriteDir(void)
+ * \brief Get path where PhysicsFS will allow file writing.
+ *
+ * Get the current write dir. The default write dir is NULL.
+ *
+ * \return READ ONLY string of write dir in platform-dependent notation,
+ * OR NULL IF NO WRITE PATH IS CURRENTLY SET.
+ *
+ * \sa PHYSFS_setWriteDir
+ */
+PHYSFS_DECL const char *PHYSFS_getWriteDir(void);
+
+
+/**
+ * \fn int PHYSFS_setWriteDir(const char *newDir)
+ * \brief Tell PhysicsFS where it may write files.
+ *
+ * Set a new write dir. This will override the previous setting.
+ *
+ * This call will fail (and fail to change the write dir) if the current
+ * write dir still has files open in it.
+ *
+ * \param newDir The new directory to be the root of the write dir,
+ * specified in platform-dependent notation. Setting to NULL
+ * disables the write dir, so no files can be opened for
+ * writing via PhysicsFS.
+ * \return non-zero on success, zero on failure. All attempts to open a file
+ * for writing via PhysicsFS will fail until this call succeeds.
+ * Specifics of the error can be gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_getWriteDir
+ */
+PHYSFS_DECL int PHYSFS_setWriteDir(const char *newDir);
+
+
+/**
+ * \fn int PHYSFS_addToSearchPath(const char *newDir, int appendToPath)
+ * \brief Add an archive or directory to the search path.
+ *
+ * \deprecated As of PhysicsFS 2.0, use PHYSFS_mount() instead. This
+ * function just wraps it anyhow.
+ *
+ * This function is equivalent to:
+ *
+ * \code
+ * PHYSFS_mount(newDir, NULL, appendToPath);
+ * \endcode
+ *
+ * You must use this and not PHYSFS_mount if binary compatibility with
+ * PhysicsFS 1.0 is important (which it may not be for many people).
+ *
+ * \sa PHYSFS_mount
+ * \sa PHYSFS_removeFromSearchPath
+ * \sa PHYSFS_getSearchPath
+ */
+PHYSFS_DECL int PHYSFS_addToSearchPath(const char *newDir, int appendToPath)
+ PHYSFS_DEPRECATED;
+
+/**
+ * \fn int PHYSFS_removeFromSearchPath(const char *oldDir)
+ * \brief Remove a directory or archive from the search path.
+ *
+ * \deprecated As of PhysicsFS 2.1, use PHYSFS_unmount() instead. This
+ * function just wraps it anyhow. There's no functional difference
+ * except the vocabulary changed from "adding to the search path"
+ * to "mounting" when that functionality was extended, and thus
+ * the preferred way to accomplish this function's work is now
+ * called "unmounting."
+ *
+ * This function is equivalent to:
+ *
+ * \code
+ * PHYSFS_unmount(oldDir);
+ * \endcode
+ *
+ * You must use this and not PHYSFS_unmount if binary compatibility with
+ * PhysicsFS 1.0 is important (which it may not be for many people).
+ *
+ * \sa PHYSFS_addToSearchPath
+ * \sa PHYSFS_getSearchPath
+ * \sa PHYSFS_unmount
+ */
+PHYSFS_DECL int PHYSFS_removeFromSearchPath(const char *oldDir)
+ PHYSFS_DEPRECATED;
+
+
+/**
+ * \fn char **PHYSFS_getSearchPath(void)
+ * \brief Get the current search path.
+ *
+ * The default search path is an empty list.
+ *
+ * The returned value is an array of strings, with a NULL entry to signify the
+ * end of the list:
+ *
+ * \code
+ * char **i;
+ *
+ * for (i = PHYSFS_getSearchPath(); *i != NULL; i++)
+ * printf("[%s] is in the search path.\n", *i);
+ * \endcode
+ *
+ * When you are done with the returned information, you may dispose of the
+ * resources by calling PHYSFS_freeList() with the returned pointer.
+ *
+ * \return Null-terminated array of null-terminated strings. NULL if there
+ * was a problem (read: OUT OF MEMORY).
+ *
+ * \sa PHYSFS_getSearchPathCallback
+ * \sa PHYSFS_addToSearchPath
+ * \sa PHYSFS_removeFromSearchPath
+ */
+PHYSFS_DECL char **PHYSFS_getSearchPath(void);
+
+
+/**
+ * \fn int PHYSFS_setSaneConfig(const char *organization, const char *appName, const char *archiveExt, int includeCdRoms, int archivesFirst)
+ * \brief Set up sane, default paths.
+ *
+ * Helper function.
+ *
+ * The write dir will be set to the pref dir returned by
+ * \code PHYSFS_getPrefDir(organization, appName) \endcode, which is
+ * created if it doesn't exist.
+ *
+ * The above is sufficient to make sure your program's configuration directory
+ * is separated from other clutter, and platform-independent.
+ *
+ * The search path will be:
+ *
+ * - The Write Dir (created if it doesn't exist)
+ * - The Base Dir (PHYSFS_getBaseDir())
+ * - All found CD-ROM dirs (optionally)
+ *
+ * These directories are then searched for files ending with the extension
+ * (archiveExt), which, if they are valid and supported archives, will also
+ * be added to the search path. If you specified "PKG" for (archiveExt), and
+ * there's a file named data.PKG in the base dir, it'll be checked. Archives
+ * can either be appended or prepended to the search path in alphabetical
+ * order, regardless of which directories they were found in. All archives
+ * are mounted in the root of the virtual file system ("/").
+ *
+ * All of this can be accomplished from the application, but this just does it
+ * all for you. Feel free to add more to the search path manually, too.
+ *
+ * \param organization Name of your company/group/etc to be used as a
+ * dirname, so keep it small, and no-frills.
+ *
+ * \param appName Program-specific name of your program, to separate it
+ * from other programs using PhysicsFS.
+ *
+ * \param archiveExt File extension used by your program to specify an
+ * archive. For example, Quake 3 uses "pk3", even though
+ * they are just zipfiles. Specify NULL to not dig out
+ * archives automatically. Do not specify the '.' char;
+ * If you want to look for ZIP files, specify "ZIP" and
+ * not ".ZIP" ... the archive search is case-insensitive.
+ *
+ * \param includeCdRoms Non-zero to include CD-ROMs in the search path, and
+ * (if (archiveExt) != NULL) search them for archives.
+ * This may cause a significant amount of blocking
+ * while discs are accessed, and if there are no discs
+ * in the drive (or even not mounted on Unix systems),
+ * then they may not be made available anyhow. You may
+ * want to specify zero and handle the disc setup
+ * yourself.
+ *
+ * \param archivesFirst Non-zero to prepend the archives to the search path.
+ * Zero to append them. Ignored if !(archiveExt).
+ *
+ * \return nonzero on success, zero on error. Specifics of the error can be
+ * gleaned from PHYSFS_getLastError().
+ */
+PHYSFS_DECL int PHYSFS_setSaneConfig(const char *organization,
+ const char *appName,
+ const char *archiveExt,
+ int includeCdRoms,
+ int archivesFirst);
+
+
+/* Directory management stuff ... */
+
+/**
+ * \fn int PHYSFS_mkdir(const char *dirName)
+ * \brief Create a directory.
+ *
+ * This is specified in platform-independent notation in relation to the
+ * write dir. All missing parent directories are also created if they
+ * don't exist.
+ *
+ * So if you've got the write dir set to "C:\mygame\writedir" and call
+ * PHYSFS_mkdir("downloads/maps") then the directories
+ * "C:\mygame\writedir\downloads" and "C:\mygame\writedir\downloads\maps"
+ * will be created if possible. If the creation of "maps" fails after we
+ * have successfully created "downloads", then the function leaves the
+ * created directory behind and reports failure.
+ *
+ * \param dirName New dir to create.
+ * \return nonzero on success, zero on error. Specifics of the error can be
+ * gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_delete
+ */
+PHYSFS_DECL int PHYSFS_mkdir(const char *dirName);
+
+
+/**
+ * \fn int PHYSFS_delete(const char *filename)
+ * \brief Delete a file or directory.
+ *
+ * (filename) is specified in platform-independent notation in relation to the
+ * write dir.
+ *
+ * A directory must be empty before this call can delete it.
+ *
+ * Deleting a symlink will remove the link, not what it points to, regardless
+ * of whether you "permitSymLinks" or not.
+ *
+ * So if you've got the write dir set to "C:\mygame\writedir" and call
+ * PHYSFS_delete("downloads/maps/level1.map") then the file
+ * "C:\mygame\writedir\downloads\maps\level1.map" is removed from the
+ * physical filesystem, if it exists and the operating system permits the
+ * deletion.
+ *
+ * Note that on Unix systems, deleting a file may be successful, but the
+ * actual file won't be removed until all processes that have an open
+ * filehandle to it (including your program) close their handles.
+ *
+ * Chances are, the bits that make up the file still exist, they are just
+ * made available to be written over at a later point. Don't consider this
+ * a security method or anything. :)
+ *
+ * \param filename Filename to delete.
+ * \return nonzero on success, zero on error. Specifics of the error can be
+ * gleaned from PHYSFS_getLastError().
+ */
+PHYSFS_DECL int PHYSFS_delete(const char *filename);
+
+
+/**
+ * \fn const char *PHYSFS_getRealDir(const char *filename)
+ * \brief Figure out where in the search path a file resides.
+ *
+ * The file is specified in platform-independent notation. The returned
+ * filename will be the element of the search path where the file was found,
+ * which may be a directory, or an archive. Even if there are multiple
+ * matches in different parts of the search path, only the first one found
+ * is used, just like when opening a file.
+ *
+ * So, if you look for "maps/level1.map", and C:\\mygame is in your search
+ * path and C:\\mygame\\maps\\level1.map exists, then "C:\mygame" is returned.
+ *
+ * If a any part of a match is a symbolic link, and you've not explicitly
+ * permitted symlinks, then it will be ignored, and the search for a match
+ * will continue.
+ *
+ * If you specify a fake directory that only exists as a mount point, it'll
+ * be associated with the first archive mounted there, even though that
+ * directory isn't necessarily contained in a real archive.
+ *
+ * \warning This will return NULL if there is no real directory associated
+ * with (filename). Specifically, PHYSFS_mountIo(),
+ * PHYSFS_mountMemory(), and PHYSFS_mountHandle() will return NULL
+ * even if the filename is found in the search path. Plan accordingly.
+ *
+ * \param filename file to look for.
+ * \return READ ONLY string of element of search path containing the
+ * the file in question. NULL if not found.
+ */
+PHYSFS_DECL const char *PHYSFS_getRealDir(const char *filename);
+
+
+/**
+ * \fn char **PHYSFS_enumerateFiles(const char *dir)
+ * \brief Get a file listing of a search path's directory.
+ *
+ * Matching directories are interpolated. That is, if "C:\mydir" is in the
+ * search path and contains a directory "savegames" that contains "x.sav",
+ * "y.sav", and "z.sav", and there is also a "C:\userdir" in the search path
+ * that has a "savegames" subdirectory with "w.sav", then the following code:
+ *
+ * \code
+ * char **rc = PHYSFS_enumerateFiles("savegames");
+ * char **i;
+ *
+ * for (i = rc; *i != NULL; i++)
+ * printf(" * We've got [%s].\n", *i);
+ *
+ * PHYSFS_freeList(rc);
+ * \endcode
+ *
+ * \...will print:
+ *
+ * \verbatim
+ * We've got [x.sav].
+ * We've got [y.sav].
+ * We've got [z.sav].
+ * We've got [w.sav].\endverbatim
+ *
+ * Feel free to sort the list however you like. We only promise there will
+ * be no duplicates, but not what order the final list will come back in.
+ *
+ * Don't forget to call PHYSFS_freeList() with the return value from this
+ * function when you are done with it.
+ *
+ * \param dir directory in platform-independent notation to enumerate.
+ * \return Null-terminated array of null-terminated strings.
+ *
+ * \sa PHYSFS_enumerateFilesCallback
+ */
+PHYSFS_DECL char **PHYSFS_enumerateFiles(const char *dir);
+
+
+/**
+ * \fn int PHYSFS_exists(const char *fname)
+ * \brief Determine if a file exists in the search path.
+ *
+ * Reports true if there is an entry anywhere in the search path by the
+ * name of (fname).
+ *
+ * Note that entries that are symlinks are ignored if
+ * PHYSFS_permitSymbolicLinks(1) hasn't been called, so you
+ * might end up further down in the search path than expected.
+ *
+ * \param fname filename in platform-independent notation.
+ * \return non-zero if filename exists. zero otherwise.
+ */
+PHYSFS_DECL int PHYSFS_exists(const char *fname);
+
+
+/**
+ * \fn int PHYSFS_isDirectory(const char *fname)
+ * \brief Determine if a file in the search path is really a directory.
+ *
+ * \deprecated As of PhysicsFS 2.1, use PHYSFS_stat() instead. This
+ * function just wraps it anyhow.
+ *
+ * Determine if the first occurence of (fname) in the search path is
+ * really a directory entry.
+ *
+ * Note that entries that are symlinks are ignored if
+ * PHYSFS_permitSymbolicLinks(1) hasn't been called, so you
+ * might end up further down in the search path than expected.
+ *
+ * \param fname filename in platform-independent notation.
+ * \return non-zero if filename exists and is a directory. zero otherwise.
+ *
+ * \sa PHYSFS_stat
+ * \sa PHYSFS_exists
+ */
+PHYSFS_DECL int PHYSFS_isDirectory(const char *fname) PHYSFS_DEPRECATED;
+
+
+/**
+ * \fn int PHYSFS_isSymbolicLink(const char *fname)
+ * \brief Determine if a file in the search path is really a symbolic link.
+ *
+ * \deprecated As of PhysicsFS 2.1, use PHYSFS_stat() instead. This
+ * function just wraps it anyhow.
+ *
+ * Determine if the first occurence of (fname) in the search path is
+ * really a symbolic link.
+ *
+ * Note that entries that are symlinks are ignored if
+ * PHYSFS_permitSymbolicLinks(1) hasn't been called, and as such,
+ * this function will always return 0 in that case.
+ *
+ * \param fname filename in platform-independent notation.
+ * \return non-zero if filename exists and is a symlink. zero otherwise.
+ *
+ * \sa PHYSFS_stat
+ * \sa PHYSFS_exists
+ */
+PHYSFS_DECL int PHYSFS_isSymbolicLink(const char *fname) PHYSFS_DEPRECATED;
+
+
+/**
+ * \fn PHYSFS_sint64 PHYSFS_getLastModTime(const char *filename)
+ * \brief Get the last modification time of a file.
+ *
+ * \deprecated As of PhysicsFS 2.1, use PHYSFS_stat() instead. This
+ * function just wraps it anyhow.
+ *
+ * The modtime is returned as a number of seconds since the Unix epoch
+ * (midnight, Jan 1, 1970). The exact derivation and accuracy of this time
+ * depends on the particular archiver. If there is no reasonable way to
+ * obtain this information for a particular archiver, or there was some sort
+ * of error, this function returns (-1).
+ *
+ * You must use this and not PHYSFS_stat() if binary compatibility with
+ * PhysicsFS 2.0 is important (which it may not be for many people).
+ *
+ * \param filename filename to check, in platform-independent notation.
+ * \return last modified time of the file. -1 if it can't be determined.
+ *
+ * \sa PHYSFS_stat
+ */
+PHYSFS_DECL PHYSFS_sint64 PHYSFS_getLastModTime(const char *filename)
+ PHYSFS_DEPRECATED;
+
+
+/* i/o stuff... */
+
+/**
+ * \fn PHYSFS_File *PHYSFS_openWrite(const char *filename)
+ * \brief Open a file for writing.
+ *
+ * Open a file for writing, in platform-independent notation and in relation
+ * to the write dir as the root of the writable filesystem. The specified
+ * file is created if it doesn't exist. If it does exist, it is truncated to
+ * zero bytes, and the writing offset is set to the start.
+ *
+ * Note that entries that are symlinks are ignored if
+ * PHYSFS_permitSymbolicLinks(1) hasn't been called, and opening a
+ * symlink with this function will fail in such a case.
+ *
+ * \param filename File to open.
+ * \return A valid PhysicsFS filehandle on success, NULL on error. Specifics
+ * of the error can be gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_openRead
+ * \sa PHYSFS_openAppend
+ * \sa PHYSFS_write
+ * \sa PHYSFS_close
+ */
+PHYSFS_DECL PHYSFS_File *PHYSFS_openWrite(const char *filename);
+
+
+/**
+ * \fn PHYSFS_File *PHYSFS_openAppend(const char *filename)
+ * \brief Open a file for appending.
+ *
+ * Open a file for writing, in platform-independent notation and in relation
+ * to the write dir as the root of the writable filesystem. The specified
+ * file is created if it doesn't exist. If it does exist, the writing offset
+ * is set to the end of the file, so the first write will be the byte after
+ * the end.
+ *
+ * Note that entries that are symlinks are ignored if
+ * PHYSFS_permitSymbolicLinks(1) hasn't been called, and opening a
+ * symlink with this function will fail in such a case.
+ *
+ * \param filename File to open.
+ * \return A valid PhysicsFS filehandle on success, NULL on error. Specifics
+ * of the error can be gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_openRead
+ * \sa PHYSFS_openWrite
+ * \sa PHYSFS_write
+ * \sa PHYSFS_close
+ */
+PHYSFS_DECL PHYSFS_File *PHYSFS_openAppend(const char *filename);
+
+
+/**
+ * \fn PHYSFS_File *PHYSFS_openRead(const char *filename)
+ * \brief Open a file for reading.
+ *
+ * Open a file for reading, in platform-independent notation. The search path
+ * is checked one at a time until a matching file is found, in which case an
+ * abstract filehandle is associated with it, and reading may be done.
+ * The reading offset is set to the first byte of the file.
+ *
+ * Note that entries that are symlinks are ignored if
+ * PHYSFS_permitSymbolicLinks(1) hasn't been called, and opening a
+ * symlink with this function will fail in such a case.
+ *
+ * \param filename File to open.
+ * \return A valid PhysicsFS filehandle on success, NULL on error. Specifics
+ * of the error can be gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_openWrite
+ * \sa PHYSFS_openAppend
+ * \sa PHYSFS_read
+ * \sa PHYSFS_close
+ */
+PHYSFS_DECL PHYSFS_File *PHYSFS_openRead(const char *filename);
+
+
+/**
+ * \fn int PHYSFS_close(PHYSFS_File *handle)
+ * \brief Close a PhysicsFS filehandle.
+ *
+ * This call is capable of failing if the operating system was buffering
+ * writes to the physical media, and, now forced to write those changes to
+ * physical media, can not store the data for some reason. In such a case,
+ * the filehandle stays open. A well-written program should ALWAYS check the
+ * return value from the close call in addition to every writing call!
+ *
+ * \param handle handle returned from PHYSFS_open*().
+ * \return nonzero on success, zero on error. Specifics of the error can be
+ * gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_openRead
+ * \sa PHYSFS_openWrite
+ * \sa PHYSFS_openAppend
+ */
+PHYSFS_DECL int PHYSFS_close(PHYSFS_File *handle);
+
+
+/**
+ * \fn PHYSFS_sint64 PHYSFS_read(PHYSFS_File *handle, void *buffer, PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+ * \brief Read data from a PhysicsFS filehandle
+ *
+ * The file must be opened for reading.
+ *
+ * \deprecated As of PhysicsFS 2.1, use PHYSFS_readBytes() instead. This
+ * function just wraps it anyhow. This function never clarified
+ * what would happen if you managed to read a partial object, so
+ * working at the byte level makes this cleaner for everyone,
+ * especially now that PHYSFS_Io interfaces can be supplied by the
+ * application.
+ *
+ * \param handle handle returned from PHYSFS_openRead().
+ * \param buffer buffer to store read data into.
+ * \param objSize size in bytes of objects being read from (handle).
+ * \param objCount number of (objSize) objects to read from (handle).
+ * \return number of objects read. PHYSFS_getLastError() can shed light on
+ * the reason this might be < (objCount), as can PHYSFS_eof().
+ * -1 if complete failure.
+ *
+ * \sa PHYSFS_readBytes
+ * \sa PHYSFS_eof
+ */
+PHYSFS_DECL PHYSFS_sint64 PHYSFS_read(PHYSFS_File *handle,
+ void *buffer,
+ PHYSFS_uint32 objSize,
+ PHYSFS_uint32 objCount)
+ PHYSFS_DEPRECATED;
+
+/**
+ * \fn PHYSFS_sint64 PHYSFS_write(PHYSFS_File *handle, const void *buffer, PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+ * \brief Write data to a PhysicsFS filehandle
+ *
+ * The file must be opened for writing.
+ *
+ * \deprecated As of PhysicsFS 2.1, use PHYSFS_writeBytes() instead. This
+ * function just wraps it anyhow. This function never clarified
+ * what would happen if you managed to write a partial object, so
+ * working at the byte level makes this cleaner for everyone,
+ * especially now that PHYSFS_Io interfaces can be supplied by the
+ * application.
+ *
+ * \param handle retval from PHYSFS_openWrite() or PHYSFS_openAppend().
+ * \param buffer buffer of bytes to write to (handle).
+ * \param objSize size in bytes of objects being written to (handle).
+ * \param objCount number of (objSize) objects to write to (handle).
+ * \return number of objects written. PHYSFS_getLastError() can shed light on
+ * the reason this might be < (objCount). -1 if complete failure.
+ *
+ * \sa PHYSFS_writeBytes
+ */
+PHYSFS_DECL PHYSFS_sint64 PHYSFS_write(PHYSFS_File *handle,
+ const void *buffer,
+ PHYSFS_uint32 objSize,
+ PHYSFS_uint32 objCount)
+ PHYSFS_DEPRECATED;
+
+
+/* File position stuff... */
+
+/**
+ * \fn int PHYSFS_eof(PHYSFS_File *handle)
+ * \brief Check for end-of-file state on a PhysicsFS filehandle.
+ *
+ * Determine if the end of file has been reached in a PhysicsFS filehandle.
+ *
+ * \param handle handle returned from PHYSFS_openRead().
+ * \return nonzero if EOF, zero if not.
+ *
+ * \sa PHYSFS_read
+ * \sa PHYSFS_tell
+ */
+PHYSFS_DECL int PHYSFS_eof(PHYSFS_File *handle);
+
+
+/**
+ * \fn PHYSFS_sint64 PHYSFS_tell(PHYSFS_File *handle)
+ * \brief Determine current position within a PhysicsFS filehandle.
+ *
+ * \param handle handle returned from PHYSFS_open*().
+ * \return offset in bytes from start of file. -1 if error occurred.
+ * Specifics of the error can be gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_seek
+ */
+PHYSFS_DECL PHYSFS_sint64 PHYSFS_tell(PHYSFS_File *handle);
+
+
+/**
+ * \fn int PHYSFS_seek(PHYSFS_File *handle, PHYSFS_uint64 pos)
+ * \brief Seek to a new position within a PhysicsFS filehandle.
+ *
+ * The next read or write will occur at that place. Seeking past the
+ * beginning or end of the file is not allowed, and causes an error.
+ *
+ * \param handle handle returned from PHYSFS_open*().
+ * \param pos number of bytes from start of file to seek to.
+ * \return nonzero on success, zero on error. Specifics of the error can be
+ * gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_tell
+ */
+PHYSFS_DECL int PHYSFS_seek(PHYSFS_File *handle, PHYSFS_uint64 pos);
+
+
+/**
+ * \fn PHYSFS_sint64 PHYSFS_fileLength(PHYSFS_File *handle)
+ * \brief Get total length of a file in bytes.
+ *
+ * Note that if another process/thread is writing to this file at the same
+ * time, then the information this function supplies could be incorrect
+ * before you get it. Use with caution, or better yet, don't use at all.
+ *
+ * \param handle handle returned from PHYSFS_open*().
+ * \return size in bytes of the file. -1 if can't be determined.
+ *
+ * \sa PHYSFS_tell
+ * \sa PHYSFS_seek
+ */
+PHYSFS_DECL PHYSFS_sint64 PHYSFS_fileLength(PHYSFS_File *handle);
+
+
+/* Buffering stuff... */
+
+/**
+ * \fn int PHYSFS_setBuffer(PHYSFS_File *handle, PHYSFS_uint64 bufsize)
+ * \brief Set up buffering for a PhysicsFS file handle.
+ *
+ * Define an i/o buffer for a file handle. A memory block of (bufsize) bytes
+ * will be allocated and associated with (handle).
+ *
+ * For files opened for reading, up to (bufsize) bytes are read from (handle)
+ * and stored in the internal buffer. Calls to PHYSFS_read() will pull
+ * from this buffer until it is empty, and then refill it for more reading.
+ * Note that compressed files, like ZIP archives, will decompress while
+ * buffering, so this can be handy for offsetting CPU-intensive operations.
+ * The buffer isn't filled until you do your next read.
+ *
+ * For files opened for writing, data will be buffered to memory until the
+ * buffer is full or the buffer is flushed. Closing a handle implicitly
+ * causes a flush...check your return values!
+ *
+ * Seeking, etc transparently accounts for buffering.
+ *
+ * You can resize an existing buffer by calling this function more than once
+ * on the same file. Setting the buffer size to zero will free an existing
+ * buffer.
+ *
+ * PhysicsFS file handles are unbuffered by default.
+ *
+ * Please check the return value of this function! Failures can include
+ * not being able to seek backwards in a read-only file when removing the
+ * buffer, not being able to allocate the buffer, and not being able to
+ * flush the buffer to disk, among other unexpected problems.
+ *
+ * \param handle handle returned from PHYSFS_open*().
+ * \param bufsize size, in bytes, of buffer to allocate.
+ * \return nonzero if successful, zero on error.
+ *
+ * \sa PHYSFS_flush
+ * \sa PHYSFS_read
+ * \sa PHYSFS_write
+ * \sa PHYSFS_close
+ */
+PHYSFS_DECL int PHYSFS_setBuffer(PHYSFS_File *handle, PHYSFS_uint64 bufsize);
+
+
+/**
+ * \fn int PHYSFS_flush(PHYSFS_File *handle)
+ * \brief Flush a buffered PhysicsFS file handle.
+ *
+ * For buffered files opened for writing, this will put the current contents
+ * of the buffer to disk and flag the buffer as empty if possible.
+ *
+ * For buffered files opened for reading or unbuffered files, this is a safe
+ * no-op, and will report success.
+ *
+ * \param handle handle returned from PHYSFS_open*().
+ * \return nonzero if successful, zero on error.
+ *
+ * \sa PHYSFS_setBuffer
+ * \sa PHYSFS_close
+ */
+PHYSFS_DECL int PHYSFS_flush(PHYSFS_File *handle);
+
+
+/* Byteorder stuff... */
+
+#ifndef SWIG /* not available from scripting languages. */
+
+/**
+ * \fn PHYSFS_sint16 PHYSFS_swapSLE16(PHYSFS_sint16 val)
+ * \brief Swap littleendian signed 16 to platform's native byte order.
+ *
+ * Take a 16-bit signed value in littleendian format and convert it to
+ * the platform's native byte order.
+ *
+ * \param val value to convert
+ * \return converted value.
+ */
+PHYSFS_DECL PHYSFS_sint16 PHYSFS_swapSLE16(PHYSFS_sint16 val);
+
+
+/**
+ * \fn PHYSFS_uint16 PHYSFS_swapULE16(PHYSFS_uint16 val)
+ * \brief Swap littleendian unsigned 16 to platform's native byte order.
+ *
+ * Take a 16-bit unsigned value in littleendian format and convert it to
+ * the platform's native byte order.
+ *
+ * \param val value to convert
+ * \return converted value.
+ */
+PHYSFS_DECL PHYSFS_uint16 PHYSFS_swapULE16(PHYSFS_uint16 val);
+
+/**
+ * \fn PHYSFS_sint32 PHYSFS_swapSLE32(PHYSFS_sint32 val)
+ * \brief Swap littleendian signed 32 to platform's native byte order.
+ *
+ * Take a 32-bit signed value in littleendian format and convert it to
+ * the platform's native byte order.
+ *
+ * \param val value to convert
+ * \return converted value.
+ */
+PHYSFS_DECL PHYSFS_sint32 PHYSFS_swapSLE32(PHYSFS_sint32 val);
+
+
+/**
+ * \fn PHYSFS_uint32 PHYSFS_swapULE32(PHYSFS_uint32 val)
+ * \brief Swap littleendian unsigned 32 to platform's native byte order.
+ *
+ * Take a 32-bit unsigned value in littleendian format and convert it to
+ * the platform's native byte order.
+ *
+ * \param val value to convert
+ * \return converted value.
+ */
+PHYSFS_DECL PHYSFS_uint32 PHYSFS_swapULE32(PHYSFS_uint32 val);
+
+/**
+ * \fn PHYSFS_sint64 PHYSFS_swapSLE64(PHYSFS_sint64 val)
+ * \brief Swap littleendian signed 64 to platform's native byte order.
+ *
+ * Take a 64-bit signed value in littleendian format and convert it to
+ * the platform's native byte order.
+ *
+ * \param val value to convert
+ * \return converted value.
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ * any sort of 64-bit support.
+ */
+PHYSFS_DECL PHYSFS_sint64 PHYSFS_swapSLE64(PHYSFS_sint64 val);
+
+
+/**
+ * \fn PHYSFS_uint64 PHYSFS_swapULE64(PHYSFS_uint64 val)
+ * \brief Swap littleendian unsigned 64 to platform's native byte order.
+ *
+ * Take a 64-bit unsigned value in littleendian format and convert it to
+ * the platform's native byte order.
+ *
+ * \param val value to convert
+ * \return converted value.
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ * any sort of 64-bit support.
+ */
+PHYSFS_DECL PHYSFS_uint64 PHYSFS_swapULE64(PHYSFS_uint64 val);
+
+
+/**
+ * \fn PHYSFS_sint16 PHYSFS_swapSBE16(PHYSFS_sint16 val)
+ * \brief Swap bigendian signed 16 to platform's native byte order.
+ *
+ * Take a 16-bit signed value in bigendian format and convert it to
+ * the platform's native byte order.
+ *
+ * \param val value to convert
+ * \return converted value.
+ */
+PHYSFS_DECL PHYSFS_sint16 PHYSFS_swapSBE16(PHYSFS_sint16 val);
+
+
+/**
+ * \fn PHYSFS_uint16 PHYSFS_swapUBE16(PHYSFS_uint16 val)
+ * \brief Swap bigendian unsigned 16 to platform's native byte order.
+ *
+ * Take a 16-bit unsigned value in bigendian format and convert it to
+ * the platform's native byte order.
+ *
+ * \param val value to convert
+ * \return converted value.
+ */
+PHYSFS_DECL PHYSFS_uint16 PHYSFS_swapUBE16(PHYSFS_uint16 val);
+
+/**
+ * \fn PHYSFS_sint32 PHYSFS_swapSBE32(PHYSFS_sint32 val)
+ * \brief Swap bigendian signed 32 to platform's native byte order.
+ *
+ * Take a 32-bit signed value in bigendian format and convert it to
+ * the platform's native byte order.
+ *
+ * \param val value to convert
+ * \return converted value.
+ */
+PHYSFS_DECL PHYSFS_sint32 PHYSFS_swapSBE32(PHYSFS_sint32 val);
+
+
+/**
+ * \fn PHYSFS_uint32 PHYSFS_swapUBE32(PHYSFS_uint32 val)
+ * \brief Swap bigendian unsigned 32 to platform's native byte order.
+ *
+ * Take a 32-bit unsigned value in bigendian format and convert it to
+ * the platform's native byte order.
+ *
+ * \param val value to convert
+ * \return converted value.
+ */
+PHYSFS_DECL PHYSFS_uint32 PHYSFS_swapUBE32(PHYSFS_uint32 val);
+
+
+/**
+ * \fn PHYSFS_sint64 PHYSFS_swapSBE64(PHYSFS_sint64 val)
+ * \brief Swap bigendian signed 64 to platform's native byte order.
+ *
+ * Take a 64-bit signed value in bigendian format and convert it to
+ * the platform's native byte order.
+ *
+ * \param val value to convert
+ * \return converted value.
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ * any sort of 64-bit support.
+ */
+PHYSFS_DECL PHYSFS_sint64 PHYSFS_swapSBE64(PHYSFS_sint64 val);
+
+
+/**
+ * \fn PHYSFS_uint64 PHYSFS_swapUBE64(PHYSFS_uint64 val)
+ * \brief Swap bigendian unsigned 64 to platform's native byte order.
+ *
+ * Take a 64-bit unsigned value in bigendian format and convert it to
+ * the platform's native byte order.
+ *
+ * \param val value to convert
+ * \return converted value.
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ * any sort of 64-bit support.
+ */
+PHYSFS_DECL PHYSFS_uint64 PHYSFS_swapUBE64(PHYSFS_uint64 val);
+
+#endif /* SWIG */
+
+
+/**
+ * \fn int PHYSFS_readSLE16(PHYSFS_File *file, PHYSFS_sint16 *val)
+ * \brief Read and convert a signed 16-bit littleendian value.
+ *
+ * Convenience function. Read a signed 16-bit littleendian value from a
+ * file and convert it to the platform's native byte order.
+ *
+ * \param file PhysicsFS file handle from which to read.
+ * \param val pointer to where value should be stored.
+ * \return zero on failure, non-zero on success. If successful, (*val) will
+ * store the result. On failure, you can find out what went wrong
+ * from PHYSFS_getLastError().
+ */
+PHYSFS_DECL int PHYSFS_readSLE16(PHYSFS_File *file, PHYSFS_sint16 *val);
+
+
+/**
+ * \fn int PHYSFS_readULE16(PHYSFS_File *file, PHYSFS_uint16 *val)
+ * \brief Read and convert an unsigned 16-bit littleendian value.
+ *
+ * Convenience function. Read an unsigned 16-bit littleendian value from a
+ * file and convert it to the platform's native byte order.
+ *
+ * \param file PhysicsFS file handle from which to read.
+ * \param val pointer to where value should be stored.
+ * \return zero on failure, non-zero on success. If successful, (*val) will
+ * store the result. On failure, you can find out what went wrong
+ * from PHYSFS_getLastError().
+ *
+ */
+PHYSFS_DECL int PHYSFS_readULE16(PHYSFS_File *file, PHYSFS_uint16 *val);
+
+
+/**
+ * \fn int PHYSFS_readSBE16(PHYSFS_File *file, PHYSFS_sint16 *val)
+ * \brief Read and convert a signed 16-bit bigendian value.
+ *
+ * Convenience function. Read a signed 16-bit bigendian value from a
+ * file and convert it to the platform's native byte order.
+ *
+ * \param file PhysicsFS file handle from which to read.
+ * \param val pointer to where value should be stored.
+ * \return zero on failure, non-zero on success. If successful, (*val) will
+ * store the result. On failure, you can find out what went wrong
+ * from PHYSFS_getLastError().
+ */
+PHYSFS_DECL int PHYSFS_readSBE16(PHYSFS_File *file, PHYSFS_sint16 *val);
+
+
+/**
+ * \fn int PHYSFS_readUBE16(PHYSFS_File *file, PHYSFS_uint16 *val)
+ * \brief Read and convert an unsigned 16-bit bigendian value.
+ *
+ * Convenience function. Read an unsigned 16-bit bigendian value from a
+ * file and convert it to the platform's native byte order.
+ *
+ * \param file PhysicsFS file handle from which to read.
+ * \param val pointer to where value should be stored.
+ * \return zero on failure, non-zero on success. If successful, (*val) will
+ * store the result. On failure, you can find out what went wrong
+ * from PHYSFS_getLastError().
+ *
+ */
+PHYSFS_DECL int PHYSFS_readUBE16(PHYSFS_File *file, PHYSFS_uint16 *val);
+
+
+/**
+ * \fn int PHYSFS_readSLE32(PHYSFS_File *file, PHYSFS_sint32 *val)
+ * \brief Read and convert a signed 32-bit littleendian value.
+ *
+ * Convenience function. Read a signed 32-bit littleendian value from a
+ * file and convert it to the platform's native byte order.
+ *
+ * \param file PhysicsFS file handle from which to read.
+ * \param val pointer to where value should be stored.
+ * \return zero on failure, non-zero on success. If successful, (*val) will
+ * store the result. On failure, you can find out what went wrong
+ * from PHYSFS_getLastError().
+ */
+PHYSFS_DECL int PHYSFS_readSLE32(PHYSFS_File *file, PHYSFS_sint32 *val);
+
+
+/**
+ * \fn int PHYSFS_readULE32(PHYSFS_File *file, PHYSFS_uint32 *val)
+ * \brief Read and convert an unsigned 32-bit littleendian value.
+ *
+ * Convenience function. Read an unsigned 32-bit littleendian value from a
+ * file and convert it to the platform's native byte order.
+ *
+ * \param file PhysicsFS file handle from which to read.
+ * \param val pointer to where value should be stored.
+ * \return zero on failure, non-zero on success. If successful, (*val) will
+ * store the result. On failure, you can find out what went wrong
+ * from PHYSFS_getLastError().
+ *
+ */
+PHYSFS_DECL int PHYSFS_readULE32(PHYSFS_File *file, PHYSFS_uint32 *val);
+
+
+/**
+ * \fn int PHYSFS_readSBE32(PHYSFS_File *file, PHYSFS_sint32 *val)
+ * \brief Read and convert a signed 32-bit bigendian value.
+ *
+ * Convenience function. Read a signed 32-bit bigendian value from a
+ * file and convert it to the platform's native byte order.
+ *
+ * \param file PhysicsFS file handle from which to read.
+ * \param val pointer to where value should be stored.
+ * \return zero on failure, non-zero on success. If successful, (*val) will
+ * store the result. On failure, you can find out what went wrong
+ * from PHYSFS_getLastError().
+ */
+PHYSFS_DECL int PHYSFS_readSBE32(PHYSFS_File *file, PHYSFS_sint32 *val);
+
+
+/**
+ * \fn int PHYSFS_readUBE32(PHYSFS_File *file, PHYSFS_uint32 *val)
+ * \brief Read and convert an unsigned 32-bit bigendian value.
+ *
+ * Convenience function. Read an unsigned 32-bit bigendian value from a
+ * file and convert it to the platform's native byte order.
+ *
+ * \param file PhysicsFS file handle from which to read.
+ * \param val pointer to where value should be stored.
+ * \return zero on failure, non-zero on success. If successful, (*val) will
+ * store the result. On failure, you can find out what went wrong
+ * from PHYSFS_getLastError().
+ *
+ */
+PHYSFS_DECL int PHYSFS_readUBE32(PHYSFS_File *file, PHYSFS_uint32 *val);
+
+
+/**
+ * \fn int PHYSFS_readSLE64(PHYSFS_File *file, PHYSFS_sint64 *val)
+ * \brief Read and convert a signed 64-bit littleendian value.
+ *
+ * Convenience function. Read a signed 64-bit littleendian value from a
+ * file and convert it to the platform's native byte order.
+ *
+ * \param file PhysicsFS file handle from which to read.
+ * \param val pointer to where value should be stored.
+ * \return zero on failure, non-zero on success. If successful, (*val) will
+ * store the result. On failure, you can find out what went wrong
+ * from PHYSFS_getLastError().
+ *
+ * \warning Remember, PHYSFS_sint64 is only 32 bits on platforms without
+ * any sort of 64-bit support.
+ */
+PHYSFS_DECL int PHYSFS_readSLE64(PHYSFS_File *file, PHYSFS_sint64 *val);
+
+
+/**
+ * \fn int PHYSFS_readULE64(PHYSFS_File *file, PHYSFS_uint64 *val)
+ * \brief Read and convert an unsigned 64-bit littleendian value.
+ *
+ * Convenience function. Read an unsigned 64-bit littleendian value from a
+ * file and convert it to the platform's native byte order.
+ *
+ * \param file PhysicsFS file handle from which to read.
+ * \param val pointer to where value should be stored.
+ * \return zero on failure, non-zero on success. If successful, (*val) will
+ * store the result. On failure, you can find out what went wrong
+ * from PHYSFS_getLastError().
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ * any sort of 64-bit support.
+ */
+PHYSFS_DECL int PHYSFS_readULE64(PHYSFS_File *file, PHYSFS_uint64 *val);
+
+
+/**
+ * \fn int PHYSFS_readSBE64(PHYSFS_File *file, PHYSFS_sint64 *val)
+ * \brief Read and convert a signed 64-bit bigendian value.
+ *
+ * Convenience function. Read a signed 64-bit bigendian value from a
+ * file and convert it to the platform's native byte order.
+ *
+ * \param file PhysicsFS file handle from which to read.
+ * \param val pointer to where value should be stored.
+ * \return zero on failure, non-zero on success. If successful, (*val) will
+ * store the result. On failure, you can find out what went wrong
+ * from PHYSFS_getLastError().
+ *
+ * \warning Remember, PHYSFS_sint64 is only 32 bits on platforms without
+ * any sort of 64-bit support.
+ */
+PHYSFS_DECL int PHYSFS_readSBE64(PHYSFS_File *file, PHYSFS_sint64 *val);
+
+
+/**
+ * \fn int PHYSFS_readUBE64(PHYSFS_File *file, PHYSFS_uint64 *val)
+ * \brief Read and convert an unsigned 64-bit bigendian value.
+ *
+ * Convenience function. Read an unsigned 64-bit bigendian value from a
+ * file and convert it to the platform's native byte order.
+ *
+ * \param file PhysicsFS file handle from which to read.
+ * \param val pointer to where value should be stored.
+ * \return zero on failure, non-zero on success. If successful, (*val) will
+ * store the result. On failure, you can find out what went wrong
+ * from PHYSFS_getLastError().
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ * any sort of 64-bit support.
+ */
+PHYSFS_DECL int PHYSFS_readUBE64(PHYSFS_File *file, PHYSFS_uint64 *val);
+
+
+/**
+ * \fn int PHYSFS_writeSLE16(PHYSFS_File *file, PHYSFS_sint16 val)
+ * \brief Convert and write a signed 16-bit littleendian value.
+ *
+ * Convenience function. Convert a signed 16-bit value from the platform's
+ * native byte order to littleendian and write it to a file.
+ *
+ * \param file PhysicsFS file handle to which to write.
+ * \param val Value to convert and write.
+ * \return zero on failure, non-zero on success. On failure, you can
+ * find out what went wrong from PHYSFS_getLastError().
+ */
+PHYSFS_DECL int PHYSFS_writeSLE16(PHYSFS_File *file, PHYSFS_sint16 val);
+
+
+/**
+ * \fn int PHYSFS_writeULE16(PHYSFS_File *file, PHYSFS_uint16 val)
+ * \brief Convert and write an unsigned 16-bit littleendian value.
+ *
+ * Convenience function. Convert an unsigned 16-bit value from the platform's
+ * native byte order to littleendian and write it to a file.
+ *
+ * \param file PhysicsFS file handle to which to write.
+ * \param val Value to convert and write.
+ * \return zero on failure, non-zero on success. On failure, you can
+ * find out what went wrong from PHYSFS_getLastError().
+ */
+PHYSFS_DECL int PHYSFS_writeULE16(PHYSFS_File *file, PHYSFS_uint16 val);
+
+
+/**
+ * \fn int PHYSFS_writeSBE16(PHYSFS_File *file, PHYSFS_sint16 val)
+ * \brief Convert and write a signed 16-bit bigendian value.
+ *
+ * Convenience function. Convert a signed 16-bit value from the platform's
+ * native byte order to bigendian and write it to a file.
+ *
+ * \param file PhysicsFS file handle to which to write.
+ * \param val Value to convert and write.
+ * \return zero on failure, non-zero on success. On failure, you can
+ * find out what went wrong from PHYSFS_getLastError().
+ */
+PHYSFS_DECL int PHYSFS_writeSBE16(PHYSFS_File *file, PHYSFS_sint16 val);
+
+
+/**
+ * \fn int PHYSFS_writeUBE16(PHYSFS_File *file, PHYSFS_uint16 val)
+ * \brief Convert and write an unsigned 16-bit bigendian value.
+ *
+ * Convenience function. Convert an unsigned 16-bit value from the platform's
+ * native byte order to bigendian and write it to a file.
+ *
+ * \param file PhysicsFS file handle to which to write.
+ * \param val Value to convert and write.
+ * \return zero on failure, non-zero on success. On failure, you can
+ * find out what went wrong from PHYSFS_getLastError().
+ */
+PHYSFS_DECL int PHYSFS_writeUBE16(PHYSFS_File *file, PHYSFS_uint16 val);
+
+
+/**
+ * \fn int PHYSFS_writeSLE32(PHYSFS_File *file, PHYSFS_sint32 val)
+ * \brief Convert and write a signed 32-bit littleendian value.
+ *
+ * Convenience function. Convert a signed 32-bit value from the platform's
+ * native byte order to littleendian and write it to a file.
+ *
+ * \param file PhysicsFS file handle to which to write.
+ * \param val Value to convert and write.
+ * \return zero on failure, non-zero on success. On failure, you can
+ * find out what went wrong from PHYSFS_getLastError().
+ */
+PHYSFS_DECL int PHYSFS_writeSLE32(PHYSFS_File *file, PHYSFS_sint32 val);
+
+
+/**
+ * \fn int PHYSFS_writeULE32(PHYSFS_File *file, PHYSFS_uint32 val)
+ * \brief Convert and write an unsigned 32-bit littleendian value.
+ *
+ * Convenience function. Convert an unsigned 32-bit value from the platform's
+ * native byte order to littleendian and write it to a file.
+ *
+ * \param file PhysicsFS file handle to which to write.
+ * \param val Value to convert and write.
+ * \return zero on failure, non-zero on success. On failure, you can
+ * find out what went wrong from PHYSFS_getLastError().
+ */
+PHYSFS_DECL int PHYSFS_writeULE32(PHYSFS_File *file, PHYSFS_uint32 val);
+
+
+/**
+ * \fn int PHYSFS_writeSBE32(PHYSFS_File *file, PHYSFS_sint32 val)
+ * \brief Convert and write a signed 32-bit bigendian value.
+ *
+ * Convenience function. Convert a signed 32-bit value from the platform's
+ * native byte order to bigendian and write it to a file.
+ *
+ * \param file PhysicsFS file handle to which to write.
+ * \param val Value to convert and write.
+ * \return zero on failure, non-zero on success. On failure, you can
+ * find out what went wrong from PHYSFS_getLastError().
+ */
+PHYSFS_DECL int PHYSFS_writeSBE32(PHYSFS_File *file, PHYSFS_sint32 val);
+
+
+/**
+ * \fn int PHYSFS_writeUBE32(PHYSFS_File *file, PHYSFS_uint32 val)
+ * \brief Convert and write an unsigned 32-bit bigendian value.
+ *
+ * Convenience function. Convert an unsigned 32-bit value from the platform's
+ * native byte order to bigendian and write it to a file.
+ *
+ * \param file PhysicsFS file handle to which to write.
+ * \param val Value to convert and write.
+ * \return zero on failure, non-zero on success. On failure, you can
+ * find out what went wrong from PHYSFS_getLastError().
+ */
+PHYSFS_DECL int PHYSFS_writeUBE32(PHYSFS_File *file, PHYSFS_uint32 val);
+
+
+/**
+ * \fn int PHYSFS_writeSLE64(PHYSFS_File *file, PHYSFS_sint64 val)
+ * \brief Convert and write a signed 64-bit littleendian value.
+ *
+ * Convenience function. Convert a signed 64-bit value from the platform's
+ * native byte order to littleendian and write it to a file.
+ *
+ * \param file PhysicsFS file handle to which to write.
+ * \param val Value to convert and write.
+ * \return zero on failure, non-zero on success. On failure, you can
+ * find out what went wrong from PHYSFS_getLastError().
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ * any sort of 64-bit support.
+ */
+PHYSFS_DECL int PHYSFS_writeSLE64(PHYSFS_File *file, PHYSFS_sint64 val);
+
+
+/**
+ * \fn int PHYSFS_writeULE64(PHYSFS_File *file, PHYSFS_uint64 val)
+ * \brief Convert and write an unsigned 64-bit littleendian value.
+ *
+ * Convenience function. Convert an unsigned 64-bit value from the platform's
+ * native byte order to littleendian and write it to a file.
+ *
+ * \param file PhysicsFS file handle to which to write.
+ * \param val Value to convert and write.
+ * \return zero on failure, non-zero on success. On failure, you can
+ * find out what went wrong from PHYSFS_getLastError().
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ * any sort of 64-bit support.
+ */
+PHYSFS_DECL int PHYSFS_writeULE64(PHYSFS_File *file, PHYSFS_uint64 val);
+
+
+/**
+ * \fn int PHYSFS_writeSBE64(PHYSFS_File *file, PHYSFS_sint64 val)
+ * \brief Convert and write a signed 64-bit bigending value.
+ *
+ * Convenience function. Convert a signed 64-bit value from the platform's
+ * native byte order to bigendian and write it to a file.
+ *
+ * \param file PhysicsFS file handle to which to write.
+ * \param val Value to convert and write.
+ * \return zero on failure, non-zero on success. On failure, you can
+ * find out what went wrong from PHYSFS_getLastError().
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ * any sort of 64-bit support.
+ */
+PHYSFS_DECL int PHYSFS_writeSBE64(PHYSFS_File *file, PHYSFS_sint64 val);
+
+
+/**
+ * \fn int PHYSFS_writeUBE64(PHYSFS_File *file, PHYSFS_uint64 val)
+ * \brief Convert and write an unsigned 64-bit bigendian value.
+ *
+ * Convenience function. Convert an unsigned 64-bit value from the platform's
+ * native byte order to bigendian and write it to a file.
+ *
+ * \param file PhysicsFS file handle to which to write.
+ * \param val Value to convert and write.
+ * \return zero on failure, non-zero on success. On failure, you can
+ * find out what went wrong from PHYSFS_getLastError().
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ * any sort of 64-bit support.
+ */
+PHYSFS_DECL int PHYSFS_writeUBE64(PHYSFS_File *file, PHYSFS_uint64 val);
+
+
+/* Everything above this line is part of the PhysicsFS 1.0 API. */
+
+/**
+ * \fn int PHYSFS_isInit(void)
+ * \brief Determine if the PhysicsFS library is initialized.
+ *
+ * Once PHYSFS_init() returns successfully, this will return non-zero.
+ * Before a successful PHYSFS_init() and after PHYSFS_deinit() returns
+ * successfully, this will return zero. This function is safe to call at
+ * any time.
+ *
+ * \return non-zero if library is initialized, zero if library is not.
+ *
+ * \sa PHYSFS_init
+ * \sa PHYSFS_deinit
+ */
+PHYSFS_DECL int PHYSFS_isInit(void);
+
+
+/**
+ * \fn int PHYSFS_symbolicLinksPermitted(void)
+ * \brief Determine if the symbolic links are permitted.
+ *
+ * This reports the setting from the last call to PHYSFS_permitSymbolicLinks().
+ * If PHYSFS_permitSymbolicLinks() hasn't been called since the library was
+ * last initialized, symbolic links are implicitly disabled.
+ *
+ * \return non-zero if symlinks are permitted, zero if not.
+ *
+ * \sa PHYSFS_permitSymbolicLinks
+ */
+PHYSFS_DECL int PHYSFS_symbolicLinksPermitted(void);
+
+
+#ifndef SWIG /* not available from scripting languages. */
+
+/**
+ * \struct PHYSFS_Allocator
+ * \brief PhysicsFS allocation function pointers.
+ *
+ * (This is for limited, hardcore use. If you don't immediately see a need
+ * for it, you can probably ignore this forever.)
+ *
+ * You create one of these structures for use with PHYSFS_setAllocator.
+ * Allocators are assumed to be reentrant by the caller; please mutex
+ * accordingly.
+ *
+ * Allocations are always discussed in 64-bits, for future expansion...we're
+ * on the cusp of a 64-bit transition, and we'll probably be allocating 6
+ * gigabytes like it's nothing sooner or later, and I don't want to change
+ * this again at that point. If you're on a 32-bit platform and have to
+ * downcast, it's okay to return NULL if the allocation is greater than
+ * 4 gigabytes, since you'd have to do so anyhow.
+ *
+ * \sa PHYSFS_setAllocator
+ */
+typedef struct PHYSFS_Allocator
+{
+ int (*Init)(void); /**< Initialize. Can be NULL. Zero on failure. */
+ void (*Deinit)(void); /**< Deinitialize your allocator. Can be NULL. */
+ void *(*Malloc)(PHYSFS_uint64); /**< Allocate like malloc(). */
+ void *(*Realloc)(void *, PHYSFS_uint64); /**< Reallocate like realloc(). */
+ void (*Free)(void *); /**< Free memory from Malloc or Realloc. */
+} PHYSFS_Allocator;
+
+
+/**
+ * \fn int PHYSFS_setAllocator(const PHYSFS_Allocator *allocator)
+ * \brief Hook your own allocation routines into PhysicsFS.
+ *
+ * (This is for limited, hardcore use. If you don't immediately see a need
+ * for it, you can probably ignore this forever.)
+ *
+ * By default, PhysicsFS will use whatever is reasonable for a platform
+ * to manage dynamic memory (usually ANSI C malloc/realloc/free, but
+ * some platforms might use something else), but in some uncommon cases, the
+ * app might want more control over the library's memory management. This
+ * lets you redirect PhysicsFS to use your own allocation routines instead.
+ * You can only call this function before PHYSFS_init(); if the library is
+ * initialized, it'll reject your efforts to change the allocator mid-stream.
+ * You may call this function after PHYSFS_deinit() if you are willing to
+ * shut down the library and restart it with a new allocator; this is a safe
+ * and supported operation. The allocator remains intact between deinit/init
+ * calls. If you want to return to the platform's default allocator, pass a
+ * NULL in here.
+ *
+ * If you aren't immediately sure what to do with this function, you can
+ * safely ignore it altogether.
+ *
+ * \param allocator Structure containing your allocator's entry points.
+ * \return zero on failure, non-zero on success. This call only fails
+ * when used between PHYSFS_init() and PHYSFS_deinit() calls.
+ */
+PHYSFS_DECL int PHYSFS_setAllocator(const PHYSFS_Allocator *allocator);
+
+#endif /* SWIG */
+
+
+/**
+ * \fn int PHYSFS_mount(const char *newDir, const char *mountPoint, int appendToPath)
+ * \brief Add an archive or directory to the search path.
+ *
+ * If this is a duplicate, the entry is not added again, even though the
+ * function succeeds. You may not add the same archive to two different
+ * mountpoints: duplicate checking is done against the archive and not the
+ * mountpoint.
+ *
+ * When you mount an archive, it is added to a virtual file system...all files
+ * in all of the archives are interpolated into a single hierachical file
+ * tree. Two archives mounted at the same place (or an archive with files
+ * overlapping another mountpoint) may have overlapping files: in such a case,
+ * the file earliest in the search path is selected, and the other files are
+ * inaccessible to the application. This allows archives to be used to
+ * override previous revisions; you can use the mounting mechanism to place
+ * archives at a specific point in the file tree and prevent overlap; this
+ * is useful for downloadable mods that might trample over application data
+ * or each other, for example.
+ *
+ * The mountpoint does not need to exist prior to mounting, which is different
+ * than those familiar with the Unix concept of "mounting" may not expect.
+ * As well, more than one archive can be mounted to the same mountpoint, or
+ * mountpoints and archive contents can overlap...the interpolation mechanism
+ * still functions as usual.
+ *
+ * \param newDir directory or archive to add to the path, in
+ * platform-dependent notation.
+ * \param mountPoint Location in the interpolated tree that this archive
+ * will be "mounted", in platform-independent notation.
+ * NULL or "" is equivalent to "/".
+ * \param appendToPath nonzero to append to search path, zero to prepend.
+ * \return nonzero if added to path, zero on failure (bogus archive, dir
+ * missing, etc). Specifics of the error can be
+ * gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_removeFromSearchPath
+ * \sa PHYSFS_getSearchPath
+ * \sa PHYSFS_getMountPoint
+ * \sa PHYSFS_mountIo
+ */
+PHYSFS_DECL int PHYSFS_mount(const char *newDir,
+ const char *mountPoint,
+ int appendToPath);
+
+/**
+ * \fn int PHYSFS_getMountPoint(const char *dir)
+ * \brief Determine a mounted archive's mountpoint.
+ *
+ * You give this function the name of an archive or dir you successfully
+ * added to the search path, and it reports the location in the interpolated
+ * tree where it is mounted. Files mounted with a NULL mountpoint or through
+ * PHYSFS_addToSearchPath() will report "/". The return value is READ ONLY
+ * and valid until the archive is removed from the search path.
+ *
+ * \param dir directory or archive previously added to the path, in
+ * platform-dependent notation. This must match the string
+ * used when adding, even if your string would also reference
+ * the same file with a different string of characters.
+ * \return READ-ONLY string of mount point if added to path, NULL on failure
+ * (bogus archive, etc) Specifics of the error can be gleaned from
+ * PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_removeFromSearchPath
+ * \sa PHYSFS_getSearchPath
+ * \sa PHYSFS_getMountPoint
+ */
+PHYSFS_DECL const char *PHYSFS_getMountPoint(const char *dir);
+
+
+#ifndef SWIG /* not available from scripting languages. */
+
+/**
+ * \typedef PHYSFS_StringCallback
+ * \brief Function signature for callbacks that report strings.
+ *
+ * These are used to report a list of strings to an original caller, one
+ * string per callback. All strings are UTF-8 encoded. Functions should not
+ * try to modify or free the string's memory.
+ *
+ * These callbacks are used, starting in PhysicsFS 1.1, as an alternative to
+ * functions that would return lists that need to be cleaned up with
+ * PHYSFS_freeList(). The callback means that the library doesn't need to
+ * allocate an entire list and all the strings up front.
+ *
+ * Be aware that promises data ordering in the list versions are not
+ * necessarily so in the callback versions. Check the documentation on
+ * specific APIs, but strings may not be sorted as you expect.
+ *
+ * \param data User-defined data pointer, passed through from the API
+ * that eventually called the callback.
+ * \param str The string data about which the callback is meant to inform.
+ *
+ * \sa PHYSFS_getCdRomDirsCallback
+ * \sa PHYSFS_getSearchPathCallback
+ */
+typedef void (*PHYSFS_StringCallback)(void *data, const char *str);
+
+
+/**
+ * \typedef PHYSFS_EnumFilesCallback
+ * \brief Function signature for callbacks that enumerate files.
+ *
+ * These are used to report a list of directory entries to an original caller,
+ * one file/dir/symlink per callback. All strings are UTF-8 encoded.
+ * Functions should not try to modify or free any string's memory.
+ *
+ * These callbacks are used, starting in PhysicsFS 1.1, as an alternative to
+ * functions that would return lists that need to be cleaned up with
+ * PHYSFS_freeList(). The callback means that the library doesn't need to
+ * allocate an entire list and all the strings up front.
+ *
+ * Be aware that promises data ordering in the list versions are not
+ * necessarily so in the callback versions. Check the documentation on
+ * specific APIs, but strings may not be sorted as you expect.
+ *
+ * \param data User-defined data pointer, passed through from the API
+ * that eventually called the callback.
+ * \param origdir A string containing the full path, in platform-independent
+ * notation, of the directory containing this file. In most
+ * cases, this is the directory on which you requested
+ * enumeration, passed in the callback for your convenience.
+ * \param fname The filename that is being enumerated. It may not be in
+ * alphabetical order compared to other callbacks that have
+ * fired, and it will not contain the full path. You can
+ * recreate the fullpath with $origdir/$fname ... The file
+ * can be a subdirectory, a file, a symlink, etc.
+ *
+ * \sa PHYSFS_enumerateFilesCallback
+ */
+typedef void (*PHYSFS_EnumFilesCallback)(void *data, const char *origdir,
+ const char *fname);
+
+
+/**
+ * \fn void PHYSFS_getCdRomDirsCallback(PHYSFS_StringCallback c, void *d)
+ * \brief Enumerate CD-ROM directories, using an application-defined callback.
+ *
+ * Internally, PHYSFS_getCdRomDirs() just calls this function and then builds
+ * a list before returning to the application, so functionality is identical
+ * except for how the information is represented to the application.
+ *
+ * Unlike PHYSFS_getCdRomDirs(), this function does not return an array.
+ * Rather, it calls a function specified by the application once per
+ * detected disc:
+ *
+ * \code
+ *
+ * static void foundDisc(void *data, const char *cddir)
+ * {
+ * printf("cdrom dir [%s] is available.\n", cddir);
+ * }
+ *
+ * // ...
+ * PHYSFS_getCdRomDirsCallback(foundDisc, NULL);
+ * \endcode
+ *
+ * This call may block while drives spin up. Be forewarned.
+ *
+ * \param c Callback function to notify about detected drives.
+ * \param d Application-defined data passed to callback. Can be NULL.
+ *
+ * \sa PHYSFS_StringCallback
+ * \sa PHYSFS_getCdRomDirs
+ */
+PHYSFS_DECL void PHYSFS_getCdRomDirsCallback(PHYSFS_StringCallback c, void *d);
+
+
+/**
+ * \fn void PHYSFS_getSearchPathCallback(PHYSFS_StringCallback c, void *d)
+ * \brief Enumerate the search path, using an application-defined callback.
+ *
+ * Internally, PHYSFS_getSearchPath() just calls this function and then builds
+ * a list before returning to the application, so functionality is identical
+ * except for how the information is represented to the application.
+ *
+ * Unlike PHYSFS_getSearchPath(), this function does not return an array.
+ * Rather, it calls a function specified by the application once per
+ * element of the search path:
+ *
+ * \code
+ *
+ * static void printSearchPath(void *data, const char *pathItem)
+ * {
+ * printf("[%s] is in the search path.\n", pathItem);
+ * }
+ *
+ * // ...
+ * PHYSFS_getSearchPathCallback(printSearchPath, NULL);
+ * \endcode
+ *
+ * Elements of the search path are reported in order search priority, so the
+ * first archive/dir that would be examined when looking for a file is the
+ * first element passed through the callback.
+ *
+ * \param c Callback function to notify about search path elements.
+ * \param d Application-defined data passed to callback. Can be NULL.
+ *
+ * \sa PHYSFS_StringCallback
+ * \sa PHYSFS_getSearchPath
+ */
+PHYSFS_DECL void PHYSFS_getSearchPathCallback(PHYSFS_StringCallback c, void *d);
+
+
+/**
+ * \fn void PHYSFS_enumerateFilesCallback(const char *dir, PHYSFS_EnumFilesCallback c, void *d)
+ * \brief Get a file listing of a search path's directory, using an application-defined callback.
+ *
+ * Internally, PHYSFS_enumerateFiles() just calls this function and then builds
+ * a list before returning to the application, so functionality is identical
+ * except for how the information is represented to the application.
+ *
+ * Unlike PHYSFS_enumerateFiles(), this function does not return an array.
+ * Rather, it calls a function specified by the application once per
+ * element of the search path:
+ *
+ * \code
+ *
+ * static void printDir(void *data, const char *origdir, const char *fname)
+ * {
+ * printf(" * We've got [%s] in [%s].\n", fname, origdir);
+ * }
+ *
+ * // ...
+ * PHYSFS_enumerateFilesCallback("/some/path", printDir, NULL);
+ * \endcode
+ *
+ * !!! FIXME: enumerateFiles() does not promise alphabetical sorting by
+ * !!! FIXME: case-sensitivity in the code, and doesn't promise sorting at
+ * !!! FIXME: all in the above docs.
+ *
+ * Items sent to the callback are not guaranteed to be in any order whatsoever.
+ * There is no sorting done at this level, and if you need that, you should
+ * probably use PHYSFS_enumerateFiles() instead, which guarantees
+ * alphabetical sorting. This form reports whatever is discovered in each
+ * archive before moving on to the next. Even within one archive, we can't
+ * guarantee what order it will discover data. Any sorting you find in
+ * these callbacks is just pure luck. Do not rely on it. As this walks
+ * the entire list of archives, you may receive duplicate filenames.
+ *
+ * \param dir Directory, in platform-independent notation, to enumerate.
+ * \param c Callback function to notify about search path elements.
+ * \param d Application-defined data passed to callback. Can be NULL.
+ *
+ * \sa PHYSFS_EnumFilesCallback
+ * \sa PHYSFS_enumerateFiles
+ */
+PHYSFS_DECL void PHYSFS_enumerateFilesCallback(const char *dir,
+ PHYSFS_EnumFilesCallback c,
+ void *d);
+
+/**
+ * \fn void PHYSFS_utf8FromUcs4(const PHYSFS_uint32 *src, char *dst, PHYSFS_uint64 len)
+ * \brief Convert a UCS-4 string to a UTF-8 string.
+ *
+ * UCS-4 strings are 32-bits per character: \c wchar_t on Unix.
+ *
+ * To ensure that the destination buffer is large enough for the conversion,
+ * please allocate a buffer that is the same size as the source buffer. UTF-8
+ * never uses more than 32-bits per character, so while it may shrink a UCS-4
+ * string, it will never expand it.
+ *
+ * Strings that don't fit in the destination buffer will be truncated, but
+ * will always be null-terminated and never have an incomplete UTF-8
+ * sequence at the end. If the buffer length is 0, this function does nothing.
+ *
+ * \param src Null-terminated source string in UCS-4 format.
+ * \param dst Buffer to store converted UTF-8 string.
+ * \param len Size, in bytes, of destination buffer.
+ */
+PHYSFS_DECL void PHYSFS_utf8FromUcs4(const PHYSFS_uint32 *src, char *dst,
+ PHYSFS_uint64 len);
+
+/**
+ * \fn void PHYSFS_utf8ToUcs4(const char *src, PHYSFS_uint32 *dst, PHYSFS_uint64 len)
+ * \brief Convert a UTF-8 string to a UCS-4 string.
+ *
+ * UCS-4 strings are 32-bits per character: \c wchar_t on Unix.
+ *
+ * To ensure that the destination buffer is large enough for the conversion,
+ * please allocate a buffer that is four times the size of the source buffer.
+ * UTF-8 uses from one to four bytes per character, but UCS-4 always uses
+ * four, so an entirely low-ASCII string will quadruple in size!
+ *
+ * Strings that don't fit in the destination buffer will be truncated, but
+ * will always be null-terminated and never have an incomplete UCS-4
+ * sequence at the end. If the buffer length is 0, this function does nothing.
+ *
+ * \param src Null-terminated source string in UTF-8 format.
+ * \param dst Buffer to store converted UCS-4 string.
+ * \param len Size, in bytes, of destination buffer.
+ */
+PHYSFS_DECL void PHYSFS_utf8ToUcs4(const char *src, PHYSFS_uint32 *dst,
+ PHYSFS_uint64 len);
+
+/**
+ * \fn void PHYSFS_utf8FromUcs2(const PHYSFS_uint16 *src, char *dst, PHYSFS_uint64 len)
+ * \brief Convert a UCS-2 string to a UTF-8 string.
+ *
+ * \warning you almost certainly should use PHYSFS_utf8FromUtf16(), which
+ * became available in PhysicsFS 2.1, unless you know what you're doing.
+ *
+ * UCS-2 strings are 16-bits per character: \c TCHAR on Windows, when building
+ * with Unicode support. Please note that modern versions of Windows use
+ * UTF-16, which is an extended form of UCS-2, and not UCS-2 itself. You
+ * almost certainly want PHYSFS_utf8FromUtf16() instead.
+ *
+ * To ensure that the destination buffer is large enough for the conversion,
+ * please allocate a buffer that is double the size of the source buffer.
+ * UTF-8 never uses more than 32-bits per character, so while it may shrink
+ * a UCS-2 string, it may also expand it.
+ *
+ * Strings that don't fit in the destination buffer will be truncated, but
+ * will always be null-terminated and never have an incomplete UTF-8
+ * sequence at the end. If the buffer length is 0, this function does nothing.
+ *
+ * \param src Null-terminated source string in UCS-2 format.
+ * \param dst Buffer to store converted UTF-8 string.
+ * \param len Size, in bytes, of destination buffer.
+ *
+ * \sa PHYSFS_utf8FromUtf16
+ */
+PHYSFS_DECL void PHYSFS_utf8FromUcs2(const PHYSFS_uint16 *src, char *dst,
+ PHYSFS_uint64 len);
+
+/**
+ * \fn PHYSFS_utf8ToUcs2(const char *src, PHYSFS_uint16 *dst, PHYSFS_uint64 len)
+ * \brief Convert a UTF-8 string to a UCS-2 string.
+ *
+ * \warning you almost certainly should use PHYSFS_utf8ToUtf16(), which
+ * became available in PhysicsFS 2.1, unless you know what you're doing.
+ *
+ * UCS-2 strings are 16-bits per character: \c TCHAR on Windows, when building
+ * with Unicode support. Please note that modern versions of Windows use
+ * UTF-16, which is an extended form of UCS-2, and not UCS-2 itself. You
+ * almost certainly want PHYSFS_utf8ToUtf16() instead, but you need to
+ * understand how that changes things, too.
+ *
+ * To ensure that the destination buffer is large enough for the conversion,
+ * please allocate a buffer that is double the size of the source buffer.
+ * UTF-8 uses from one to four bytes per character, but UCS-2 always uses
+ * two, so an entirely low-ASCII string will double in size!
+ *
+ * Strings that don't fit in the destination buffer will be truncated, but
+ * will always be null-terminated and never have an incomplete UCS-2
+ * sequence at the end. If the buffer length is 0, this function does nothing.
+ *
+ * \param src Null-terminated source string in UTF-8 format.
+ * \param dst Buffer to store converted UCS-2 string.
+ * \param len Size, in bytes, of destination buffer.
+ *
+ * \sa PHYSFS_utf8ToUtf16
+ */
+PHYSFS_DECL void PHYSFS_utf8ToUcs2(const char *src, PHYSFS_uint16 *dst,
+ PHYSFS_uint64 len);
+
+/**
+ * \fn void PHYSFS_utf8FromLatin1(const char *src, char *dst, PHYSFS_uint64 len)
+ * \brief Convert a UTF-8 string to a Latin1 string.
+ *
+ * Latin1 strings are 8-bits per character: a popular "high ASCII" encoding.
+ *
+ * To ensure that the destination buffer is large enough for the conversion,
+ * please allocate a buffer that is double the size of the source buffer.
+ * UTF-8 expands latin1 codepoints over 127 from 1 to 2 bytes, so the string
+ * may grow in some cases.
+ *
+ * Strings that don't fit in the destination buffer will be truncated, but
+ * will always be null-terminated and never have an incomplete UTF-8
+ * sequence at the end. If the buffer length is 0, this function does nothing.
+ *
+ * Please note that we do not supply a UTF-8 to Latin1 converter, since Latin1
+ * can't express most Unicode codepoints. It's a legacy encoding; you should
+ * be converting away from it at all times.
+ *
+ * \param src Null-terminated source string in Latin1 format.
+ * \param dst Buffer to store converted UTF-8 string.
+ * \param len Size, in bytes, of destination buffer.
+ */
+PHYSFS_DECL void PHYSFS_utf8FromLatin1(const char *src, char *dst,
+ PHYSFS_uint64 len);
+
+/* Everything above this line is part of the PhysicsFS 2.0 API. */
+
+/**
+ * \fn int PHYSFS_unmount(const char *oldDir)
+ * \brief Remove a directory or archive from the search path.
+ *
+ * This is functionally equivalent to PHYSFS_removeFromSearchPath(), but that
+ * function is deprecated to keep the vocabulary paired with PHYSFS_mount().
+ *
+ * This must be a (case-sensitive) match to a dir or archive already in the
+ * search path, specified in platform-dependent notation.
+ *
+ * This call will fail (and fail to remove from the path) if the element still
+ * has files open in it.
+ *
+ * \param oldDir dir/archive to remove.
+ * \return nonzero on success, zero on failure.
+ * Specifics of the error can be gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_getSearchPath
+ * \sa PHYSFS_mount
+ */
+PHYSFS_DECL int PHYSFS_unmount(const char *oldDir);
+
+/**
+ * \fn const PHYSFS_Allocator *PHYSFS_getAllocator(void)
+ * \brief Discover the current allocator.
+ *
+ * (This is for limited, hardcore use. If you don't immediately see a need
+ * for it, you can probably ignore this forever.)
+ *
+ * This function exposes the function pointers that make up the currently used
+ * allocator. This can be useful for apps that want to access PhysicsFS's
+ * internal, default allocation routines, as well as for external code that
+ * wants to share the same allocator, even if the application specified their
+ * own.
+ *
+ * This call is only valid between PHYSFS_init() and PHYSFS_deinit() calls;
+ * it will return NULL if the library isn't initialized. As we can't
+ * guarantee the state of the internal allocators unless the library is
+ * initialized, you shouldn't use any allocator returned here after a call
+ * to PHYSFS_deinit().
+ *
+ * Do not call the returned allocator's Init() or Deinit() methods under any
+ * circumstances.
+ *
+ * If you aren't immediately sure what to do with this function, you can
+ * safely ignore it altogether.
+ *
+ * \return Current allocator, as set by PHYSFS_setAllocator(), or PhysicsFS's
+ * internal, default allocator if no application defined allocator
+ * is currently set. Will return NULL if the library is not
+ * initialized.
+ *
+ * \sa PHYSFS_Allocator
+ * \sa PHYSFS_setAllocator
+ */
+PHYSFS_DECL const PHYSFS_Allocator *PHYSFS_getAllocator(void);
+
+#endif /* SWIG */
+
+/**
+ * \enum PHYSFS_FileType
+ * \brief Type of a File
+ *
+ * Possible types of a file.
+ *
+ * \sa PHYSFS_stat
+ */
+typedef enum PHYSFS_FileType
+{
+ PHYSFS_FILETYPE_REGULAR, /**< a normal file */
+ PHYSFS_FILETYPE_DIRECTORY, /**< a directory */
+ PHYSFS_FILETYPE_SYMLINK, /**< a symlink */
+ PHYSFS_FILETYPE_OTHER /**< something completely different like a device */
+} PHYSFS_FileType;
+
+/**
+ * \struct PHYSFS_Stat
+ * \brief Meta data for a file or directory
+ *
+ * Container for various meta data about a file in the virtual file system.
+ * PHYSFS_stat() uses this structure for returning the information. The time
+ * data will be either the number of seconds since the Unix epoch (midnight,
+ * Jan 1, 1970), or -1 if the information isn't available or applicable.
+ * The (filesize) field is measured in bytes.
+ * The (readonly) field tells you whether when you open a file for writing you
+ * are writing to the same file as if you were opening it, given you have
+ * enough filesystem rights to do that. !!! FIXME: this might change.
+ *
+ * \sa PHYSFS_stat
+ * \sa PHYSFS_FileType
+ */
+typedef struct PHYSFS_Stat
+{
+ PHYSFS_sint64 filesize; /**< size in bytes, -1 for non-files and unknown */
+ PHYSFS_sint64 modtime; /**< last modification time */
+ PHYSFS_sint64 createtime; /**< like modtime, but for file creation time */
+ PHYSFS_sint64 accesstime; /**< like modtime, but for file access time */
+ PHYSFS_FileType filetype; /**< File? Directory? Symlink? */
+ int readonly; /**< non-zero if read only, zero if writable. */
+} PHYSFS_Stat;
+
+/**
+ * \fn int PHYSFS_stat(const char *fname, PHYSFS_Stat *stat)
+ * \brief Get various information about a directory or a file.
+ *
+ * Obtain various information about a file or directory from the meta data.
+ *
+ * This function will never follow symbolic links. If you haven't enabled
+ * symlinks with PHYSFS_permitSymbolicLinks(), stat'ing a symlink will be
+ * treated like stat'ing a non-existant file. If symlinks are enabled,
+ * stat'ing a symlink will give you information on the link itself and not
+ * what it points to.
+ *
+ * \param fname filename to check, in platform-indepedent notation.
+ * \param stat pointer to structure to fill in with data about (fname).
+ * \return non-zero on success, zero on failure. On failure, (stat)'s
+ * contents are undefined.
+ *
+ * \sa PHYSFS_Stat
+ */
+PHYSFS_DECL int PHYSFS_stat(const char *fname, PHYSFS_Stat *stat);
+
+
+#ifndef SWIG /* not available from scripting languages. */
+
+/**
+ * \fn void PHYSFS_utf8FromUtf16(const PHYSFS_uint16 *src, char *dst, PHYSFS_uint64 len)
+ * \brief Convert a UTF-16 string to a UTF-8 string.
+ *
+ * UTF-16 strings are 16-bits per character (except some chars, which are
+ * 32-bits): \c TCHAR on Windows, when building with Unicode support. Modern
+ * Windows releases use UTF-16. Windows releases before 2000 used TCHAR, but
+ * only handled UCS-2. UTF-16 _is_ UCS-2, except for the characters that
+ * are 4 bytes, which aren't representable in UCS-2 at all anyhow. If you
+ * aren't sure, you should be using UTF-16 at this point on Windows.
+ *
+ * To ensure that the destination buffer is large enough for the conversion,
+ * please allocate a buffer that is double the size of the source buffer.
+ * UTF-8 never uses more than 32-bits per character, so while it may shrink
+ * a UTF-16 string, it may also expand it.
+ *
+ * Strings that don't fit in the destination buffer will be truncated, but
+ * will always be null-terminated and never have an incomplete UTF-8
+ * sequence at the end. If the buffer length is 0, this function does nothing.
+ *
+ * \param src Null-terminated source string in UTF-16 format.
+ * \param dst Buffer to store converted UTF-8 string.
+ * \param len Size, in bytes, of destination buffer.
+ */
+PHYSFS_DECL void PHYSFS_utf8FromUtf16(const PHYSFS_uint16 *src, char *dst,
+ PHYSFS_uint64 len);
+
+/**
+ * \fn PHYSFS_utf8ToUtf16(const char *src, PHYSFS_uint16 *dst, PHYSFS_uint64 len)
+ * \brief Convert a UTF-8 string to a UTF-16 string.
+ *
+ * UTF-16 strings are 16-bits per character (except some chars, which are
+ * 32-bits): \c TCHAR on Windows, when building with Unicode support. Modern
+ * Windows releases use UTF-16. Windows releases before 2000 used TCHAR, but
+ * only handled UCS-2. UTF-16 _is_ UCS-2, except for the characters that
+ * are 4 bytes, which aren't representable in UCS-2 at all anyhow. If you
+ * aren't sure, you should be using UTF-16 at this point on Windows.
+ *
+ * To ensure that the destination buffer is large enough for the conversion,
+ * please allocate a buffer that is double the size of the source buffer.
+ * UTF-8 uses from one to four bytes per character, but UTF-16 always uses
+ * two to four, so an entirely low-ASCII string will double in size! The
+ * UTF-16 characters that would take four bytes also take four bytes in UTF-8,
+ * so you don't need to allocate 4x the space just in case: double will do.
+ *
+ * Strings that don't fit in the destination buffer will be truncated, but
+ * will always be null-terminated and never have an incomplete UTF-16
+ * surrogate pair at the end. If the buffer length is 0, this function does
+ * nothing.
+ *
+ * \param src Null-terminated source string in UTF-8 format.
+ * \param dst Buffer to store converted UTF-16 string.
+ * \param len Size, in bytes, of destination buffer.
+ *
+ * \sa PHYSFS_utf8ToUtf16
+ */
+PHYSFS_DECL void PHYSFS_utf8ToUtf16(const char *src, PHYSFS_uint16 *dst,
+ PHYSFS_uint64 len);
+
+#endif /* SWIG */
+
+
+/**
+ * \fn PHYSFS_sint64 PHYSFS_readBytes(PHYSFS_File *handle, void *buffer, PHYSFS_uint64 len)
+ * \brief Read bytes from a PhysicsFS filehandle
+ *
+ * The file must be opened for reading.
+ *
+ * \param handle handle returned from PHYSFS_openRead().
+ * \param buffer buffer of at least (len) bytes to store read data into.
+ * \param len number of bytes being read from (handle).
+ * \return number of bytes read. This may be less than (len); this does not
+ * signify an error, necessarily (a short read may mean EOF).
+ * PHYSFS_getLastError() can shed light on the reason this might
+ * be < (len), as can PHYSFS_eof(). -1 if complete failure.
+ *
+ * \sa PHYSFS_eof
+ */
+PHYSFS_DECL PHYSFS_sint64 PHYSFS_readBytes(PHYSFS_File *handle, void *buffer,
+ PHYSFS_uint64 len);
+
+/**
+ * \fn PHYSFS_sint64 PHYSFS_writeBytes(PHYSFS_File *handle, const void *buffer, PHYSFS_uint64 len)
+ * \brief Write data to a PhysicsFS filehandle
+ *
+ * The file must be opened for writing.
+ *
+ * Please note that while (len) is an unsigned 64-bit integer, you are limited
+ * to 63 bits (9223372036854775807 bytes), so we can return a negative value
+ * on error. If length is greater than 0x7FFFFFFFFFFFFFFF, this function will
+ * immediately fail. For systems without a 64-bit datatype, you are limited
+ * to 31 bits (0x7FFFFFFF, or 2147483647 bytes). We trust most things won't
+ * need to do multiple gigabytes of i/o in one call anyhow, but why limit
+ * things?
+ *
+ * \param handle retval from PHYSFS_openWrite() or PHYSFS_openAppend().
+ * \param buffer buffer of (len) bytes to write to (handle).
+ * \param len number of bytes being written to (handle).
+ * \return number of bytes written. This may be less than (len); in the case
+ * of an error, the system may try to write as many bytes as possible,
+ * so an incomplete write might occur. PHYSFS_getLastError() can shed
+ * light on the reason this might be < (len). -1 if complete failure.
+ */
+PHYSFS_DECL PHYSFS_sint64 PHYSFS_writeBytes(PHYSFS_File *handle,
+ const void *buffer,
+ PHYSFS_uint64 len);
+
+
+#ifndef SWIG /* not available from scripting languages. */
+
+/**
+ * \struct PHYSFS_Io
+ * \brief An abstract i/o interface.
+ *
+ * \warning This is advanced, hardcore stuff. You don't need this unless you
+ * really know what you're doing. Most apps will not need this.
+ *
+ * Historically, PhysicsFS provided access to the physical filesystem and
+ * archives within that filesystem. However, sometimes you need more power
+ * than this. Perhaps you need to provide an archive that is entirely
+ * contained in RAM, or you need to bridge some other file i/o API to
+ * PhysicsFS, or you need to translate the bits (perhaps you have a
+ * a standard .zip file that's encrypted, and you need to decrypt on the fly
+ * for the unsuspecting zip archiver).
+ *
+ * A PHYSFS_Io is the interface that Archivers use to get archive data.
+ * Historically, this has mapped to file i/o to the physical filesystem, but
+ * as of PhysicsFS 2.1, applications can provide their own i/o implementations
+ * at runtime.
+ *
+ * This interface isn't necessarily a good universal fit for i/o. There are a
+ * few requirements of note:
+ *
+ * - They only do blocking i/o (at least, for now).
+ * - They need to be able to duplicate. If you have a file handle from
+ * fopen(), you need to be able to create a unique clone of it (so we
+ * have two handles to the same file that can both seek/read/etc without
+ * stepping on each other).
+ * - They need to know the size of their entire data set.
+ * - They need to be able to seek and rewind on demand.
+ *
+ * ...in short, you're probably not going to write an HTTP implementation.
+ *
+ * Thread safety: TO BE DECIDED. !!! FIXME
+ *
+ * \sa PHYSFS_mountIo
+ */
+typedef struct PHYSFS_Io
+{
+ /**
+ * \brief Binary compatibility information.
+ *
+ * This must be set to zero at this time. Future versions of this
+ * struct will increment this field, so we know what a given
+ * implementation supports. We'll presumably keep supporting older
+ * versions as we offer new features, though.
+ */
+ PHYSFS_uint32 version;
+
+ /**
+ * \brief Instance data for this struct.
+ *
+ * Each instance has a pointer associated with it that can be used to
+ * store anything it likes. This pointer is per-instance of the stream,
+ * so presumably it will change when calling duplicate(). This can be
+ * deallocated during the destroy() method.
+ */
+ void *opaque;
+
+ /**
+ * \brief Read more data.
+ *
+ * Read (len) bytes from the interface, at the current i/o position, and
+ * store them in (buffer). The current i/o position should move ahead
+ * by the number of bytes successfully read.
+ *
+ * You don't have to implement this; set it to NULL if not implemented.
+ * This will only be used if the file is opened for reading. If set to
+ * NULL, a default implementation that immediately reports failure will
+ * be used.
+ *
+ * \param io The i/o instance to read from.
+ * \param buf The buffer to store data into. It must be at least
+ * (len) bytes long and can't be NULL.
+ * \param len The number of bytes to read from the interface.
+ * \return number of bytes read from file, 0 on EOF, -1 if complete
+ * failure.
+ */
+ PHYSFS_sint64 (*read)(struct PHYSFS_Io *io, void *buf, PHYSFS_uint64 len);
+
+ /**
+ * \brief Write more data.
+ *
+ * Write (len) bytes from (buffer) to the interface at the current i/o
+ * position. The current i/o position should move ahead by the number of
+ * bytes successfully written.
+ *
+ * You don't have to implement this; set it to NULL if not implemented.
+ * This will only be used if the file is opened for writing. If set to
+ * NULL, a default implementation that immediately reports failure will
+ * be used.
+ *
+ * You are allowed to buffer; a write can succeed here and then later
+ * fail when flushing. Note that PHYSFS_setBuffer() may be operating a
+ * level above your i/o, so you should usually not implement your
+ * own buffering routines.
+ *
+ * \param io The i/o instance to write to.
+ * \param buffer The buffer to read data from. It must be at least
+ * (len) bytes long and can't be NULL.
+ * \param len The number of bytes to read from (buffer).
+ * \return number of bytes written to file, -1 if complete failure.
+ */
+ PHYSFS_sint64 (*write)(struct PHYSFS_Io *io, const void *buffer,
+ PHYSFS_uint64 len);
+
+ /**
+ * \brief Move i/o position to a given byte offset from start.
+ *
+ * This method moves the i/o position, so the next read/write will
+ * be of the byte at (offset) offset. Seeks past the end of file should
+ * be treated as an error condition.
+ *
+ * \param io The i/o instance to seek.
+ * \param offset The new byte offset for the i/o position.
+ * \return non-zero on success, zero on error.
+ */
+ int (*seek)(struct PHYSFS_Io *io, PHYSFS_uint64 offset);
+
+ /**
+ * \brief Report current i/o position.
+ *
+ * Return bytes offset, or -1 if you aren't able to determine. A failure
+ * will almost certainly be fatal to further use of this stream, so you
+ * may not leave this unimplemented.
+ *
+ * \param io The i/o instance to query.
+ * \return The current byte offset for the i/o position, -1 if unknown.
+ */
+ PHYSFS_sint64 (*tell)(struct PHYSFS_Io *io);
+
+ /**
+ * \brief Determine size of the i/o instance's dataset.
+ *
+ * Return number of bytes available in the file, or -1 if you
+ * aren't able to determine. A failure will almost certainly be fatal
+ * to further use of this stream, so you may not leave this unimplemented.
+ *
+ * \param io The i/o instance to query.
+ * \return Total size, in bytes, of the dataset.
+ */
+ PHYSFS_sint64 (*length)(struct PHYSFS_Io *io);
+
+ /**
+ * \brief Duplicate this i/o instance.
+ *
+ * // !!! FIXME: write me.
+ *
+ * \param io The i/o instance to duplicate.
+ * \return A new value for a stream's (opaque) field, or NULL on error.
+ */
+ struct PHYSFS_Io *(*duplicate)(struct PHYSFS_Io *io);
+
+ /**
+ * \brief Flush resources to media, or wherever.
+ *
+ * This is the chance to report failure for writes that had claimed
+ * success earlier, but still had a chance to actually fail. This method
+ * can be NULL if flushing isn't necessary.
+ *
+ * This function may be called before destroy(), as it can report failure
+ * and destroy() can not. It may be called at other times, too.
+ *
+ * \param io The i/o instance to flush.
+ * \return Zero on error, non-zero on success.
+ */
+ int (*flush)(struct PHYSFS_Io *io);
+
+ /**
+ * \brief Cleanup and deallocate i/o instance.
+ *
+ * Free associated resources, including (opaque) if applicable.
+ *
+ * This function must always succeed: as such, it returns void. The
+ * system may call your flush() method before this. You may report
+ * failure there if necessary. This method may still be called if
+ * flush() fails, in which case you'll have to abandon unflushed data
+ * and other failing conditions and clean up.
+ *
+ * Once this method is called for a given instance, the system will assume
+ * it is unsafe to touch that instance again and will discard any
+ * references to it.
+ *
+ * \param s The i/o instance to destroy.
+ */
+ void (*destroy)(struct PHYSFS_Io *io);
+} PHYSFS_Io;
+
+
+/**
+ * \fn int PHYSFS_mountIo(PHYSFS_Io *io, const char *fname, const char *mountPoint, int appendToPath)
+ * \brief Add an archive, built on a PHYSFS_Io, to the search path.
+ *
+ * \warning Unless you have some special, low-level need, you should be using
+ * PHYSFS_mount() instead of this.
+ *
+ * This function operates just like PHYSFS_mount(), but takes a PHYSFS_Io
+ * instead of a pathname. Behind the scenes, PHYSFS_mount() calls this
+ * function with a physical-filesystem-based PHYSFS_Io.
+ *
+ * (filename) is only used here to optimize archiver selection (if you name it
+ * XXXXX.zip, we might try the ZIP archiver first, for example). It doesn't
+ * need to refer to a real file at all, and can even be NULL. If the filename
+ * isn't helpful, the system will try every archiver until one works or none
+ * of them do.
+ *
+ * (io) must remain until the archive is unmounted. When the archive is
+ * unmounted, the system will call (io)->destroy(io), which will give you
+ * a chance to free your resources.
+ *
+ * If this function fails, (io)->destroy(io) is not called.
+ *
+ * \param io i/o instance for archive to add to the path.
+ * \param fname Filename that can represent this stream. Can be NULL.
+ * \param mountPoint Location in the interpolated tree that this archive
+ * will be "mounted", in platform-independent notation.
+ * NULL or "" is equivalent to "/".
+ * \param appendToPath nonzero to append to search path, zero to prepend.
+ * \return nonzero if added to path, zero on failure (bogus archive, stream
+ * i/o issue, etc). Specifics of the error can be
+ * gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_unmount
+ * \sa PHYSFS_getSearchPath
+ * \sa PHYSFS_getMountPoint
+ */
+PHYSFS_DECL int PHYSFS_mountIo(PHYSFS_Io *io, const char *fname,
+ const char *mountPoint, int appendToPath);
+
+#endif /* SWIG */
+
+/**
+ * \fn int PHYSFS_mountMemory(const void *ptr, PHYSFS_uint64 len, void (*del)(void *), const char *fname, const char *mountPoint, int appendToPath)
+ * \brief Add an archive, contained in a memory buffer, to the search path.
+ *
+ * \warning Unless you have some special, low-level need, you should be using
+ * PHYSFS_mount() instead of this.
+ *
+ * This function operates just like PHYSFS_mount(), but takes a memory buffer
+ * instead of a pathname. This buffer contains all the data of the archive,
+ * and is used instead of a real file in the physical filesystem.
+ *
+ * (filename) is only used here to optimize archiver selection (if you name it
+ * XXXXX.zip, we might try the ZIP archiver first, for example). It doesn't
+ * need to refer to a real file at all, and can even be NULL. If the filename
+ * isn't helpful, the system will try every archiver until one works or none
+ * of them do.
+ *
+ * (ptr) must remain until the archive is unmounted. When the archive is
+ * unmounted, the system will call (del)(ptr), which will notify you that
+ * the system is done with the buffer, and give you a chance to free your
+ * resources. (del) can be NULL, in which case the system will make no
+ * attempt to free the buffer.
+ *
+ * If this function fails, (del) is not called.
+ *
+ * \param ptr Address of the memory buffer containing the archive data.
+ * \param len Size of memory buffer, in bytes.
+ * \param del A callback that triggers upon unmount. Can be NULL.
+ * \param fname Filename that can represent this stream. Can be NULL.
+ * \param mountPoint Location in the interpolated tree that this archive
+ * will be "mounted", in platform-independent notation.
+ * NULL or "" is equivalent to "/".
+ * \param appendToPath nonzero to append to search path, zero to prepend.
+ * \return nonzero if added to path, zero on failure (bogus archive, etc).
+ * Specifics of the error can be gleaned from
+ * PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_unmount
+ * \sa PHYSFS_getSearchPath
+ * \sa PHYSFS_getMountPoint
+ */
+PHYSFS_DECL int PHYSFS_mountMemory(const void *buf, PHYSFS_uint64 len,
+ void (*del)(void *), const char *fname,
+ const char *mountPoint, int appendToPath);
+
+
+/**
+ * \fn int PHYSFS_mountHandle(PHYSFS_File *file, const char *fname, const char *mountPoint, int appendToPath)
+ * \brief Add an archive, contained in a PHYSFS_File handle, to the search path.
+ *
+ * \warning Unless you have some special, low-level need, you should be using
+ * PHYSFS_mount() instead of this.
+ *
+ * \warning Archives-in-archives may be very slow! While a PHYSFS_File can
+ * seek even when the data is compressed, it may do so by rewinding
+ * to the start and decompressing everything before the seek point.
+ * Normal archive usage may do a lot of seeking behind the scenes.
+ * As such, you might find normal archive usage extremely painful
+ * if mounted this way. Plan accordingly: if you, say, have a
+ * self-extracting .zip file, and want to mount something in it,
+ * compress the contents of the inner archive and make sure the outer
+ * .zip file doesn't compress the inner archive too.
+ *
+ * This function operates just like PHYSFS_mount(), but takes a PHYSFS_File
+ * handle instead of a pathname. This handle contains all the data of the
+ * archive, and is used instead of a real file in the physical filesystem.
+ * The PHYSFS_File may be backed by a real file in the physical filesystem,
+ * but isn't necessarily. The most popular use for this is likely to mount
+ * archives stored inside other archives.
+ *
+ * (filename) is only used here to optimize archiver selection (if you name it
+ * XXXXX.zip, we might try the ZIP archiver first, for example). It doesn't
+ * need to refer to a real file at all, and can even be NULL. If the filename
+ * isn't helpful, the system will try every archiver until one works or none
+ * of them do.
+ *
+ * (file) must remain until the archive is unmounted. When the archive is
+ * unmounted, the system will call PHYSFS_close(file). If you need this
+ * handle to survive, you will have to wrap this in a PHYSFS_Io and use
+ * PHYSFS_mountIo() instead.
+ *
+ * If this function fails, PHYSFS_close(file) is not called.
+ *
+ * \param file The PHYSFS_File handle containing archive data.
+ * \param fname Filename that can represent this stream. Can be NULL.
+ * \param mountPoint Location in the interpolated tree that this archive
+ * will be "mounted", in platform-independent notation.
+ * NULL or "" is equivalent to "/".
+ * \param appendToPath nonzero to append to search path, zero to prepend.
+ * \return nonzero if added to path, zero on failure (bogus archive, etc).
+ * Specifics of the error can be gleaned from
+ * PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_unmount
+ * \sa PHYSFS_getSearchPath
+ * \sa PHYSFS_getMountPoint
+ */
+PHYSFS_DECL int PHYSFS_mountHandle(PHYSFS_File *file, const char *fname,
+ const char *mountPoint, int appendToPath);
+
+
+/**
+ * \enum PHYSFS_ErrorCode
+ * \brief Values that represent specific causes of failure.
+ *
+ * Most of the time, you should only concern yourself with whether a given
+ * operation failed or not, but there may be occasions where you plan to
+ * handle a specific failure case gracefully, so we provide specific error
+ * codes.
+ *
+ * Most of these errors are a little vague, and most aren't things you can
+ * fix...if there's a permission error, for example, all you can really do
+ * is pass that information on to the user and let them figure out how to
+ * handle it. In most these cases, your program should only care that it
+ * failed to accomplish its goals, and not care specifically why.
+ *
+ * \sa PHYSFS_getLastErrorCode
+ * \sa PHYSFS_getErrorByCode
+ */
+typedef enum PHYSFS_ErrorCode
+{
+ PHYSFS_ERR_OK, /**< Success; no error. */
+ PHYSFS_ERR_OTHER_ERROR, /**< Error not otherwise covered here. */
+ PHYSFS_ERR_OUT_OF_MEMORY, /**< Memory allocation failed. */
+ PHYSFS_ERR_NOT_INITIALIZED, /**< PhysicsFS is not initialized. */
+ PHYSFS_ERR_IS_INITIALIZED, /**< PhysicsFS is already initialized. */
+ PHYSFS_ERR_ARGV0_IS_NULL, /**< Needed argv[0], but it is NULL. */
+ PHYSFS_ERR_UNSUPPORTED, /**< Operation or feature unsupported. */
+ PHYSFS_ERR_PAST_EOF, /**< Attempted to access past end of file. */
+ PHYSFS_ERR_FILES_STILL_OPEN, /**< Files still open. */
+ PHYSFS_ERR_INVALID_ARGUMENT, /**< Bad parameter passed to an function. */
+ PHYSFS_ERR_NOT_MOUNTED, /**< Requested archive/dir not mounted. */
+ PHYSFS_ERR_NO_SUCH_PATH, /**< No such file, directory, or parent. */
+ PHYSFS_ERR_SYMLINK_FORBIDDEN,/**< Symlink seen when not permitted. */
+ PHYSFS_ERR_NO_WRITE_DIR, /**< No write dir has been specified. */
+ PHYSFS_ERR_OPEN_FOR_READING, /**< Wrote to a file opened for reading. */
+ PHYSFS_ERR_OPEN_FOR_WRITING, /**< Read from a file opened for writing. */
+ PHYSFS_ERR_NOT_A_FILE, /**< Needed a file, got a directory (etc). */
+ PHYSFS_ERR_READ_ONLY, /**< Wrote to a read-only filesystem. */
+ PHYSFS_ERR_CORRUPT, /**< Corrupted data encountered. */
+ PHYSFS_ERR_SYMLINK_LOOP, /**< Infinite symbolic link loop. */
+ PHYSFS_ERR_IO, /**< i/o error (hardware failure, etc). */
+ PHYSFS_ERR_PERMISSION, /**< Permission denied. */
+ PHYSFS_ERR_NO_SPACE, /**< No space (disk full, over quota, etc) */
+ PHYSFS_ERR_BAD_FILENAME, /**< Filename is bogus/insecure. */
+ PHYSFS_ERR_BUSY, /**< Tried to modify a file the OS needs. */
+ PHYSFS_ERR_DIR_NOT_EMPTY, /**< Tried to delete dir with files in it. */
+ PHYSFS_ERR_OS_ERROR /**< Unspecified OS-level error. */
+} PHYSFS_ErrorCode;
+
+
+/**
+ * \fn PHYSFS_ErrorCode PHYSFS_getLastErrorCode(void)
+ * \brief Get machine-readable error information.
+ *
+ * Get the last PhysicsFS error message as an integer value. This will return
+ * PHYSFS_ERR_OK if there's been no error since the last call to this
+ * function. Each thread has a unique error state associated with it, but
+ * each time a new error message is set, it will overwrite the previous one
+ * associated with that thread. It is safe to call this function at anytime,
+ * even before PHYSFS_init().
+ *
+ * PHYSFS_getLastError() and PHYSFS_getLastErrorCode() both reset the same
+ * thread-specific error state. Calling one will wipe out the other's
+ * data. If you need both, call PHYSFS_getLastErrorCode(), then pass that
+ * value to PHYSFS_getErrorByCode().
+ *
+ * Generally, applications should only concern themselves with whether a
+ * given function failed; however, if you require more specifics, you can
+ * try this function to glean information, if there's some specific problem
+ * you're expecting and plan to handle. But with most things that involve
+ * file systems, the best course of action is usually to give up, report the
+ * problem to the user, and let them figure out what should be done about it.
+ * For that, you might prefer PHYSFS_getLastError() instead.
+ *
+ * \return Enumeration value that represents last reported error.
+ *
+ * \sa PHYSFS_getErrorByCode
+ */
+PHYSFS_DECL PHYSFS_ErrorCode PHYSFS_getLastErrorCode(void);
+
+
+/**
+ * \fn const char *PHYSFS_getErrorByCode(PHYSFS_ErrorCode code)
+ * \brief Get human-readable description string for a given error code.
+ *
+ * Get a static string, in UTF-8 format, that represents an English
+ * description of a given error code.
+ *
+ * This string is guaranteed to never change (although we may add new strings
+ * for new error codes in later versions of PhysicsFS), so you can use it
+ * for keying a localization dictionary.
+ *
+ * It is safe to call this function at anytime, even before PHYSFS_init().
+ *
+ * These strings are meant to be passed on directly to the user.
+ * Generally, applications should only concern themselves with whether a
+ * given function failed, but not care about the specifics much.
+ *
+ * Do not attempt to free the returned strings; they are read-only and you
+ * don't own their memory pages.
+ *
+ * \param code Error code to convert to a string.
+ * \return READ ONLY string of requested error message, NULL if this
+ * is not a valid PhysicsFS error code. Always check for NULL if
+ * you might be looking up an error code that didn't exist in an
+ * earlier version of PhysicsFS.
+ *
+ * \sa PHYSFS_getLastErrorCode
+ */
+PHYSFS_DECL const char *PHYSFS_getErrorByCode(PHYSFS_ErrorCode code);
+
+/**
+ * \fn void PHYSFS_setErrorCode(PHYSFS_ErrorCode code)
+ * \brief Set the current thread's error code.
+ *
+ * This lets you set the value that will be returned by the next call to
+ * PHYSFS_getLastErrorCode(). This will replace any existing error code,
+ * whether set by your application or internally by PhysicsFS.
+ *
+ * Error codes are stored per-thread; what you set here will not be
+ * accessible to another thread.
+ *
+ * Any call into PhysicsFS may change the current error code, so any code you
+ * set here is somewhat fragile, and thus you shouldn't build any serious
+ * error reporting framework on this function. The primary goal of this
+ * function is to allow PHYSFS_Io implementations to set the error state,
+ * which generally will be passed back to your application when PhysicsFS
+ * makes a PHYSFS_Io call that fails internally.
+ *
+ * This function doesn't care if the error code is a value known to PhysicsFS
+ * or not (but PHYSFS_getErrorByCode() will return NULL for unknown values).
+ * The value will be reported unmolested by PHYSFS_getLastErrorCode().
+ *
+ * \param code Error code to become the current thread's new error state.
+ *
+ * \sa PHYSFS_getLastErrorCode
+ * \sa PHYSFS_getErrorByCode
+ */
+PHYSFS_DECL void PHYSFS_setErrorCode(PHYSFS_ErrorCode code);
+
+
+/**
+ * \fn const char *PHYSFS_getPrefDir(const char *org, const char *app)
+ * \brief Get the user-and-app-specific path where files can be written.
+ *
+ * Helper function.
+ *
+ * Get the "pref dir". This is meant to be where users can write personal
+ * files (preferences and save games, etc) that are specific to your
+ * application. This directory is unique per user, per application.
+ *
+ * This function will decide the appropriate location in the native filesystem,
+ * create the directory if necessary, and return a string in
+ * platform-dependent notation, suitable for passing to PHYSFS_setWriteDir().
+ *
+ * On Windows, this might look like:
+ * "C:\\Users\\bob\\AppData\\Roaming\\My Company\\My Program Name"
+ *
+ * On Linux, this might look like:
+ * "/home/bob/.local/share/My Program Name"
+ *
+ * On Mac OS X, this might look like:
+ * "/Users/bob/Library/Application Support/My Program Name"
+ *
+ * (etc.)
+ *
+ * You should probably use the pref dir for your write dir, and also put it
+ * near the beginning of your search path. Older versions of PhysicsFS
+ * offered only PHYSFS_getUserDir() and left you to figure out where the
+ * files should go under that tree. This finds the correct location
+ * for whatever platform, which not only changes between operating systems,
+ * but also versions of the same operating system.
+ *
+ * You specify the name of your organization (if it's not a real organization,
+ * your name or an Internet domain you own might do) and the name of your
+ * application. These should be proper names.
+ *
+ * Both the (org) and (app) strings may become part of a directory name, so
+ * please follow these rules:
+ *
+ * - Try to use the same org string (including case-sensitivity) for
+ * all your applications that use this function.
+ * - Always use a unique app string for each one, and make sure it never
+ * changes for an app once you've decided on it.
+ * - Unicode characters are legal, as long as it's UTF-8 encoded, but...
+ * - ...only use letters, numbers, and spaces. Avoid punctuation like
+ * "Game Name 2: Bad Guy's Revenge!" ... "Game Name 2" is sufficient.
+ *
+ * The pointer returned by this function remains valid until you call this
+ * function again, or call PHYSFS_deinit(). This is not necessarily a fast
+ * call, though, so you should call this once at startup and copy the string
+ * if you need it.
+ *
+ * You should assume the path returned by this function is the only safe
+ * place to write files (and that PHYSFS_getUserDir() and PHYSFS_getBaseDir(),
+ * while they might be writable, or even parents of the returned path, aren't
+ * where you should be writing things).
+ *
+ * \param org The name of your organization.
+ * \param app The name of your application.
+ * \return READ ONLY string of user dir in platform-dependent notation. NULL
+ * if there's a problem (creating directory failed, etc).
+ *
+ * \sa PHYSFS_getBaseDir
+ * \sa PHYSFS_getUserDir
+ */
+PHYSFS_DECL const char *PHYSFS_getPrefDir(const char *org, const char *app);
+
+
+/* Everything above this line is part of the PhysicsFS 2.1 API. */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !defined _INCLUDE_PHYSFS_H_ */
+
+/* end of physfs.h ... */
+
diff -r 404ddce27b23 -r c13ebed437cb misc/libphysfs/physfs_byteorder.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/physfs_byteorder.c Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,137 @@
+/**
+ * PhysicsFS; a portable, flexible file i/o abstraction.
+ *
+ * Documentation is in physfs.h. It's verbose, honest. :)
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ * This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+#ifndef PHYSFS_Swap16
+static inline PHYSFS_uint16 PHYSFS_Swap16(PHYSFS_uint16 D)
+{
+ return ((D<<8)|(D>>8));
+}
+#endif
+#ifndef PHYSFS_Swap32
+static inline PHYSFS_uint32 PHYSFS_Swap32(PHYSFS_uint32 D)
+{
+ return ((D<<24)|((D<<8)&0x00FF0000)|((D>>8)&0x0000FF00)|(D>>24));
+}
+#endif
+#ifndef PHYSFS_NO_64BIT_SUPPORT
+#ifndef PHYSFS_Swap64
+static inline PHYSFS_uint64 PHYSFS_Swap64(PHYSFS_uint64 val) {
+ PHYSFS_uint32 hi, lo;
+
+ /* Separate into high and low 32-bit values and swap them */
+ lo = (PHYSFS_uint32)(val&0xFFFFFFFF);
+ val >>= 32;
+ hi = (PHYSFS_uint32)(val&0xFFFFFFFF);
+ val = PHYSFS_Swap32(lo);
+ val <<= 32;
+ val |= PHYSFS_Swap32(hi);
+ return val;
+}
+#endif
+#else
+#ifndef PHYSFS_Swap64
+/* This is mainly to keep compilers from complaining in PHYSFS code.
+ If there is no real 64-bit datatype, then compilers will complain about
+ the fake 64-bit datatype that PHYSFS provides when it compiles user code.
+*/
+#define PHYSFS_Swap64(X) (X)
+#endif
+#endif /* PHYSFS_NO_64BIT_SUPPORT */
+
+
+/* Byteswap item from the specified endianness to the native endianness */
+#if PHYSFS_BYTEORDER == PHYSFS_LIL_ENDIAN
+PHYSFS_uint16 PHYSFS_swapULE16(PHYSFS_uint16 x) { return x; }
+PHYSFS_sint16 PHYSFS_swapSLE16(PHYSFS_sint16 x) { return x; }
+PHYSFS_uint32 PHYSFS_swapULE32(PHYSFS_uint32 x) { return x; }
+PHYSFS_sint32 PHYSFS_swapSLE32(PHYSFS_sint32 x) { return x; }
+PHYSFS_uint64 PHYSFS_swapULE64(PHYSFS_uint64 x) { return x; }
+PHYSFS_sint64 PHYSFS_swapSLE64(PHYSFS_sint64 x) { return x; }
+
+PHYSFS_uint16 PHYSFS_swapUBE16(PHYSFS_uint16 x) { return PHYSFS_Swap16(x); }
+PHYSFS_sint16 PHYSFS_swapSBE16(PHYSFS_sint16 x) { return PHYSFS_Swap16(x); }
+PHYSFS_uint32 PHYSFS_swapUBE32(PHYSFS_uint32 x) { return PHYSFS_Swap32(x); }
+PHYSFS_sint32 PHYSFS_swapSBE32(PHYSFS_sint32 x) { return PHYSFS_Swap32(x); }
+PHYSFS_uint64 PHYSFS_swapUBE64(PHYSFS_uint64 x) { return PHYSFS_Swap64(x); }
+PHYSFS_sint64 PHYSFS_swapSBE64(PHYSFS_sint64 x) { return PHYSFS_Swap64(x); }
+#else
+PHYSFS_uint16 PHYSFS_swapULE16(PHYSFS_uint16 x) { return PHYSFS_Swap16(x); }
+PHYSFS_sint16 PHYSFS_swapSLE16(PHYSFS_sint16 x) { return PHYSFS_Swap16(x); }
+PHYSFS_uint32 PHYSFS_swapULE32(PHYSFS_uint32 x) { return PHYSFS_Swap32(x); }
+PHYSFS_sint32 PHYSFS_swapSLE32(PHYSFS_sint32 x) { return PHYSFS_Swap32(x); }
+PHYSFS_uint64 PHYSFS_swapULE64(PHYSFS_uint64 x) { return PHYSFS_Swap64(x); }
+PHYSFS_sint64 PHYSFS_swapSLE64(PHYSFS_sint64 x) { return PHYSFS_Swap64(x); }
+
+PHYSFS_uint16 PHYSFS_swapUBE16(PHYSFS_uint16 x) { return x; }
+PHYSFS_sint16 PHYSFS_swapSBE16(PHYSFS_sint16 x) { return x; }
+PHYSFS_uint32 PHYSFS_swapUBE32(PHYSFS_uint32 x) { return x; }
+PHYSFS_sint32 PHYSFS_swapSBE32(PHYSFS_sint32 x) { return x; }
+PHYSFS_uint64 PHYSFS_swapUBE64(PHYSFS_uint64 x) { return x; }
+PHYSFS_sint64 PHYSFS_swapSBE64(PHYSFS_sint64 x) { return x; }
+#endif
+
+static inline int readAll(PHYSFS_File *file, void *val, const size_t len)
+{
+ return (PHYSFS_readBytes(file, val, len) == len);
+} /* readAll */
+
+#define PHYSFS_BYTEORDER_READ(datatype, swaptype) \
+ int PHYSFS_read##swaptype(PHYSFS_File *file, PHYSFS_##datatype *val) { \
+ PHYSFS_##datatype in; \
+ BAIL_IF_MACRO(val == NULL, PHYSFS_ERR_INVALID_ARGUMENT, 0); \
+ BAIL_IF_MACRO(!readAll(file, &in, sizeof (in)), ERRPASS, 0); \
+ *val = PHYSFS_swap##swaptype(in); \
+ return 1; \
+ }
+
+PHYSFS_BYTEORDER_READ(sint16, SLE16)
+PHYSFS_BYTEORDER_READ(uint16, ULE16)
+PHYSFS_BYTEORDER_READ(sint16, SBE16)
+PHYSFS_BYTEORDER_READ(uint16, UBE16)
+PHYSFS_BYTEORDER_READ(sint32, SLE32)
+PHYSFS_BYTEORDER_READ(uint32, ULE32)
+PHYSFS_BYTEORDER_READ(sint32, SBE32)
+PHYSFS_BYTEORDER_READ(uint32, UBE32)
+PHYSFS_BYTEORDER_READ(sint64, SLE64)
+PHYSFS_BYTEORDER_READ(uint64, ULE64)
+PHYSFS_BYTEORDER_READ(sint64, SBE64)
+PHYSFS_BYTEORDER_READ(uint64, UBE64)
+
+
+static inline int writeAll(PHYSFS_File *f, const void *val, const size_t len)
+{
+ return (PHYSFS_writeBytes(f, val, len) == len);
+} /* writeAll */
+
+#define PHYSFS_BYTEORDER_WRITE(datatype, swaptype) \
+ int PHYSFS_write##swaptype(PHYSFS_File *file, PHYSFS_##datatype val) { \
+ const PHYSFS_##datatype out = PHYSFS_swap##swaptype(val); \
+ BAIL_IF_MACRO(!writeAll(file, &out, sizeof (out)), ERRPASS, 0); \
+ return 1; \
+ }
+
+PHYSFS_BYTEORDER_WRITE(sint16, SLE16)
+PHYSFS_BYTEORDER_WRITE(uint16, ULE16)
+PHYSFS_BYTEORDER_WRITE(sint16, SBE16)
+PHYSFS_BYTEORDER_WRITE(uint16, UBE16)
+PHYSFS_BYTEORDER_WRITE(sint32, SLE32)
+PHYSFS_BYTEORDER_WRITE(uint32, ULE32)
+PHYSFS_BYTEORDER_WRITE(sint32, SBE32)
+PHYSFS_BYTEORDER_WRITE(uint32, UBE32)
+PHYSFS_BYTEORDER_WRITE(sint64, SLE64)
+PHYSFS_BYTEORDER_WRITE(uint64, ULE64)
+PHYSFS_BYTEORDER_WRITE(sint64, SBE64)
+PHYSFS_BYTEORDER_WRITE(uint64, UBE64)
+
+/* end of physfs_byteorder.c ... */
+
diff -r 404ddce27b23 -r c13ebed437cb misc/libphysfs/physfs_casefolding.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/physfs_casefolding.h Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,2013 @@
+/*
+ * This file is part of PhysicsFS (http://icculus.org/physfs/)
+ *
+ * This data generated by physfs/extras/makecasefoldhashtable.pl ...
+ * Do not manually edit this file!
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ */
+
+#ifndef __PHYSICSFS_INTERNAL__
+#error Do not include this header from your applications.
+#endif
+
+static const CaseFoldMapping case_fold_000[] = {
+ { 0x0202, 0x0203, 0x0000, 0x0000 },
+ { 0x0404, 0x0454, 0x0000, 0x0000 },
+ { 0x1E1E, 0x1E1F, 0x0000, 0x0000 },
+ { 0x2C2C, 0x2C5C, 0x0000, 0x0000 },
+ { 0x10404, 0x1042C, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_001[] = {
+ { 0x0100, 0x0101, 0x0000, 0x0000 },
+ { 0x0405, 0x0455, 0x0000, 0x0000 },
+ { 0x0504, 0x0505, 0x0000, 0x0000 },
+ { 0x2C2D, 0x2C5D, 0x0000, 0x0000 },
+ { 0x10405, 0x1042D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_002[] = {
+ { 0x0200, 0x0201, 0x0000, 0x0000 },
+ { 0x0406, 0x0456, 0x0000, 0x0000 },
+ { 0x1E1C, 0x1E1D, 0x0000, 0x0000 },
+ { 0x1F1D, 0x1F15, 0x0000, 0x0000 },
+ { 0x2C2E, 0x2C5E, 0x0000, 0x0000 },
+ { 0x10406, 0x1042E, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_003[] = {
+ { 0x0102, 0x0103, 0x0000, 0x0000 },
+ { 0x0407, 0x0457, 0x0000, 0x0000 },
+ { 0x0506, 0x0507, 0x0000, 0x0000 },
+ { 0x1F1C, 0x1F14, 0x0000, 0x0000 },
+ { 0x10407, 0x1042F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_004[] = {
+ { 0x0206, 0x0207, 0x0000, 0x0000 },
+ { 0x0400, 0x0450, 0x0000, 0x0000 },
+ { 0x1E1A, 0x1E1B, 0x0000, 0x0000 },
+ { 0x1F1B, 0x1F13, 0x0000, 0x0000 },
+ { 0x2C28, 0x2C58, 0x0000, 0x0000 },
+ { 0x10400, 0x10428, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_005[] = {
+ { 0x0104, 0x0105, 0x0000, 0x0000 },
+ { 0x0401, 0x0451, 0x0000, 0x0000 },
+ { 0x0500, 0x0501, 0x0000, 0x0000 },
+ { 0x1F1A, 0x1F12, 0x0000, 0x0000 },
+ { 0x2C29, 0x2C59, 0x0000, 0x0000 },
+ { 0x10401, 0x10429, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_006[] = {
+ { 0x0204, 0x0205, 0x0000, 0x0000 },
+ { 0x0402, 0x0452, 0x0000, 0x0000 },
+ { 0x1E18, 0x1E19, 0x0000, 0x0000 },
+ { 0x1F19, 0x1F11, 0x0000, 0x0000 },
+ { 0x2C2A, 0x2C5A, 0x0000, 0x0000 },
+ { 0x10402, 0x1042A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_007[] = {
+ { 0x0106, 0x0107, 0x0000, 0x0000 },
+ { 0x0403, 0x0453, 0x0000, 0x0000 },
+ { 0x0502, 0x0503, 0x0000, 0x0000 },
+ { 0x1F18, 0x1F10, 0x0000, 0x0000 },
+ { 0x2126, 0x03C9, 0x0000, 0x0000 },
+ { 0x2C2B, 0x2C5B, 0x0000, 0x0000 },
+ { 0x10403, 0x1042B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_008[] = {
+ { 0x020A, 0x020B, 0x0000, 0x0000 },
+ { 0x040C, 0x045C, 0x0000, 0x0000 },
+ { 0x1E16, 0x1E17, 0x0000, 0x0000 },
+ { 0x2C24, 0x2C54, 0x0000, 0x0000 },
+ { 0x1040C, 0x10434, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_009[] = {
+ { 0x0108, 0x0109, 0x0000, 0x0000 },
+ { 0x040D, 0x045D, 0x0000, 0x0000 },
+ { 0x050C, 0x050D, 0x0000, 0x0000 },
+ { 0x2C25, 0x2C55, 0x0000, 0x0000 },
+ { 0x1040D, 0x10435, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_010[] = {
+ { 0x0208, 0x0209, 0x0000, 0x0000 },
+ { 0x040E, 0x045E, 0x0000, 0x0000 },
+ { 0x1E14, 0x1E15, 0x0000, 0x0000 },
+ { 0x212B, 0x00E5, 0x0000, 0x0000 },
+ { 0x2C26, 0x2C56, 0x0000, 0x0000 },
+ { 0x1040E, 0x10436, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_011[] = {
+ { 0x010A, 0x010B, 0x0000, 0x0000 },
+ { 0x040F, 0x045F, 0x0000, 0x0000 },
+ { 0x050E, 0x050F, 0x0000, 0x0000 },
+ { 0x212A, 0x006B, 0x0000, 0x0000 },
+ { 0x2C27, 0x2C57, 0x0000, 0x0000 },
+ { 0x1040F, 0x10437, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_012[] = {
+ { 0x020E, 0x020F, 0x0000, 0x0000 },
+ { 0x0408, 0x0458, 0x0000, 0x0000 },
+ { 0x1E12, 0x1E13, 0x0000, 0x0000 },
+ { 0x2C20, 0x2C50, 0x0000, 0x0000 },
+ { 0x10408, 0x10430, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_013[] = {
+ { 0x010C, 0x010D, 0x0000, 0x0000 },
+ { 0x0409, 0x0459, 0x0000, 0x0000 },
+ { 0x0508, 0x0509, 0x0000, 0x0000 },
+ { 0x2C21, 0x2C51, 0x0000, 0x0000 },
+ { 0x10409, 0x10431, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_014[] = {
+ { 0x020C, 0x020D, 0x0000, 0x0000 },
+ { 0x040A, 0x045A, 0x0000, 0x0000 },
+ { 0x1E10, 0x1E11, 0x0000, 0x0000 },
+ { 0x2C22, 0x2C52, 0x0000, 0x0000 },
+ { 0x1040A, 0x10432, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_015[] = {
+ { 0x010E, 0x010F, 0x0000, 0x0000 },
+ { 0x040B, 0x045B, 0x0000, 0x0000 },
+ { 0x050A, 0x050B, 0x0000, 0x0000 },
+ { 0x2C23, 0x2C53, 0x0000, 0x0000 },
+ { 0x1040B, 0x10433, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_016[] = {
+ { 0x0212, 0x0213, 0x0000, 0x0000 },
+ { 0x0414, 0x0434, 0x0000, 0x0000 },
+ { 0x1E0E, 0x1E0F, 0x0000, 0x0000 },
+ { 0x1F0F, 0x1F07, 0x0000, 0x0000 },
+ { 0x10414, 0x1043C, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_017[] = {
+ { 0x0110, 0x0111, 0x0000, 0x0000 },
+ { 0x0415, 0x0435, 0x0000, 0x0000 },
+ { 0x1F0E, 0x1F06, 0x0000, 0x0000 },
+ { 0x10415, 0x1043D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_018[] = {
+ { 0x0210, 0x0211, 0x0000, 0x0000 },
+ { 0x0416, 0x0436, 0x0000, 0x0000 },
+ { 0x1E0C, 0x1E0D, 0x0000, 0x0000 },
+ { 0x1F0D, 0x1F05, 0x0000, 0x0000 },
+ { 0x10416, 0x1043E, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_019[] = {
+ { 0x0112, 0x0113, 0x0000, 0x0000 },
+ { 0x0417, 0x0437, 0x0000, 0x0000 },
+ { 0x1F0C, 0x1F04, 0x0000, 0x0000 },
+ { 0x10417, 0x1043F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_020[] = {
+ { 0x0216, 0x0217, 0x0000, 0x0000 },
+ { 0x0410, 0x0430, 0x0000, 0x0000 },
+ { 0x1E0A, 0x1E0B, 0x0000, 0x0000 },
+ { 0x1F0B, 0x1F03, 0x0000, 0x0000 },
+ { 0x10410, 0x10438, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_021[] = {
+ { 0x0114, 0x0115, 0x0000, 0x0000 },
+ { 0x0411, 0x0431, 0x0000, 0x0000 },
+ { 0x1F0A, 0x1F02, 0x0000, 0x0000 },
+ { 0x10411, 0x10439, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_022[] = {
+ { 0x0214, 0x0215, 0x0000, 0x0000 },
+ { 0x0412, 0x0432, 0x0000, 0x0000 },
+ { 0x1E08, 0x1E09, 0x0000, 0x0000 },
+ { 0x1F09, 0x1F01, 0x0000, 0x0000 },
+ { 0x10412, 0x1043A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_023[] = {
+ { 0x0116, 0x0117, 0x0000, 0x0000 },
+ { 0x0413, 0x0433, 0x0000, 0x0000 },
+ { 0x1F08, 0x1F00, 0x0000, 0x0000 },
+ { 0x10413, 0x1043B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_024[] = {
+ { 0x021A, 0x021B, 0x0000, 0x0000 },
+ { 0x041C, 0x043C, 0x0000, 0x0000 },
+ { 0x1E06, 0x1E07, 0x0000, 0x0000 },
+ { 0x1041C, 0x10444, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_025[] = {
+ { 0x0118, 0x0119, 0x0000, 0x0000 },
+ { 0x041D, 0x043D, 0x0000, 0x0000 },
+ { 0x1041D, 0x10445, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_026[] = {
+ { 0x0218, 0x0219, 0x0000, 0x0000 },
+ { 0x041E, 0x043E, 0x0000, 0x0000 },
+ { 0x1E04, 0x1E05, 0x0000, 0x0000 },
+ { 0x1041E, 0x10446, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_027[] = {
+ { 0x011A, 0x011B, 0x0000, 0x0000 },
+ { 0x041F, 0x043F, 0x0000, 0x0000 },
+ { 0x1041F, 0x10447, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_028[] = {
+ { 0x021E, 0x021F, 0x0000, 0x0000 },
+ { 0x0418, 0x0438, 0x0000, 0x0000 },
+ { 0x1E02, 0x1E03, 0x0000, 0x0000 },
+ { 0x10418, 0x10440, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_029[] = {
+ { 0x011C, 0x011D, 0x0000, 0x0000 },
+ { 0x0419, 0x0439, 0x0000, 0x0000 },
+ { 0x10419, 0x10441, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_030[] = {
+ { 0x021C, 0x021D, 0x0000, 0x0000 },
+ { 0x041A, 0x043A, 0x0000, 0x0000 },
+ { 0x1E00, 0x1E01, 0x0000, 0x0000 },
+ { 0x1041A, 0x10442, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_031[] = {
+ { 0x011E, 0x011F, 0x0000, 0x0000 },
+ { 0x041B, 0x043B, 0x0000, 0x0000 },
+ { 0x1041B, 0x10443, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_032[] = {
+ { 0x0222, 0x0223, 0x0000, 0x0000 },
+ { 0x0424, 0x0444, 0x0000, 0x0000 },
+ { 0x1E3E, 0x1E3F, 0x0000, 0x0000 },
+ { 0x1F3F, 0x1F37, 0x0000, 0x0000 },
+ { 0x2C0C, 0x2C3C, 0x0000, 0x0000 },
+ { 0x10424, 0x1044C, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_033[] = {
+ { 0x0120, 0x0121, 0x0000, 0x0000 },
+ { 0x0425, 0x0445, 0x0000, 0x0000 },
+ { 0x1F3E, 0x1F36, 0x0000, 0x0000 },
+ { 0x2C0D, 0x2C3D, 0x0000, 0x0000 },
+ { 0x10425, 0x1044D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_034[] = {
+ { 0x0220, 0x019E, 0x0000, 0x0000 },
+ { 0x0426, 0x0446, 0x0000, 0x0000 },
+ { 0x1E3C, 0x1E3D, 0x0000, 0x0000 },
+ { 0x1F3D, 0x1F35, 0x0000, 0x0000 },
+ { 0x2C0E, 0x2C3E, 0x0000, 0x0000 },
+ { 0x10426, 0x1044E, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_035[] = {
+ { 0x0122, 0x0123, 0x0000, 0x0000 },
+ { 0x0427, 0x0447, 0x0000, 0x0000 },
+ { 0x1F3C, 0x1F34, 0x0000, 0x0000 },
+ { 0x2C0F, 0x2C3F, 0x0000, 0x0000 },
+ { 0x10427, 0x1044F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_036[] = {
+ { 0x0226, 0x0227, 0x0000, 0x0000 },
+ { 0x0420, 0x0440, 0x0000, 0x0000 },
+ { 0x1E3A, 0x1E3B, 0x0000, 0x0000 },
+ { 0x1F3B, 0x1F33, 0x0000, 0x0000 },
+ { 0x2C08, 0x2C38, 0x0000, 0x0000 },
+ { 0x10420, 0x10448, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_037[] = {
+ { 0x0124, 0x0125, 0x0000, 0x0000 },
+ { 0x0421, 0x0441, 0x0000, 0x0000 },
+ { 0x1F3A, 0x1F32, 0x0000, 0x0000 },
+ { 0x2C09, 0x2C39, 0x0000, 0x0000 },
+ { 0x10421, 0x10449, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_038[] = {
+ { 0x0224, 0x0225, 0x0000, 0x0000 },
+ { 0x0422, 0x0442, 0x0000, 0x0000 },
+ { 0x1E38, 0x1E39, 0x0000, 0x0000 },
+ { 0x1F39, 0x1F31, 0x0000, 0x0000 },
+ { 0x2C0A, 0x2C3A, 0x0000, 0x0000 },
+ { 0x10422, 0x1044A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_039[] = {
+ { 0x0126, 0x0127, 0x0000, 0x0000 },
+ { 0x0423, 0x0443, 0x0000, 0x0000 },
+ { 0x1F38, 0x1F30, 0x0000, 0x0000 },
+ { 0x2C0B, 0x2C3B, 0x0000, 0x0000 },
+ { 0x10423, 0x1044B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_040[] = {
+ { 0x022A, 0x022B, 0x0000, 0x0000 },
+ { 0x042C, 0x044C, 0x0000, 0x0000 },
+ { 0x1E36, 0x1E37, 0x0000, 0x0000 },
+ { 0x2C04, 0x2C34, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_041[] = {
+ { 0x0128, 0x0129, 0x0000, 0x0000 },
+ { 0x042D, 0x044D, 0x0000, 0x0000 },
+ { 0x2C05, 0x2C35, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_042[] = {
+ { 0x0228, 0x0229, 0x0000, 0x0000 },
+ { 0x042E, 0x044E, 0x0000, 0x0000 },
+ { 0x1E34, 0x1E35, 0x0000, 0x0000 },
+ { 0x2C06, 0x2C36, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_043[] = {
+ { 0x012A, 0x012B, 0x0000, 0x0000 },
+ { 0x042F, 0x044F, 0x0000, 0x0000 },
+ { 0x2C07, 0x2C37, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_044[] = {
+ { 0x022E, 0x022F, 0x0000, 0x0000 },
+ { 0x0428, 0x0448, 0x0000, 0x0000 },
+ { 0x1E32, 0x1E33, 0x0000, 0x0000 },
+ { 0x2C00, 0x2C30, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_045[] = {
+ { 0x012C, 0x012D, 0x0000, 0x0000 },
+ { 0x0429, 0x0449, 0x0000, 0x0000 },
+ { 0x2C01, 0x2C31, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_046[] = {
+ { 0x022C, 0x022D, 0x0000, 0x0000 },
+ { 0x042A, 0x044A, 0x0000, 0x0000 },
+ { 0x1E30, 0x1E31, 0x0000, 0x0000 },
+ { 0x2C02, 0x2C32, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_047[] = {
+ { 0x012E, 0x012F, 0x0000, 0x0000 },
+ { 0x042B, 0x044B, 0x0000, 0x0000 },
+ { 0x2C03, 0x2C33, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_048[] = {
+ { 0x0232, 0x0233, 0x0000, 0x0000 },
+ { 0x0535, 0x0565, 0x0000, 0x0000 },
+ { 0x1E2E, 0x1E2F, 0x0000, 0x0000 },
+ { 0x1F2F, 0x1F27, 0x0000, 0x0000 },
+ { 0x2C1C, 0x2C4C, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_049[] = {
+ { 0x0130, 0x0069, 0x0307, 0x0000 },
+ { 0x0534, 0x0564, 0x0000, 0x0000 },
+ { 0x1F2E, 0x1F26, 0x0000, 0x0000 },
+ { 0x2C1D, 0x2C4D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_050[] = {
+ { 0x0230, 0x0231, 0x0000, 0x0000 },
+ { 0x0537, 0x0567, 0x0000, 0x0000 },
+ { 0x1E2C, 0x1E2D, 0x0000, 0x0000 },
+ { 0x1F2D, 0x1F25, 0x0000, 0x0000 },
+ { 0x2C1E, 0x2C4E, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_051[] = {
+ { 0x0132, 0x0133, 0x0000, 0x0000 },
+ { 0x0536, 0x0566, 0x0000, 0x0000 },
+ { 0x1F2C, 0x1F24, 0x0000, 0x0000 },
+ { 0x2C1F, 0x2C4F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_052[] = {
+ { 0x0531, 0x0561, 0x0000, 0x0000 },
+ { 0x1E2A, 0x1E2B, 0x0000, 0x0000 },
+ { 0x1F2B, 0x1F23, 0x0000, 0x0000 },
+ { 0x2C18, 0x2C48, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_053[] = {
+ { 0x0134, 0x0135, 0x0000, 0x0000 },
+ { 0x1F2A, 0x1F22, 0x0000, 0x0000 },
+ { 0x2C19, 0x2C49, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_054[] = {
+ { 0x0533, 0x0563, 0x0000, 0x0000 },
+ { 0x1E28, 0x1E29, 0x0000, 0x0000 },
+ { 0x1F29, 0x1F21, 0x0000, 0x0000 },
+ { 0x2C1A, 0x2C4A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_055[] = {
+ { 0x0136, 0x0137, 0x0000, 0x0000 },
+ { 0x0532, 0x0562, 0x0000, 0x0000 },
+ { 0x1F28, 0x1F20, 0x0000, 0x0000 },
+ { 0x2C1B, 0x2C4B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_056[] = {
+ { 0x0139, 0x013A, 0x0000, 0x0000 },
+ { 0x053D, 0x056D, 0x0000, 0x0000 },
+ { 0x1E26, 0x1E27, 0x0000, 0x0000 },
+ { 0x2C14, 0x2C44, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_057[] = {
+ { 0x023B, 0x023C, 0x0000, 0x0000 },
+ { 0x053C, 0x056C, 0x0000, 0x0000 },
+ { 0x2C15, 0x2C45, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_058[] = {
+ { 0x013B, 0x013C, 0x0000, 0x0000 },
+ { 0x053F, 0x056F, 0x0000, 0x0000 },
+ { 0x1E24, 0x1E25, 0x0000, 0x0000 },
+ { 0x2C16, 0x2C46, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_059[] = {
+ { 0x053E, 0x056E, 0x0000, 0x0000 },
+ { 0x2C17, 0x2C47, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_060[] = {
+ { 0x013D, 0x013E, 0x0000, 0x0000 },
+ { 0x0539, 0x0569, 0x0000, 0x0000 },
+ { 0x1E22, 0x1E23, 0x0000, 0x0000 },
+ { 0x2C10, 0x2C40, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_061[] = {
+ { 0x0538, 0x0568, 0x0000, 0x0000 },
+ { 0x2C11, 0x2C41, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_062[] = {
+ { 0x013F, 0x0140, 0x0000, 0x0000 },
+ { 0x053B, 0x056B, 0x0000, 0x0000 },
+ { 0x1E20, 0x1E21, 0x0000, 0x0000 },
+ { 0x2C12, 0x2C42, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_063[] = {
+ { 0x023D, 0x019A, 0x0000, 0x0000 },
+ { 0x053A, 0x056A, 0x0000, 0x0000 },
+ { 0x2C13, 0x2C43, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_064[] = {
+ { 0x0141, 0x0142, 0x0000, 0x0000 },
+ { 0x0545, 0x0575, 0x0000, 0x0000 },
+ { 0x1E5E, 0x1E5F, 0x0000, 0x0000 },
+ { 0x1F5F, 0x1F57, 0x0000, 0x0000 },
+ { 0x2161, 0x2171, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_065[] = {
+ { 0x0041, 0x0061, 0x0000, 0x0000 },
+ { 0x0544, 0x0574, 0x0000, 0x0000 },
+ { 0x2160, 0x2170, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_066[] = {
+ { 0x0042, 0x0062, 0x0000, 0x0000 },
+ { 0x0143, 0x0144, 0x0000, 0x0000 },
+ { 0x0547, 0x0577, 0x0000, 0x0000 },
+ { 0x1E5C, 0x1E5D, 0x0000, 0x0000 },
+ { 0x1F5D, 0x1F55, 0x0000, 0x0000 },
+ { 0x2163, 0x2173, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_067[] = {
+ { 0x0043, 0x0063, 0x0000, 0x0000 },
+ { 0x0241, 0x0294, 0x0000, 0x0000 },
+ { 0x0546, 0x0576, 0x0000, 0x0000 },
+ { 0x2162, 0x2172, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_068[] = {
+ { 0x0044, 0x0064, 0x0000, 0x0000 },
+ { 0x0145, 0x0146, 0x0000, 0x0000 },
+ { 0x0541, 0x0571, 0x0000, 0x0000 },
+ { 0x1E5A, 0x1E5B, 0x0000, 0x0000 },
+ { 0x1F5B, 0x1F53, 0x0000, 0x0000 },
+ { 0x2165, 0x2175, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_069[] = {
+ { 0x0045, 0x0065, 0x0000, 0x0000 },
+ { 0x0540, 0x0570, 0x0000, 0x0000 },
+ { 0x2164, 0x2174, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_070[] = {
+ { 0x0046, 0x0066, 0x0000, 0x0000 },
+ { 0x0147, 0x0148, 0x0000, 0x0000 },
+ { 0x0345, 0x03B9, 0x0000, 0x0000 },
+ { 0x0543, 0x0573, 0x0000, 0x0000 },
+ { 0x1E58, 0x1E59, 0x0000, 0x0000 },
+ { 0x1F59, 0x1F51, 0x0000, 0x0000 },
+ { 0x2167, 0x2177, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_071[] = {
+ { 0x0047, 0x0067, 0x0000, 0x0000 },
+ { 0x0542, 0x0572, 0x0000, 0x0000 },
+ { 0x2166, 0x2176, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_072[] = {
+ { 0x0048, 0x0068, 0x0000, 0x0000 },
+ { 0x0149, 0x02BC, 0x006E, 0x0000 },
+ { 0x054D, 0x057D, 0x0000, 0x0000 },
+ { 0x1E56, 0x1E57, 0x0000, 0x0000 },
+ { 0x2169, 0x2179, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_073[] = {
+ { 0x0049, 0x0069, 0x0000, 0x0000 },
+ { 0x054C, 0x057C, 0x0000, 0x0000 },
+ { 0x1F56, 0x03C5, 0x0313, 0x0342 },
+ { 0x2168, 0x2178, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_074[] = {
+ { 0x004A, 0x006A, 0x0000, 0x0000 },
+ { 0x054F, 0x057F, 0x0000, 0x0000 },
+ { 0x1E54, 0x1E55, 0x0000, 0x0000 },
+ { 0x216B, 0x217B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_075[] = {
+ { 0x004B, 0x006B, 0x0000, 0x0000 },
+ { 0x014A, 0x014B, 0x0000, 0x0000 },
+ { 0x054E, 0x057E, 0x0000, 0x0000 },
+ { 0x1F54, 0x03C5, 0x0313, 0x0301 },
+ { 0x216A, 0x217A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_076[] = {
+ { 0x004C, 0x006C, 0x0000, 0x0000 },
+ { 0x0549, 0x0579, 0x0000, 0x0000 },
+ { 0x1E52, 0x1E53, 0x0000, 0x0000 },
+ { 0x216D, 0x217D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_077[] = {
+ { 0x004D, 0x006D, 0x0000, 0x0000 },
+ { 0x014C, 0x014D, 0x0000, 0x0000 },
+ { 0x0548, 0x0578, 0x0000, 0x0000 },
+ { 0x1F52, 0x03C5, 0x0313, 0x0300 },
+ { 0x216C, 0x217C, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_078[] = {
+ { 0x004E, 0x006E, 0x0000, 0x0000 },
+ { 0x054B, 0x057B, 0x0000, 0x0000 },
+ { 0x1E50, 0x1E51, 0x0000, 0x0000 },
+ { 0x216F, 0x217F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_079[] = {
+ { 0x004F, 0x006F, 0x0000, 0x0000 },
+ { 0x014E, 0x014F, 0x0000, 0x0000 },
+ { 0x054A, 0x057A, 0x0000, 0x0000 },
+ { 0x1F50, 0x03C5, 0x0313, 0x0000 },
+ { 0x216E, 0x217E, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_080[] = {
+ { 0x0050, 0x0070, 0x0000, 0x0000 },
+ { 0x0555, 0x0585, 0x0000, 0x0000 },
+ { 0x1E4E, 0x1E4F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_081[] = {
+ { 0x0051, 0x0071, 0x0000, 0x0000 },
+ { 0x0150, 0x0151, 0x0000, 0x0000 },
+ { 0x0554, 0x0584, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_082[] = {
+ { 0x0052, 0x0072, 0x0000, 0x0000 },
+ { 0x1E4C, 0x1E4D, 0x0000, 0x0000 },
+ { 0x1F4D, 0x1F45, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_083[] = {
+ { 0x0053, 0x0073, 0x0000, 0x0000 },
+ { 0x0152, 0x0153, 0x0000, 0x0000 },
+ { 0x0556, 0x0586, 0x0000, 0x0000 },
+ { 0x1F4C, 0x1F44, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_084[] = {
+ { 0x0054, 0x0074, 0x0000, 0x0000 },
+ { 0x0551, 0x0581, 0x0000, 0x0000 },
+ { 0x1E4A, 0x1E4B, 0x0000, 0x0000 },
+ { 0x1F4B, 0x1F43, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_085[] = {
+ { 0x0055, 0x0075, 0x0000, 0x0000 },
+ { 0x0154, 0x0155, 0x0000, 0x0000 },
+ { 0x0550, 0x0580, 0x0000, 0x0000 },
+ { 0x1F4A, 0x1F42, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_086[] = {
+ { 0x0056, 0x0076, 0x0000, 0x0000 },
+ { 0x0553, 0x0583, 0x0000, 0x0000 },
+ { 0x1E48, 0x1E49, 0x0000, 0x0000 },
+ { 0x1F49, 0x1F41, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_087[] = {
+ { 0x0057, 0x0077, 0x0000, 0x0000 },
+ { 0x0156, 0x0157, 0x0000, 0x0000 },
+ { 0x0552, 0x0582, 0x0000, 0x0000 },
+ { 0x1F48, 0x1F40, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_088[] = {
+ { 0x0058, 0x0078, 0x0000, 0x0000 },
+ { 0x1E46, 0x1E47, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_089[] = {
+ { 0x0059, 0x0079, 0x0000, 0x0000 },
+ { 0x0158, 0x0159, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_090[] = {
+ { 0x005A, 0x007A, 0x0000, 0x0000 },
+ { 0x1E44, 0x1E45, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_091[] = {
+ { 0x015A, 0x015B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_092[] = {
+ { 0x1E42, 0x1E43, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_093[] = {
+ { 0x015C, 0x015D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_094[] = {
+ { 0x1E40, 0x1E41, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_095[] = {
+ { 0x015E, 0x015F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_096[] = {
+ { 0x0464, 0x0465, 0x0000, 0x0000 },
+ { 0x1E7E, 0x1E7F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_097[] = {
+ { 0x0160, 0x0161, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_098[] = {
+ { 0x0466, 0x0467, 0x0000, 0x0000 },
+ { 0x1E7C, 0x1E7D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_099[] = {
+ { 0x0162, 0x0163, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_100[] = {
+ { 0x0460, 0x0461, 0x0000, 0x0000 },
+ { 0x1E7A, 0x1E7B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_101[] = {
+ { 0x0164, 0x0165, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_102[] = {
+ { 0x0462, 0x0463, 0x0000, 0x0000 },
+ { 0x1E78, 0x1E79, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_103[] = {
+ { 0x0166, 0x0167, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_104[] = {
+ { 0x046C, 0x046D, 0x0000, 0x0000 },
+ { 0x1E76, 0x1E77, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_105[] = {
+ { 0x0168, 0x0169, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_106[] = {
+ { 0x046E, 0x046F, 0x0000, 0x0000 },
+ { 0x1E74, 0x1E75, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_107[] = {
+ { 0x016A, 0x016B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_108[] = {
+ { 0x0468, 0x0469, 0x0000, 0x0000 },
+ { 0x1E72, 0x1E73, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_109[] = {
+ { 0x016C, 0x016D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_110[] = {
+ { 0x046A, 0x046B, 0x0000, 0x0000 },
+ { 0x1E70, 0x1E71, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_111[] = {
+ { 0x016E, 0x016F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_112[] = {
+ { 0x0474, 0x0475, 0x0000, 0x0000 },
+ { 0x1E6E, 0x1E6F, 0x0000, 0x0000 },
+ { 0x1F6F, 0x1F67, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_113[] = {
+ { 0x0170, 0x0171, 0x0000, 0x0000 },
+ { 0x1F6E, 0x1F66, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_114[] = {
+ { 0x0476, 0x0477, 0x0000, 0x0000 },
+ { 0x1E6C, 0x1E6D, 0x0000, 0x0000 },
+ { 0x1F6D, 0x1F65, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_115[] = {
+ { 0x0172, 0x0173, 0x0000, 0x0000 },
+ { 0x1F6C, 0x1F64, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_116[] = {
+ { 0x0470, 0x0471, 0x0000, 0x0000 },
+ { 0x1E6A, 0x1E6B, 0x0000, 0x0000 },
+ { 0x1F6B, 0x1F63, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_117[] = {
+ { 0x0174, 0x0175, 0x0000, 0x0000 },
+ { 0x1F6A, 0x1F62, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_118[] = {
+ { 0x0472, 0x0473, 0x0000, 0x0000 },
+ { 0x1E68, 0x1E69, 0x0000, 0x0000 },
+ { 0x1F69, 0x1F61, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_119[] = {
+ { 0x0176, 0x0177, 0x0000, 0x0000 },
+ { 0x1F68, 0x1F60, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_120[] = {
+ { 0x0179, 0x017A, 0x0000, 0x0000 },
+ { 0x047C, 0x047D, 0x0000, 0x0000 },
+ { 0x1E66, 0x1E67, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_121[] = {
+ { 0x0178, 0x00FF, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_122[] = {
+ { 0x017B, 0x017C, 0x0000, 0x0000 },
+ { 0x047E, 0x047F, 0x0000, 0x0000 },
+ { 0x1E64, 0x1E65, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_124[] = {
+ { 0x017D, 0x017E, 0x0000, 0x0000 },
+ { 0x0478, 0x0479, 0x0000, 0x0000 },
+ { 0x1E62, 0x1E63, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_126[] = {
+ { 0x017F, 0x0073, 0x0000, 0x0000 },
+ { 0x047A, 0x047B, 0x0000, 0x0000 },
+ { 0x1E60, 0x1E61, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_128[] = {
+ { 0x0181, 0x0253, 0x0000, 0x0000 },
+ { 0x1F9F, 0x1F27, 0x03B9, 0x0000 },
+ { 0x2CAC, 0x2CAD, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_129[] = {
+ { 0x1F9E, 0x1F26, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_130[] = {
+ { 0x0587, 0x0565, 0x0582, 0x0000 },
+ { 0x1F9D, 0x1F25, 0x03B9, 0x0000 },
+ { 0x2CAE, 0x2CAF, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_131[] = {
+ { 0x0182, 0x0183, 0x0000, 0x0000 },
+ { 0x1F9C, 0x1F24, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_132[] = {
+ { 0x0480, 0x0481, 0x0000, 0x0000 },
+ { 0x1E9A, 0x0061, 0x02BE, 0x0000 },
+ { 0x1F9B, 0x1F23, 0x03B9, 0x0000 },
+ { 0x2CA8, 0x2CA9, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_133[] = {
+ { 0x0184, 0x0185, 0x0000, 0x0000 },
+ { 0x0386, 0x03AC, 0x0000, 0x0000 },
+ { 0x1E9B, 0x1E61, 0x0000, 0x0000 },
+ { 0x1F9A, 0x1F22, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_134[] = {
+ { 0x0187, 0x0188, 0x0000, 0x0000 },
+ { 0x1E98, 0x0077, 0x030A, 0x0000 },
+ { 0x1F99, 0x1F21, 0x03B9, 0x0000 },
+ { 0x2CAA, 0x2CAB, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_135[] = {
+ { 0x0186, 0x0254, 0x0000, 0x0000 },
+ { 0x1E99, 0x0079, 0x030A, 0x0000 },
+ { 0x1F98, 0x1F20, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_136[] = {
+ { 0x0189, 0x0256, 0x0000, 0x0000 },
+ { 0x048C, 0x048D, 0x0000, 0x0000 },
+ { 0x1E96, 0x0068, 0x0331, 0x0000 },
+ { 0x1F97, 0x1F27, 0x03B9, 0x0000 },
+ { 0x2CA4, 0x2CA5, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_137[] = {
+ { 0x038A, 0x03AF, 0x0000, 0x0000 },
+ { 0x1E97, 0x0074, 0x0308, 0x0000 },
+ { 0x1F96, 0x1F26, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_138[] = {
+ { 0x018B, 0x018C, 0x0000, 0x0000 },
+ { 0x0389, 0x03AE, 0x0000, 0x0000 },
+ { 0x048E, 0x048F, 0x0000, 0x0000 },
+ { 0x1E94, 0x1E95, 0x0000, 0x0000 },
+ { 0x1F95, 0x1F25, 0x03B9, 0x0000 },
+ { 0x2CA6, 0x2CA7, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_139[] = {
+ { 0x018A, 0x0257, 0x0000, 0x0000 },
+ { 0x0388, 0x03AD, 0x0000, 0x0000 },
+ { 0x1F94, 0x1F24, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_140[] = {
+ { 0x038F, 0x03CE, 0x0000, 0x0000 },
+ { 0x1E92, 0x1E93, 0x0000, 0x0000 },
+ { 0x1F93, 0x1F23, 0x03B9, 0x0000 },
+ { 0x2CA0, 0x2CA1, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_141[] = {
+ { 0x038E, 0x03CD, 0x0000, 0x0000 },
+ { 0x1F92, 0x1F22, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_142[] = {
+ { 0x018F, 0x0259, 0x0000, 0x0000 },
+ { 0x048A, 0x048B, 0x0000, 0x0000 },
+ { 0x1E90, 0x1E91, 0x0000, 0x0000 },
+ { 0x1F91, 0x1F21, 0x03B9, 0x0000 },
+ { 0x2CA2, 0x2CA3, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_143[] = {
+ { 0x018E, 0x01DD, 0x0000, 0x0000 },
+ { 0x038C, 0x03CC, 0x0000, 0x0000 },
+ { 0x1F90, 0x1F20, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_144[] = {
+ { 0x0191, 0x0192, 0x0000, 0x0000 },
+ { 0x0393, 0x03B3, 0x0000, 0x0000 },
+ { 0x0494, 0x0495, 0x0000, 0x0000 },
+ { 0x1E8E, 0x1E8F, 0x0000, 0x0000 },
+ { 0x1F8F, 0x1F07, 0x03B9, 0x0000 },
+ { 0x2CBC, 0x2CBD, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_145[] = {
+ { 0x0190, 0x025B, 0x0000, 0x0000 },
+ { 0x0392, 0x03B2, 0x0000, 0x0000 },
+ { 0x1F8E, 0x1F06, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_146[] = {
+ { 0x0193, 0x0260, 0x0000, 0x0000 },
+ { 0x0391, 0x03B1, 0x0000, 0x0000 },
+ { 0x0496, 0x0497, 0x0000, 0x0000 },
+ { 0x1E8C, 0x1E8D, 0x0000, 0x0000 },
+ { 0x1F8D, 0x1F05, 0x03B9, 0x0000 },
+ { 0x24B6, 0x24D0, 0x0000, 0x0000 },
+ { 0x2CBE, 0x2CBF, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_147[] = {
+ { 0x0390, 0x03B9, 0x0308, 0x0301 },
+ { 0x1F8C, 0x1F04, 0x03B9, 0x0000 },
+ { 0x24B7, 0x24D1, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_148[] = {
+ { 0x0397, 0x03B7, 0x0000, 0x0000 },
+ { 0x0490, 0x0491, 0x0000, 0x0000 },
+ { 0x1E8A, 0x1E8B, 0x0000, 0x0000 },
+ { 0x1F8B, 0x1F03, 0x03B9, 0x0000 },
+ { 0x2CB8, 0x2CB9, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_149[] = {
+ { 0x0194, 0x0263, 0x0000, 0x0000 },
+ { 0x0396, 0x03B6, 0x0000, 0x0000 },
+ { 0x1F8A, 0x1F02, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_150[] = {
+ { 0x0197, 0x0268, 0x0000, 0x0000 },
+ { 0x0395, 0x03B5, 0x0000, 0x0000 },
+ { 0x0492, 0x0493, 0x0000, 0x0000 },
+ { 0x1E88, 0x1E89, 0x0000, 0x0000 },
+ { 0x1F89, 0x1F01, 0x03B9, 0x0000 },
+ { 0x2CBA, 0x2CBB, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_151[] = {
+ { 0x0196, 0x0269, 0x0000, 0x0000 },
+ { 0x0394, 0x03B4, 0x0000, 0x0000 },
+ { 0x1F88, 0x1F00, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_152[] = {
+ { 0x039B, 0x03BB, 0x0000, 0x0000 },
+ { 0x049C, 0x049D, 0x0000, 0x0000 },
+ { 0x1E86, 0x1E87, 0x0000, 0x0000 },
+ { 0x1F87, 0x1F07, 0x03B9, 0x0000 },
+ { 0x24BC, 0x24D6, 0x0000, 0x0000 },
+ { 0x2CB4, 0x2CB5, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_153[] = {
+ { 0x0198, 0x0199, 0x0000, 0x0000 },
+ { 0x039A, 0x03BA, 0x0000, 0x0000 },
+ { 0x1F86, 0x1F06, 0x03B9, 0x0000 },
+ { 0x24BD, 0x24D7, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_154[] = {
+ { 0x0399, 0x03B9, 0x0000, 0x0000 },
+ { 0x049E, 0x049F, 0x0000, 0x0000 },
+ { 0x1E84, 0x1E85, 0x0000, 0x0000 },
+ { 0x1F85, 0x1F05, 0x03B9, 0x0000 },
+ { 0x24BE, 0x24D8, 0x0000, 0x0000 },
+ { 0x2CB6, 0x2CB7, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_155[] = {
+ { 0x0398, 0x03B8, 0x0000, 0x0000 },
+ { 0x1F84, 0x1F04, 0x03B9, 0x0000 },
+ { 0x24BF, 0x24D9, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_156[] = {
+ { 0x019D, 0x0272, 0x0000, 0x0000 },
+ { 0x039F, 0x03BF, 0x0000, 0x0000 },
+ { 0x0498, 0x0499, 0x0000, 0x0000 },
+ { 0x1E82, 0x1E83, 0x0000, 0x0000 },
+ { 0x1F83, 0x1F03, 0x03B9, 0x0000 },
+ { 0x24B8, 0x24D2, 0x0000, 0x0000 },
+ { 0x2CB0, 0x2CB1, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_157[] = {
+ { 0x019C, 0x026F, 0x0000, 0x0000 },
+ { 0x039E, 0x03BE, 0x0000, 0x0000 },
+ { 0x1F82, 0x1F02, 0x03B9, 0x0000 },
+ { 0x24B9, 0x24D3, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_158[] = {
+ { 0x019F, 0x0275, 0x0000, 0x0000 },
+ { 0x039D, 0x03BD, 0x0000, 0x0000 },
+ { 0x049A, 0x049B, 0x0000, 0x0000 },
+ { 0x1E80, 0x1E81, 0x0000, 0x0000 },
+ { 0x1F81, 0x1F01, 0x03B9, 0x0000 },
+ { 0x24BA, 0x24D4, 0x0000, 0x0000 },
+ { 0x2CB2, 0x2CB3, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_159[] = {
+ { 0x039C, 0x03BC, 0x0000, 0x0000 },
+ { 0x1F80, 0x1F00, 0x03B9, 0x0000 },
+ { 0x24BB, 0x24D5, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_160[] = {
+ { 0x03A3, 0x03C3, 0x0000, 0x0000 },
+ { 0x04A4, 0x04A5, 0x0000, 0x0000 },
+ { 0x10B0, 0x2D10, 0x0000, 0x0000 },
+ { 0x1EBE, 0x1EBF, 0x0000, 0x0000 },
+ { 0x2C8C, 0x2C8D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_161[] = {
+ { 0x01A0, 0x01A1, 0x0000, 0x0000 },
+ { 0x10B1, 0x2D11, 0x0000, 0x0000 },
+ { 0x1FBE, 0x03B9, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_162[] = {
+ { 0x03A1, 0x03C1, 0x0000, 0x0000 },
+ { 0x04A6, 0x04A7, 0x0000, 0x0000 },
+ { 0x10B2, 0x2D12, 0x0000, 0x0000 },
+ { 0x1EBC, 0x1EBD, 0x0000, 0x0000 },
+ { 0x2C8E, 0x2C8F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_163[] = {
+ { 0x01A2, 0x01A3, 0x0000, 0x0000 },
+ { 0x03A0, 0x03C0, 0x0000, 0x0000 },
+ { 0x10B3, 0x2D13, 0x0000, 0x0000 },
+ { 0x1FBC, 0x03B1, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_164[] = {
+ { 0x03A7, 0x03C7, 0x0000, 0x0000 },
+ { 0x04A0, 0x04A1, 0x0000, 0x0000 },
+ { 0x10B4, 0x2D14, 0x0000, 0x0000 },
+ { 0x1EBA, 0x1EBB, 0x0000, 0x0000 },
+ { 0x1FBB, 0x1F71, 0x0000, 0x0000 },
+ { 0x2C88, 0x2C89, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_165[] = {
+ { 0x01A4, 0x01A5, 0x0000, 0x0000 },
+ { 0x03A6, 0x03C6, 0x0000, 0x0000 },
+ { 0x10B5, 0x2D15, 0x0000, 0x0000 },
+ { 0x1FBA, 0x1F70, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_166[] = {
+ { 0x01A7, 0x01A8, 0x0000, 0x0000 },
+ { 0x03A5, 0x03C5, 0x0000, 0x0000 },
+ { 0x04A2, 0x04A3, 0x0000, 0x0000 },
+ { 0x10B6, 0x2D16, 0x0000, 0x0000 },
+ { 0x1EB8, 0x1EB9, 0x0000, 0x0000 },
+ { 0x1FB9, 0x1FB1, 0x0000, 0x0000 },
+ { 0x2C8A, 0x2C8B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_167[] = {
+ { 0x01A6, 0x0280, 0x0000, 0x0000 },
+ { 0x03A4, 0x03C4, 0x0000, 0x0000 },
+ { 0x10B7, 0x2D17, 0x0000, 0x0000 },
+ { 0x1FB8, 0x1FB0, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_168[] = {
+ { 0x01A9, 0x0283, 0x0000, 0x0000 },
+ { 0x03AB, 0x03CB, 0x0000, 0x0000 },
+ { 0x04AC, 0x04AD, 0x0000, 0x0000 },
+ { 0x10B8, 0x2D18, 0x0000, 0x0000 },
+ { 0x1EB6, 0x1EB7, 0x0000, 0x0000 },
+ { 0x1FB7, 0x03B1, 0x0342, 0x03B9 },
+ { 0x2C84, 0x2C85, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_169[] = {
+ { 0x03AA, 0x03CA, 0x0000, 0x0000 },
+ { 0x10B9, 0x2D19, 0x0000, 0x0000 },
+ { 0x1FB6, 0x03B1, 0x0342, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_170[] = {
+ { 0x03A9, 0x03C9, 0x0000, 0x0000 },
+ { 0x04AE, 0x04AF, 0x0000, 0x0000 },
+ { 0x10BA, 0x2D1A, 0x0000, 0x0000 },
+ { 0x1EB4, 0x1EB5, 0x0000, 0x0000 },
+ { 0x2C86, 0x2C87, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_171[] = {
+ { 0x03A8, 0x03C8, 0x0000, 0x0000 },
+ { 0x10BB, 0x2D1B, 0x0000, 0x0000 },
+ { 0x1FB4, 0x03AC, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_172[] = {
+ { 0x04A8, 0x04A9, 0x0000, 0x0000 },
+ { 0x10BC, 0x2D1C, 0x0000, 0x0000 },
+ { 0x1EB2, 0x1EB3, 0x0000, 0x0000 },
+ { 0x1FB3, 0x03B1, 0x03B9, 0x0000 },
+ { 0x2C80, 0x2C81, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_173[] = {
+ { 0x01AC, 0x01AD, 0x0000, 0x0000 },
+ { 0x10BD, 0x2D1D, 0x0000, 0x0000 },
+ { 0x1FB2, 0x1F70, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_174[] = {
+ { 0x01AF, 0x01B0, 0x0000, 0x0000 },
+ { 0x04AA, 0x04AB, 0x0000, 0x0000 },
+ { 0x10BE, 0x2D1E, 0x0000, 0x0000 },
+ { 0x1EB0, 0x1EB1, 0x0000, 0x0000 },
+ { 0x2C82, 0x2C83, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_175[] = {
+ { 0x01AE, 0x0288, 0x0000, 0x0000 },
+ { 0x10BF, 0x2D1F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_176[] = {
+ { 0x01B1, 0x028A, 0x0000, 0x0000 },
+ { 0x04B4, 0x04B5, 0x0000, 0x0000 },
+ { 0x10A0, 0x2D00, 0x0000, 0x0000 },
+ { 0x1EAE, 0x1EAF, 0x0000, 0x0000 },
+ { 0x1FAF, 0x1F67, 0x03B9, 0x0000 },
+ { 0x2C9C, 0x2C9D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_177[] = {
+ { 0x10A1, 0x2D01, 0x0000, 0x0000 },
+ { 0x1FAE, 0x1F66, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_178[] = {
+ { 0x01B3, 0x01B4, 0x0000, 0x0000 },
+ { 0x04B6, 0x04B7, 0x0000, 0x0000 },
+ { 0x10A2, 0x2D02, 0x0000, 0x0000 },
+ { 0x1EAC, 0x1EAD, 0x0000, 0x0000 },
+ { 0x1FAD, 0x1F65, 0x03B9, 0x0000 },
+ { 0x2C9E, 0x2C9F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_179[] = {
+ { 0x01B2, 0x028B, 0x0000, 0x0000 },
+ { 0x03B0, 0x03C5, 0x0308, 0x0301 },
+ { 0x10A3, 0x2D03, 0x0000, 0x0000 },
+ { 0x1FAC, 0x1F64, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_180[] = {
+ { 0x01B5, 0x01B6, 0x0000, 0x0000 },
+ { 0x04B0, 0x04B1, 0x0000, 0x0000 },
+ { 0x10A4, 0x2D04, 0x0000, 0x0000 },
+ { 0x1EAA, 0x1EAB, 0x0000, 0x0000 },
+ { 0x1FAB, 0x1F63, 0x03B9, 0x0000 },
+ { 0x2C98, 0x2C99, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_181[] = {
+ { 0x00B5, 0x03BC, 0x0000, 0x0000 },
+ { 0x10A5, 0x2D05, 0x0000, 0x0000 },
+ { 0x1FAA, 0x1F62, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_182[] = {
+ { 0x01B7, 0x0292, 0x0000, 0x0000 },
+ { 0x04B2, 0x04B3, 0x0000, 0x0000 },
+ { 0x10A6, 0x2D06, 0x0000, 0x0000 },
+ { 0x1EA8, 0x1EA9, 0x0000, 0x0000 },
+ { 0x1FA9, 0x1F61, 0x03B9, 0x0000 },
+ { 0x2C9A, 0x2C9B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_183[] = {
+ { 0x10A7, 0x2D07, 0x0000, 0x0000 },
+ { 0x1FA8, 0x1F60, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_184[] = {
+ { 0x04BC, 0x04BD, 0x0000, 0x0000 },
+ { 0x10A8, 0x2D08, 0x0000, 0x0000 },
+ { 0x1EA6, 0x1EA7, 0x0000, 0x0000 },
+ { 0x1FA7, 0x1F67, 0x03B9, 0x0000 },
+ { 0x2C94, 0x2C95, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_185[] = {
+ { 0x01B8, 0x01B9, 0x0000, 0x0000 },
+ { 0x10A9, 0x2D09, 0x0000, 0x0000 },
+ { 0x1FA6, 0x1F66, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_186[] = {
+ { 0x04BE, 0x04BF, 0x0000, 0x0000 },
+ { 0x10AA, 0x2D0A, 0x0000, 0x0000 },
+ { 0x1EA4, 0x1EA5, 0x0000, 0x0000 },
+ { 0x1FA5, 0x1F65, 0x03B9, 0x0000 },
+ { 0x2C96, 0x2C97, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_187[] = {
+ { 0x10AB, 0x2D0B, 0x0000, 0x0000 },
+ { 0x1FA4, 0x1F64, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_188[] = {
+ { 0x04B8, 0x04B9, 0x0000, 0x0000 },
+ { 0x10AC, 0x2D0C, 0x0000, 0x0000 },
+ { 0x1EA2, 0x1EA3, 0x0000, 0x0000 },
+ { 0x1FA3, 0x1F63, 0x03B9, 0x0000 },
+ { 0x2C90, 0x2C91, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_189[] = {
+ { 0x01BC, 0x01BD, 0x0000, 0x0000 },
+ { 0x10AD, 0x2D0D, 0x0000, 0x0000 },
+ { 0x1FA2, 0x1F62, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_190[] = {
+ { 0x04BA, 0x04BB, 0x0000, 0x0000 },
+ { 0x10AE, 0x2D0E, 0x0000, 0x0000 },
+ { 0x1EA0, 0x1EA1, 0x0000, 0x0000 },
+ { 0x1FA1, 0x1F61, 0x03B9, 0x0000 },
+ { 0x2C92, 0x2C93, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_191[] = {
+ { 0x10AF, 0x2D0F, 0x0000, 0x0000 },
+ { 0x1FA0, 0x1F60, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_192[] = {
+ { 0x00C0, 0x00E0, 0x0000, 0x0000 },
+ { 0x1EDE, 0x1EDF, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_193[] = {
+ { 0x00C1, 0x00E1, 0x0000, 0x0000 },
+ { 0x03C2, 0x03C3, 0x0000, 0x0000 },
+ { 0x04C5, 0x04C6, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_194[] = {
+ { 0x00C2, 0x00E2, 0x0000, 0x0000 },
+ { 0x1EDC, 0x1EDD, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_195[] = {
+ { 0x00C3, 0x00E3, 0x0000, 0x0000 },
+ { 0x04C7, 0x04C8, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_196[] = {
+ { 0x00C4, 0x00E4, 0x0000, 0x0000 },
+ { 0x01C5, 0x01C6, 0x0000, 0x0000 },
+ { 0x1EDA, 0x1EDB, 0x0000, 0x0000 },
+ { 0x1FDB, 0x1F77, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_197[] = {
+ { 0x00C5, 0x00E5, 0x0000, 0x0000 },
+ { 0x01C4, 0x01C6, 0x0000, 0x0000 },
+ { 0x04C1, 0x04C2, 0x0000, 0x0000 },
+ { 0x1FDA, 0x1F76, 0x0000, 0x0000 },
+ { 0xFF3A, 0xFF5A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_198[] = {
+ { 0x00C6, 0x00E6, 0x0000, 0x0000 },
+ { 0x01C7, 0x01C9, 0x0000, 0x0000 },
+ { 0x1ED8, 0x1ED9, 0x0000, 0x0000 },
+ { 0x1FD9, 0x1FD1, 0x0000, 0x0000 },
+ { 0xFF39, 0xFF59, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_199[] = {
+ { 0x00C7, 0x00E7, 0x0000, 0x0000 },
+ { 0x04C3, 0x04C4, 0x0000, 0x0000 },
+ { 0x1FD8, 0x1FD0, 0x0000, 0x0000 },
+ { 0xFF38, 0xFF58, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_200[] = {
+ { 0x00C8, 0x00E8, 0x0000, 0x0000 },
+ { 0x1ED6, 0x1ED7, 0x0000, 0x0000 },
+ { 0x1FD7, 0x03B9, 0x0308, 0x0342 },
+ { 0xFF37, 0xFF57, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_201[] = {
+ { 0x00C9, 0x00E9, 0x0000, 0x0000 },
+ { 0x01C8, 0x01C9, 0x0000, 0x0000 },
+ { 0x04CD, 0x04CE, 0x0000, 0x0000 },
+ { 0x1FD6, 0x03B9, 0x0342, 0x0000 },
+ { 0xFF36, 0xFF56, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_202[] = {
+ { 0x00CA, 0x00EA, 0x0000, 0x0000 },
+ { 0x01CB, 0x01CC, 0x0000, 0x0000 },
+ { 0x1ED4, 0x1ED5, 0x0000, 0x0000 },
+ { 0xFF35, 0xFF55, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_203[] = {
+ { 0x00CB, 0x00EB, 0x0000, 0x0000 },
+ { 0x01CA, 0x01CC, 0x0000, 0x0000 },
+ { 0xFF34, 0xFF54, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_204[] = {
+ { 0x00CC, 0x00EC, 0x0000, 0x0000 },
+ { 0x01CD, 0x01CE, 0x0000, 0x0000 },
+ { 0x1ED2, 0x1ED3, 0x0000, 0x0000 },
+ { 0x1FD3, 0x03B9, 0x0308, 0x0301 },
+ { 0x2CE0, 0x2CE1, 0x0000, 0x0000 },
+ { 0xFF33, 0xFF53, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_205[] = {
+ { 0x00CD, 0x00ED, 0x0000, 0x0000 },
+ { 0x04C9, 0x04CA, 0x0000, 0x0000 },
+ { 0x1FD2, 0x03B9, 0x0308, 0x0300 },
+ { 0xFF32, 0xFF52, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_206[] = {
+ { 0x00CE, 0x00EE, 0x0000, 0x0000 },
+ { 0x01CF, 0x01D0, 0x0000, 0x0000 },
+ { 0x1ED0, 0x1ED1, 0x0000, 0x0000 },
+ { 0x2CE2, 0x2CE3, 0x0000, 0x0000 },
+ { 0xFF31, 0xFF51, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_207[] = {
+ { 0x00CF, 0x00EF, 0x0000, 0x0000 },
+ { 0x04CB, 0x04CC, 0x0000, 0x0000 },
+ { 0xFF30, 0xFF50, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_208[] = {
+ { 0x00D0, 0x00F0, 0x0000, 0x0000 },
+ { 0x01D1, 0x01D2, 0x0000, 0x0000 },
+ { 0x04D4, 0x04D5, 0x0000, 0x0000 },
+ { 0x10C0, 0x2D20, 0x0000, 0x0000 },
+ { 0x1ECE, 0x1ECF, 0x0000, 0x0000 },
+ { 0xFF2F, 0xFF4F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_209[] = {
+ { 0x00D1, 0x00F1, 0x0000, 0x0000 },
+ { 0x10C1, 0x2D21, 0x0000, 0x0000 },
+ { 0xFF2E, 0xFF4E, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_210[] = {
+ { 0x00D2, 0x00F2, 0x0000, 0x0000 },
+ { 0x01D3, 0x01D4, 0x0000, 0x0000 },
+ { 0x03D1, 0x03B8, 0x0000, 0x0000 },
+ { 0x04D6, 0x04D7, 0x0000, 0x0000 },
+ { 0x10C2, 0x2D22, 0x0000, 0x0000 },
+ { 0x1ECC, 0x1ECD, 0x0000, 0x0000 },
+ { 0xFF2D, 0xFF4D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_211[] = {
+ { 0x00D3, 0x00F3, 0x0000, 0x0000 },
+ { 0x03D0, 0x03B2, 0x0000, 0x0000 },
+ { 0x10C3, 0x2D23, 0x0000, 0x0000 },
+ { 0x1FCC, 0x03B7, 0x03B9, 0x0000 },
+ { 0xFF2C, 0xFF4C, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_212[] = {
+ { 0x00D4, 0x00F4, 0x0000, 0x0000 },
+ { 0x01D5, 0x01D6, 0x0000, 0x0000 },
+ { 0x04D0, 0x04D1, 0x0000, 0x0000 },
+ { 0x10C4, 0x2D24, 0x0000, 0x0000 },
+ { 0x1ECA, 0x1ECB, 0x0000, 0x0000 },
+ { 0x1FCB, 0x1F75, 0x0000, 0x0000 },
+ { 0xFF2B, 0xFF4B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_213[] = {
+ { 0x00D5, 0x00F5, 0x0000, 0x0000 },
+ { 0x03D6, 0x03C0, 0x0000, 0x0000 },
+ { 0x10C5, 0x2D25, 0x0000, 0x0000 },
+ { 0x1FCA, 0x1F74, 0x0000, 0x0000 },
+ { 0xFF2A, 0xFF4A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_214[] = {
+ { 0x00D6, 0x00F6, 0x0000, 0x0000 },
+ { 0x01D7, 0x01D8, 0x0000, 0x0000 },
+ { 0x03D5, 0x03C6, 0x0000, 0x0000 },
+ { 0x04D2, 0x04D3, 0x0000, 0x0000 },
+ { 0x1EC8, 0x1EC9, 0x0000, 0x0000 },
+ { 0x1FC9, 0x1F73, 0x0000, 0x0000 },
+ { 0xFF29, 0xFF49, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_215[] = {
+ { 0x1FC8, 0x1F72, 0x0000, 0x0000 },
+ { 0xFF28, 0xFF48, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_216[] = {
+ { 0x00D8, 0x00F8, 0x0000, 0x0000 },
+ { 0x01D9, 0x01DA, 0x0000, 0x0000 },
+ { 0x04DC, 0x04DD, 0x0000, 0x0000 },
+ { 0x1EC6, 0x1EC7, 0x0000, 0x0000 },
+ { 0x1FC7, 0x03B7, 0x0342, 0x03B9 },
+ { 0xFF27, 0xFF47, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_217[] = {
+ { 0x00D9, 0x00F9, 0x0000, 0x0000 },
+ { 0x03DA, 0x03DB, 0x0000, 0x0000 },
+ { 0x1FC6, 0x03B7, 0x0342, 0x0000 },
+ { 0xFF26, 0xFF46, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_218[] = {
+ { 0x00DA, 0x00FA, 0x0000, 0x0000 },
+ { 0x01DB, 0x01DC, 0x0000, 0x0000 },
+ { 0x04DE, 0x04DF, 0x0000, 0x0000 },
+ { 0x1EC4, 0x1EC5, 0x0000, 0x0000 },
+ { 0xFF25, 0xFF45, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_219[] = {
+ { 0x00DB, 0x00FB, 0x0000, 0x0000 },
+ { 0x03D8, 0x03D9, 0x0000, 0x0000 },
+ { 0x1FC4, 0x03AE, 0x03B9, 0x0000 },
+ { 0xFF24, 0xFF44, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_220[] = {
+ { 0x00DC, 0x00FC, 0x0000, 0x0000 },
+ { 0x04D8, 0x04D9, 0x0000, 0x0000 },
+ { 0x1EC2, 0x1EC3, 0x0000, 0x0000 },
+ { 0x1FC3, 0x03B7, 0x03B9, 0x0000 },
+ { 0xFF23, 0xFF43, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_221[] = {
+ { 0x00DD, 0x00FD, 0x0000, 0x0000 },
+ { 0x03DE, 0x03DF, 0x0000, 0x0000 },
+ { 0x1FC2, 0x1F74, 0x03B9, 0x0000 },
+ { 0xFF22, 0xFF42, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_222[] = {
+ { 0x00DE, 0x00FE, 0x0000, 0x0000 },
+ { 0x04DA, 0x04DB, 0x0000, 0x0000 },
+ { 0x1EC0, 0x1EC1, 0x0000, 0x0000 },
+ { 0xFF21, 0xFF41, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_223[] = {
+ { 0x00DF, 0x0073, 0x0073, 0x0000 },
+ { 0x01DE, 0x01DF, 0x0000, 0x0000 },
+ { 0x03DC, 0x03DD, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_224[] = {
+ { 0x04E4, 0x04E5, 0x0000, 0x0000 },
+ { 0x24C4, 0x24DE, 0x0000, 0x0000 },
+ { 0x2CCC, 0x2CCD, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_225[] = {
+ { 0x01E0, 0x01E1, 0x0000, 0x0000 },
+ { 0x03E2, 0x03E3, 0x0000, 0x0000 },
+ { 0x24C5, 0x24DF, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_226[] = {
+ { 0x04E6, 0x04E7, 0x0000, 0x0000 },
+ { 0x24C6, 0x24E0, 0x0000, 0x0000 },
+ { 0x2CCE, 0x2CCF, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_227[] = {
+ { 0x01E2, 0x01E3, 0x0000, 0x0000 },
+ { 0x03E0, 0x03E1, 0x0000, 0x0000 },
+ { 0x1FFC, 0x03C9, 0x03B9, 0x0000 },
+ { 0x24C7, 0x24E1, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_228[] = {
+ { 0x04E0, 0x04E1, 0x0000, 0x0000 },
+ { 0x1FFB, 0x1F7D, 0x0000, 0x0000 },
+ { 0x24C0, 0x24DA, 0x0000, 0x0000 },
+ { 0x2CC8, 0x2CC9, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_229[] = {
+ { 0x01E4, 0x01E5, 0x0000, 0x0000 },
+ { 0x03E6, 0x03E7, 0x0000, 0x0000 },
+ { 0x1FFA, 0x1F7C, 0x0000, 0x0000 },
+ { 0x24C1, 0x24DB, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_230[] = {
+ { 0x04E2, 0x04E3, 0x0000, 0x0000 },
+ { 0x1EF8, 0x1EF9, 0x0000, 0x0000 },
+ { 0x1FF9, 0x1F79, 0x0000, 0x0000 },
+ { 0x24C2, 0x24DC, 0x0000, 0x0000 },
+ { 0x2CCA, 0x2CCB, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_231[] = {
+ { 0x01E6, 0x01E7, 0x0000, 0x0000 },
+ { 0x03E4, 0x03E5, 0x0000, 0x0000 },
+ { 0x1FF8, 0x1F78, 0x0000, 0x0000 },
+ { 0x24C3, 0x24DD, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_232[] = {
+ { 0x04EC, 0x04ED, 0x0000, 0x0000 },
+ { 0x1EF6, 0x1EF7, 0x0000, 0x0000 },
+ { 0x1FF7, 0x03C9, 0x0342, 0x03B9 },
+ { 0x24CC, 0x24E6, 0x0000, 0x0000 },
+ { 0x2CC4, 0x2CC5, 0x0000, 0x0000 },
+ { 0xFB13, 0x0574, 0x0576, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_233[] = {
+ { 0x01E8, 0x01E9, 0x0000, 0x0000 },
+ { 0x03EA, 0x03EB, 0x0000, 0x0000 },
+ { 0x1FF6, 0x03C9, 0x0342, 0x0000 },
+ { 0x24CD, 0x24E7, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_234[] = {
+ { 0x04EE, 0x04EF, 0x0000, 0x0000 },
+ { 0x1EF4, 0x1EF5, 0x0000, 0x0000 },
+ { 0x24CE, 0x24E8, 0x0000, 0x0000 },
+ { 0x2CC6, 0x2CC7, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_235[] = {
+ { 0x01EA, 0x01EB, 0x0000, 0x0000 },
+ { 0x03E8, 0x03E9, 0x0000, 0x0000 },
+ { 0x1FF4, 0x03CE, 0x03B9, 0x0000 },
+ { 0x24CF, 0x24E9, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_236[] = {
+ { 0x04E8, 0x04E9, 0x0000, 0x0000 },
+ { 0x1EF2, 0x1EF3, 0x0000, 0x0000 },
+ { 0x1FF3, 0x03C9, 0x03B9, 0x0000 },
+ { 0x24C8, 0x24E2, 0x0000, 0x0000 },
+ { 0x2CC0, 0x2CC1, 0x0000, 0x0000 },
+ { 0xFB17, 0x0574, 0x056D, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_237[] = {
+ { 0x01EC, 0x01ED, 0x0000, 0x0000 },
+ { 0x03EE, 0x03EF, 0x0000, 0x0000 },
+ { 0x1FF2, 0x1F7C, 0x03B9, 0x0000 },
+ { 0x24C9, 0x24E3, 0x0000, 0x0000 },
+ { 0xFB16, 0x057E, 0x0576, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_238[] = {
+ { 0x04EA, 0x04EB, 0x0000, 0x0000 },
+ { 0x1EF0, 0x1EF1, 0x0000, 0x0000 },
+ { 0x24CA, 0x24E4, 0x0000, 0x0000 },
+ { 0x2CC2, 0x2CC3, 0x0000, 0x0000 },
+ { 0xFB15, 0x0574, 0x056B, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_239[] = {
+ { 0x01EE, 0x01EF, 0x0000, 0x0000 },
+ { 0x03EC, 0x03ED, 0x0000, 0x0000 },
+ { 0x24CB, 0x24E5, 0x0000, 0x0000 },
+ { 0xFB14, 0x0574, 0x0565, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_240[] = {
+ { 0x01F1, 0x01F3, 0x0000, 0x0000 },
+ { 0x04F4, 0x04F5, 0x0000, 0x0000 },
+ { 0x1EEE, 0x1EEF, 0x0000, 0x0000 },
+ { 0x2CDC, 0x2CDD, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_241[] = {
+ { 0x01F0, 0x006A, 0x030C, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_242[] = {
+ { 0x03F1, 0x03C1, 0x0000, 0x0000 },
+ { 0x04F6, 0x04F7, 0x0000, 0x0000 },
+ { 0x1EEC, 0x1EED, 0x0000, 0x0000 },
+ { 0x2CDE, 0x2CDF, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_243[] = {
+ { 0x01F2, 0x01F3, 0x0000, 0x0000 },
+ { 0x03F0, 0x03BA, 0x0000, 0x0000 },
+ { 0x1FEC, 0x1FE5, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_244[] = {
+ { 0x03F7, 0x03F8, 0x0000, 0x0000 },
+ { 0x04F0, 0x04F1, 0x0000, 0x0000 },
+ { 0x1EEA, 0x1EEB, 0x0000, 0x0000 },
+ { 0x1FEB, 0x1F7B, 0x0000, 0x0000 },
+ { 0x2CD8, 0x2CD9, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_245[] = {
+ { 0x01F4, 0x01F5, 0x0000, 0x0000 },
+ { 0x1FEA, 0x1F7A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_246[] = {
+ { 0x01F7, 0x01BF, 0x0000, 0x0000 },
+ { 0x03F5, 0x03B5, 0x0000, 0x0000 },
+ { 0x04F2, 0x04F3, 0x0000, 0x0000 },
+ { 0x1EE8, 0x1EE9, 0x0000, 0x0000 },
+ { 0x1FE9, 0x1FE1, 0x0000, 0x0000 },
+ { 0x2CDA, 0x2CDB, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_247[] = {
+ { 0x01F6, 0x0195, 0x0000, 0x0000 },
+ { 0x03F4, 0x03B8, 0x0000, 0x0000 },
+ { 0x1FE8, 0x1FE0, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_248[] = {
+ { 0x1EE6, 0x1EE7, 0x0000, 0x0000 },
+ { 0x1FE7, 0x03C5, 0x0308, 0x0342 },
+ { 0x2CD4, 0x2CD5, 0x0000, 0x0000 },
+ { 0xFB03, 0x0066, 0x0066, 0x0069 }
+};
+
+static const CaseFoldMapping case_fold_249[] = {
+ { 0x01F8, 0x01F9, 0x0000, 0x0000 },
+ { 0x03FA, 0x03FB, 0x0000, 0x0000 },
+ { 0x1FE6, 0x03C5, 0x0342, 0x0000 },
+ { 0xFB02, 0x0066, 0x006C, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_250[] = {
+ { 0x03F9, 0x03F2, 0x0000, 0x0000 },
+ { 0x1EE4, 0x1EE5, 0x0000, 0x0000 },
+ { 0x2CD6, 0x2CD7, 0x0000, 0x0000 },
+ { 0xFB01, 0x0066, 0x0069, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_251[] = {
+ { 0x01FA, 0x01FB, 0x0000, 0x0000 },
+ { 0x1FE4, 0x03C1, 0x0313, 0x0000 },
+ { 0xFB00, 0x0066, 0x0066, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_252[] = {
+ { 0x04F8, 0x04F9, 0x0000, 0x0000 },
+ { 0x1EE2, 0x1EE3, 0x0000, 0x0000 },
+ { 0x1FE3, 0x03C5, 0x0308, 0x0301 },
+ { 0x2CD0, 0x2CD1, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_253[] = {
+ { 0x01FC, 0x01FD, 0x0000, 0x0000 },
+ { 0x1FE2, 0x03C5, 0x0308, 0x0300 },
+ { 0xFB06, 0x0073, 0x0074, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_254[] = {
+ { 0x1EE0, 0x1EE1, 0x0000, 0x0000 },
+ { 0x2CD2, 0x2CD3, 0x0000, 0x0000 },
+ { 0xFB05, 0x0073, 0x0074, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_255[] = {
+ { 0x01FE, 0x01FF, 0x0000, 0x0000 },
+ { 0xFB04, 0x0066, 0x0066, 0x006C }
+};
+
+
+static const CaseFoldHashBucket case_fold_hash[256] = {
+ { __PHYSFS_ARRAYLEN(case_fold_000), case_fold_000 },
+ { __PHYSFS_ARRAYLEN(case_fold_001), case_fold_001 },
+ { __PHYSFS_ARRAYLEN(case_fold_002), case_fold_002 },
+ { __PHYSFS_ARRAYLEN(case_fold_003), case_fold_003 },
+ { __PHYSFS_ARRAYLEN(case_fold_004), case_fold_004 },
+ { __PHYSFS_ARRAYLEN(case_fold_005), case_fold_005 },
+ { __PHYSFS_ARRAYLEN(case_fold_006), case_fold_006 },
+ { __PHYSFS_ARRAYLEN(case_fold_007), case_fold_007 },
+ { __PHYSFS_ARRAYLEN(case_fold_008), case_fold_008 },
+ { __PHYSFS_ARRAYLEN(case_fold_009), case_fold_009 },
+ { __PHYSFS_ARRAYLEN(case_fold_010), case_fold_010 },
+ { __PHYSFS_ARRAYLEN(case_fold_011), case_fold_011 },
+ { __PHYSFS_ARRAYLEN(case_fold_012), case_fold_012 },
+ { __PHYSFS_ARRAYLEN(case_fold_013), case_fold_013 },
+ { __PHYSFS_ARRAYLEN(case_fold_014), case_fold_014 },
+ { __PHYSFS_ARRAYLEN(case_fold_015), case_fold_015 },
+ { __PHYSFS_ARRAYLEN(case_fold_016), case_fold_016 },
+ { __PHYSFS_ARRAYLEN(case_fold_017), case_fold_017 },
+ { __PHYSFS_ARRAYLEN(case_fold_018), case_fold_018 },
+ { __PHYSFS_ARRAYLEN(case_fold_019), case_fold_019 },
+ { __PHYSFS_ARRAYLEN(case_fold_020), case_fold_020 },
+ { __PHYSFS_ARRAYLEN(case_fold_021), case_fold_021 },
+ { __PHYSFS_ARRAYLEN(case_fold_022), case_fold_022 },
+ { __PHYSFS_ARRAYLEN(case_fold_023), case_fold_023 },
+ { __PHYSFS_ARRAYLEN(case_fold_024), case_fold_024 },
+ { __PHYSFS_ARRAYLEN(case_fold_025), case_fold_025 },
+ { __PHYSFS_ARRAYLEN(case_fold_026), case_fold_026 },
+ { __PHYSFS_ARRAYLEN(case_fold_027), case_fold_027 },
+ { __PHYSFS_ARRAYLEN(case_fold_028), case_fold_028 },
+ { __PHYSFS_ARRAYLEN(case_fold_029), case_fold_029 },
+ { __PHYSFS_ARRAYLEN(case_fold_030), case_fold_030 },
+ { __PHYSFS_ARRAYLEN(case_fold_031), case_fold_031 },
+ { __PHYSFS_ARRAYLEN(case_fold_032), case_fold_032 },
+ { __PHYSFS_ARRAYLEN(case_fold_033), case_fold_033 },
+ { __PHYSFS_ARRAYLEN(case_fold_034), case_fold_034 },
+ { __PHYSFS_ARRAYLEN(case_fold_035), case_fold_035 },
+ { __PHYSFS_ARRAYLEN(case_fold_036), case_fold_036 },
+ { __PHYSFS_ARRAYLEN(case_fold_037), case_fold_037 },
+ { __PHYSFS_ARRAYLEN(case_fold_038), case_fold_038 },
+ { __PHYSFS_ARRAYLEN(case_fold_039), case_fold_039 },
+ { __PHYSFS_ARRAYLEN(case_fold_040), case_fold_040 },
+ { __PHYSFS_ARRAYLEN(case_fold_041), case_fold_041 },
+ { __PHYSFS_ARRAYLEN(case_fold_042), case_fold_042 },
+ { __PHYSFS_ARRAYLEN(case_fold_043), case_fold_043 },
+ { __PHYSFS_ARRAYLEN(case_fold_044), case_fold_044 },
+ { __PHYSFS_ARRAYLEN(case_fold_045), case_fold_045 },
+ { __PHYSFS_ARRAYLEN(case_fold_046), case_fold_046 },
+ { __PHYSFS_ARRAYLEN(case_fold_047), case_fold_047 },
+ { __PHYSFS_ARRAYLEN(case_fold_048), case_fold_048 },
+ { __PHYSFS_ARRAYLEN(case_fold_049), case_fold_049 },
+ { __PHYSFS_ARRAYLEN(case_fold_050), case_fold_050 },
+ { __PHYSFS_ARRAYLEN(case_fold_051), case_fold_051 },
+ { __PHYSFS_ARRAYLEN(case_fold_052), case_fold_052 },
+ { __PHYSFS_ARRAYLEN(case_fold_053), case_fold_053 },
+ { __PHYSFS_ARRAYLEN(case_fold_054), case_fold_054 },
+ { __PHYSFS_ARRAYLEN(case_fold_055), case_fold_055 },
+ { __PHYSFS_ARRAYLEN(case_fold_056), case_fold_056 },
+ { __PHYSFS_ARRAYLEN(case_fold_057), case_fold_057 },
+ { __PHYSFS_ARRAYLEN(case_fold_058), case_fold_058 },
+ { __PHYSFS_ARRAYLEN(case_fold_059), case_fold_059 },
+ { __PHYSFS_ARRAYLEN(case_fold_060), case_fold_060 },
+ { __PHYSFS_ARRAYLEN(case_fold_061), case_fold_061 },
+ { __PHYSFS_ARRAYLEN(case_fold_062), case_fold_062 },
+ { __PHYSFS_ARRAYLEN(case_fold_063), case_fold_063 },
+ { __PHYSFS_ARRAYLEN(case_fold_064), case_fold_064 },
+ { __PHYSFS_ARRAYLEN(case_fold_065), case_fold_065 },
+ { __PHYSFS_ARRAYLEN(case_fold_066), case_fold_066 },
+ { __PHYSFS_ARRAYLEN(case_fold_067), case_fold_067 },
+ { __PHYSFS_ARRAYLEN(case_fold_068), case_fold_068 },
+ { __PHYSFS_ARRAYLEN(case_fold_069), case_fold_069 },
+ { __PHYSFS_ARRAYLEN(case_fold_070), case_fold_070 },
+ { __PHYSFS_ARRAYLEN(case_fold_071), case_fold_071 },
+ { __PHYSFS_ARRAYLEN(case_fold_072), case_fold_072 },
+ { __PHYSFS_ARRAYLEN(case_fold_073), case_fold_073 },
+ { __PHYSFS_ARRAYLEN(case_fold_074), case_fold_074 },
+ { __PHYSFS_ARRAYLEN(case_fold_075), case_fold_075 },
+ { __PHYSFS_ARRAYLEN(case_fold_076), case_fold_076 },
+ { __PHYSFS_ARRAYLEN(case_fold_077), case_fold_077 },
+ { __PHYSFS_ARRAYLEN(case_fold_078), case_fold_078 },
+ { __PHYSFS_ARRAYLEN(case_fold_079), case_fold_079 },
+ { __PHYSFS_ARRAYLEN(case_fold_080), case_fold_080 },
+ { __PHYSFS_ARRAYLEN(case_fold_081), case_fold_081 },
+ { __PHYSFS_ARRAYLEN(case_fold_082), case_fold_082 },
+ { __PHYSFS_ARRAYLEN(case_fold_083), case_fold_083 },
+ { __PHYSFS_ARRAYLEN(case_fold_084), case_fold_084 },
+ { __PHYSFS_ARRAYLEN(case_fold_085), case_fold_085 },
+ { __PHYSFS_ARRAYLEN(case_fold_086), case_fold_086 },
+ { __PHYSFS_ARRAYLEN(case_fold_087), case_fold_087 },
+ { __PHYSFS_ARRAYLEN(case_fold_088), case_fold_088 },
+ { __PHYSFS_ARRAYLEN(case_fold_089), case_fold_089 },
+ { __PHYSFS_ARRAYLEN(case_fold_090), case_fold_090 },
+ { __PHYSFS_ARRAYLEN(case_fold_091), case_fold_091 },
+ { __PHYSFS_ARRAYLEN(case_fold_092), case_fold_092 },
+ { __PHYSFS_ARRAYLEN(case_fold_093), case_fold_093 },
+ { __PHYSFS_ARRAYLEN(case_fold_094), case_fold_094 },
+ { __PHYSFS_ARRAYLEN(case_fold_095), case_fold_095 },
+ { __PHYSFS_ARRAYLEN(case_fold_096), case_fold_096 },
+ { __PHYSFS_ARRAYLEN(case_fold_097), case_fold_097 },
+ { __PHYSFS_ARRAYLEN(case_fold_098), case_fold_098 },
+ { __PHYSFS_ARRAYLEN(case_fold_099), case_fold_099 },
+ { __PHYSFS_ARRAYLEN(case_fold_100), case_fold_100 },
+ { __PHYSFS_ARRAYLEN(case_fold_101), case_fold_101 },
+ { __PHYSFS_ARRAYLEN(case_fold_102), case_fold_102 },
+ { __PHYSFS_ARRAYLEN(case_fold_103), case_fold_103 },
+ { __PHYSFS_ARRAYLEN(case_fold_104), case_fold_104 },
+ { __PHYSFS_ARRAYLEN(case_fold_105), case_fold_105 },
+ { __PHYSFS_ARRAYLEN(case_fold_106), case_fold_106 },
+ { __PHYSFS_ARRAYLEN(case_fold_107), case_fold_107 },
+ { __PHYSFS_ARRAYLEN(case_fold_108), case_fold_108 },
+ { __PHYSFS_ARRAYLEN(case_fold_109), case_fold_109 },
+ { __PHYSFS_ARRAYLEN(case_fold_110), case_fold_110 },
+ { __PHYSFS_ARRAYLEN(case_fold_111), case_fold_111 },
+ { __PHYSFS_ARRAYLEN(case_fold_112), case_fold_112 },
+ { __PHYSFS_ARRAYLEN(case_fold_113), case_fold_113 },
+ { __PHYSFS_ARRAYLEN(case_fold_114), case_fold_114 },
+ { __PHYSFS_ARRAYLEN(case_fold_115), case_fold_115 },
+ { __PHYSFS_ARRAYLEN(case_fold_116), case_fold_116 },
+ { __PHYSFS_ARRAYLEN(case_fold_117), case_fold_117 },
+ { __PHYSFS_ARRAYLEN(case_fold_118), case_fold_118 },
+ { __PHYSFS_ARRAYLEN(case_fold_119), case_fold_119 },
+ { __PHYSFS_ARRAYLEN(case_fold_120), case_fold_120 },
+ { __PHYSFS_ARRAYLEN(case_fold_121), case_fold_121 },
+ { __PHYSFS_ARRAYLEN(case_fold_122), case_fold_122 },
+ { 0, NULL },
+ { __PHYSFS_ARRAYLEN(case_fold_124), case_fold_124 },
+ { 0, NULL },
+ { __PHYSFS_ARRAYLEN(case_fold_126), case_fold_126 },
+ { 0, NULL },
+ { __PHYSFS_ARRAYLEN(case_fold_128), case_fold_128 },
+ { __PHYSFS_ARRAYLEN(case_fold_129), case_fold_129 },
+ { __PHYSFS_ARRAYLEN(case_fold_130), case_fold_130 },
+ { __PHYSFS_ARRAYLEN(case_fold_131), case_fold_131 },
+ { __PHYSFS_ARRAYLEN(case_fold_132), case_fold_132 },
+ { __PHYSFS_ARRAYLEN(case_fold_133), case_fold_133 },
+ { __PHYSFS_ARRAYLEN(case_fold_134), case_fold_134 },
+ { __PHYSFS_ARRAYLEN(case_fold_135), case_fold_135 },
+ { __PHYSFS_ARRAYLEN(case_fold_136), case_fold_136 },
+ { __PHYSFS_ARRAYLEN(case_fold_137), case_fold_137 },
+ { __PHYSFS_ARRAYLEN(case_fold_138), case_fold_138 },
+ { __PHYSFS_ARRAYLEN(case_fold_139), case_fold_139 },
+ { __PHYSFS_ARRAYLEN(case_fold_140), case_fold_140 },
+ { __PHYSFS_ARRAYLEN(case_fold_141), case_fold_141 },
+ { __PHYSFS_ARRAYLEN(case_fold_142), case_fold_142 },
+ { __PHYSFS_ARRAYLEN(case_fold_143), case_fold_143 },
+ { __PHYSFS_ARRAYLEN(case_fold_144), case_fold_144 },
+ { __PHYSFS_ARRAYLEN(case_fold_145), case_fold_145 },
+ { __PHYSFS_ARRAYLEN(case_fold_146), case_fold_146 },
+ { __PHYSFS_ARRAYLEN(case_fold_147), case_fold_147 },
+ { __PHYSFS_ARRAYLEN(case_fold_148), case_fold_148 },
+ { __PHYSFS_ARRAYLEN(case_fold_149), case_fold_149 },
+ { __PHYSFS_ARRAYLEN(case_fold_150), case_fold_150 },
+ { __PHYSFS_ARRAYLEN(case_fold_151), case_fold_151 },
+ { __PHYSFS_ARRAYLEN(case_fold_152), case_fold_152 },
+ { __PHYSFS_ARRAYLEN(case_fold_153), case_fold_153 },
+ { __PHYSFS_ARRAYLEN(case_fold_154), case_fold_154 },
+ { __PHYSFS_ARRAYLEN(case_fold_155), case_fold_155 },
+ { __PHYSFS_ARRAYLEN(case_fold_156), case_fold_156 },
+ { __PHYSFS_ARRAYLEN(case_fold_157), case_fold_157 },
+ { __PHYSFS_ARRAYLEN(case_fold_158), case_fold_158 },
+ { __PHYSFS_ARRAYLEN(case_fold_159), case_fold_159 },
+ { __PHYSFS_ARRAYLEN(case_fold_160), case_fold_160 },
+ { __PHYSFS_ARRAYLEN(case_fold_161), case_fold_161 },
+ { __PHYSFS_ARRAYLEN(case_fold_162), case_fold_162 },
+ { __PHYSFS_ARRAYLEN(case_fold_163), case_fold_163 },
+ { __PHYSFS_ARRAYLEN(case_fold_164), case_fold_164 },
+ { __PHYSFS_ARRAYLEN(case_fold_165), case_fold_165 },
+ { __PHYSFS_ARRAYLEN(case_fold_166), case_fold_166 },
+ { __PHYSFS_ARRAYLEN(case_fold_167), case_fold_167 },
+ { __PHYSFS_ARRAYLEN(case_fold_168), case_fold_168 },
+ { __PHYSFS_ARRAYLEN(case_fold_169), case_fold_169 },
+ { __PHYSFS_ARRAYLEN(case_fold_170), case_fold_170 },
+ { __PHYSFS_ARRAYLEN(case_fold_171), case_fold_171 },
+ { __PHYSFS_ARRAYLEN(case_fold_172), case_fold_172 },
+ { __PHYSFS_ARRAYLEN(case_fold_173), case_fold_173 },
+ { __PHYSFS_ARRAYLEN(case_fold_174), case_fold_174 },
+ { __PHYSFS_ARRAYLEN(case_fold_175), case_fold_175 },
+ { __PHYSFS_ARRAYLEN(case_fold_176), case_fold_176 },
+ { __PHYSFS_ARRAYLEN(case_fold_177), case_fold_177 },
+ { __PHYSFS_ARRAYLEN(case_fold_178), case_fold_178 },
+ { __PHYSFS_ARRAYLEN(case_fold_179), case_fold_179 },
+ { __PHYSFS_ARRAYLEN(case_fold_180), case_fold_180 },
+ { __PHYSFS_ARRAYLEN(case_fold_181), case_fold_181 },
+ { __PHYSFS_ARRAYLEN(case_fold_182), case_fold_182 },
+ { __PHYSFS_ARRAYLEN(case_fold_183), case_fold_183 },
+ { __PHYSFS_ARRAYLEN(case_fold_184), case_fold_184 },
+ { __PHYSFS_ARRAYLEN(case_fold_185), case_fold_185 },
+ { __PHYSFS_ARRAYLEN(case_fold_186), case_fold_186 },
+ { __PHYSFS_ARRAYLEN(case_fold_187), case_fold_187 },
+ { __PHYSFS_ARRAYLEN(case_fold_188), case_fold_188 },
+ { __PHYSFS_ARRAYLEN(case_fold_189), case_fold_189 },
+ { __PHYSFS_ARRAYLEN(case_fold_190), case_fold_190 },
+ { __PHYSFS_ARRAYLEN(case_fold_191), case_fold_191 },
+ { __PHYSFS_ARRAYLEN(case_fold_192), case_fold_192 },
+ { __PHYSFS_ARRAYLEN(case_fold_193), case_fold_193 },
+ { __PHYSFS_ARRAYLEN(case_fold_194), case_fold_194 },
+ { __PHYSFS_ARRAYLEN(case_fold_195), case_fold_195 },
+ { __PHYSFS_ARRAYLEN(case_fold_196), case_fold_196 },
+ { __PHYSFS_ARRAYLEN(case_fold_197), case_fold_197 },
+ { __PHYSFS_ARRAYLEN(case_fold_198), case_fold_198 },
+ { __PHYSFS_ARRAYLEN(case_fold_199), case_fold_199 },
+ { __PHYSFS_ARRAYLEN(case_fold_200), case_fold_200 },
+ { __PHYSFS_ARRAYLEN(case_fold_201), case_fold_201 },
+ { __PHYSFS_ARRAYLEN(case_fold_202), case_fold_202 },
+ { __PHYSFS_ARRAYLEN(case_fold_203), case_fold_203 },
+ { __PHYSFS_ARRAYLEN(case_fold_204), case_fold_204 },
+ { __PHYSFS_ARRAYLEN(case_fold_205), case_fold_205 },
+ { __PHYSFS_ARRAYLEN(case_fold_206), case_fold_206 },
+ { __PHYSFS_ARRAYLEN(case_fold_207), case_fold_207 },
+ { __PHYSFS_ARRAYLEN(case_fold_208), case_fold_208 },
+ { __PHYSFS_ARRAYLEN(case_fold_209), case_fold_209 },
+ { __PHYSFS_ARRAYLEN(case_fold_210), case_fold_210 },
+ { __PHYSFS_ARRAYLEN(case_fold_211), case_fold_211 },
+ { __PHYSFS_ARRAYLEN(case_fold_212), case_fold_212 },
+ { __PHYSFS_ARRAYLEN(case_fold_213), case_fold_213 },
+ { __PHYSFS_ARRAYLEN(case_fold_214), case_fold_214 },
+ { __PHYSFS_ARRAYLEN(case_fold_215), case_fold_215 },
+ { __PHYSFS_ARRAYLEN(case_fold_216), case_fold_216 },
+ { __PHYSFS_ARRAYLEN(case_fold_217), case_fold_217 },
+ { __PHYSFS_ARRAYLEN(case_fold_218), case_fold_218 },
+ { __PHYSFS_ARRAYLEN(case_fold_219), case_fold_219 },
+ { __PHYSFS_ARRAYLEN(case_fold_220), case_fold_220 },
+ { __PHYSFS_ARRAYLEN(case_fold_221), case_fold_221 },
+ { __PHYSFS_ARRAYLEN(case_fold_222), case_fold_222 },
+ { __PHYSFS_ARRAYLEN(case_fold_223), case_fold_223 },
+ { __PHYSFS_ARRAYLEN(case_fold_224), case_fold_224 },
+ { __PHYSFS_ARRAYLEN(case_fold_225), case_fold_225 },
+ { __PHYSFS_ARRAYLEN(case_fold_226), case_fold_226 },
+ { __PHYSFS_ARRAYLEN(case_fold_227), case_fold_227 },
+ { __PHYSFS_ARRAYLEN(case_fold_228), case_fold_228 },
+ { __PHYSFS_ARRAYLEN(case_fold_229), case_fold_229 },
+ { __PHYSFS_ARRAYLEN(case_fold_230), case_fold_230 },
+ { __PHYSFS_ARRAYLEN(case_fold_231), case_fold_231 },
+ { __PHYSFS_ARRAYLEN(case_fold_232), case_fold_232 },
+ { __PHYSFS_ARRAYLEN(case_fold_233), case_fold_233 },
+ { __PHYSFS_ARRAYLEN(case_fold_234), case_fold_234 },
+ { __PHYSFS_ARRAYLEN(case_fold_235), case_fold_235 },
+ { __PHYSFS_ARRAYLEN(case_fold_236), case_fold_236 },
+ { __PHYSFS_ARRAYLEN(case_fold_237), case_fold_237 },
+ { __PHYSFS_ARRAYLEN(case_fold_238), case_fold_238 },
+ { __PHYSFS_ARRAYLEN(case_fold_239), case_fold_239 },
+ { __PHYSFS_ARRAYLEN(case_fold_240), case_fold_240 },
+ { __PHYSFS_ARRAYLEN(case_fold_241), case_fold_241 },
+ { __PHYSFS_ARRAYLEN(case_fold_242), case_fold_242 },
+ { __PHYSFS_ARRAYLEN(case_fold_243), case_fold_243 },
+ { __PHYSFS_ARRAYLEN(case_fold_244), case_fold_244 },
+ { __PHYSFS_ARRAYLEN(case_fold_245), case_fold_245 },
+ { __PHYSFS_ARRAYLEN(case_fold_246), case_fold_246 },
+ { __PHYSFS_ARRAYLEN(case_fold_247), case_fold_247 },
+ { __PHYSFS_ARRAYLEN(case_fold_248), case_fold_248 },
+ { __PHYSFS_ARRAYLEN(case_fold_249), case_fold_249 },
+ { __PHYSFS_ARRAYLEN(case_fold_250), case_fold_250 },
+ { __PHYSFS_ARRAYLEN(case_fold_251), case_fold_251 },
+ { __PHYSFS_ARRAYLEN(case_fold_252), case_fold_252 },
+ { __PHYSFS_ARRAYLEN(case_fold_253), case_fold_253 },
+ { __PHYSFS_ARRAYLEN(case_fold_254), case_fold_254 },
+ { __PHYSFS_ARRAYLEN(case_fold_255), case_fold_255 },
+};
+
diff -r 404ddce27b23 -r c13ebed437cb misc/libphysfs/physfs_internal.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/physfs_internal.h Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,776 @@
+/*
+ * Internal function/structure declaration. Do NOT include in your
+ * application.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ * This file written by Ryan C. Gordon.
+ */
+
+#ifndef _INCLUDE_PHYSFS_INTERNAL_H_
+#define _INCLUDE_PHYSFS_INTERNAL_H_
+
+#ifndef __PHYSICSFS_INTERNAL__
+#error Do not include this header from your applications.
+#endif
+
+#include "physfs.h"
+
+/* The holy trinity. */
+#include
+#include
+#include
+
+#include "physfs_platforms.h"
+
+#include
+
+/* !!! FIXME: remove this when revamping stack allocation code... */
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#include
+#endif
+
+#if PHYSFS_PLATFORM_SOLARIS
+#include
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __GNUC__
+#define PHYSFS_MINIMUM_GCC_VERSION(major, minor) \
+ ( ((__GNUC__ << 16) + __GNUC_MINOR__) >= (((major) << 16) + (minor)) )
+#else
+#define PHYSFS_MINIMUM_GCC_VERSION(major, minor) (0)
+#endif
+
+#ifdef __cplusplus
+ /* C++ always has a real inline keyword. */
+#elif (defined macintosh) && !(defined __MWERKS__)
+# define inline
+#elif (defined _MSC_VER)
+# define inline __inline
+#endif
+
+#if PHYSFS_PLATFORM_LINUX && !defined(_FILE_OFFSET_BITS)
+#define _FILE_OFFSET_BITS 64
+#endif
+
+/*
+ * Interface for small allocations. If you need a little scratch space for
+ * a throwaway buffer or string, use this. It will make small allocations
+ * on the stack if possible, and use allocator.Malloc() if they are too
+ * large. This helps reduce malloc pressure.
+ * There are some rules, though:
+ * NEVER return a pointer from this, as stack-allocated buffers go away
+ * when your function returns.
+ * NEVER allocate in a loop, as stack-allocated pointers will pile up. Call
+ * a function that uses smallAlloc from your loop, so the allocation can
+ * free each time.
+ * NEVER call smallAlloc with any complex expression (it's a macro that WILL
+ * have side effects...it references the argument multiple times). Use a
+ * variable or a literal.
+ * NEVER free a pointer from this with anything but smallFree. It will not
+ * be a valid pointer to the allocator, regardless of where the memory came
+ * from.
+ * NEVER realloc a pointer from this.
+ * NEVER forget to use smallFree: it may not be a pointer from the stack.
+ * NEVER forget to check for NULL...allocation can fail here, of course!
+ */
+#define __PHYSFS_SMALLALLOCTHRESHOLD 256
+void *__PHYSFS_initSmallAlloc(void *ptr, PHYSFS_uint64 len);
+
+#define __PHYSFS_smallAlloc(bytes) ( \
+ __PHYSFS_initSmallAlloc( \
+ (((bytes) < __PHYSFS_SMALLALLOCTHRESHOLD) ? \
+ alloca((size_t)((bytes)+sizeof(void*))) : NULL), (bytes)) \
+)
+
+void __PHYSFS_smallFree(void *ptr);
+
+
+/* Use the allocation hooks. */
+#define malloc(x) Do not use malloc() directly.
+#define realloc(x, y) Do not use realloc() directly.
+#define free(x) Do not use free() directly.
+/* !!! FIXME: add alloca check here. */
+
+#ifndef PHYSFS_SUPPORTS_ZIP
+#define PHYSFS_SUPPORTS_ZIP 1
+#endif
+#ifndef PHYSFS_SUPPORTS_7Z
+#define PHYSFS_SUPPORTS_7Z 0
+#endif
+#ifndef PHYSFS_SUPPORTS_GRP
+#define PHYSFS_SUPPORTS_GRP 0
+#endif
+#ifndef PHYSFS_SUPPORTS_HOG
+#define PHYSFS_SUPPORTS_HOG 0
+#endif
+#ifndef PHYSFS_SUPPORTS_MVL
+#define PHYSFS_SUPPORTS_MVL 0
+#endif
+#ifndef PHYSFS_SUPPORTS_WAD
+#define PHYSFS_SUPPORTS_WAD 0
+#endif
+#ifndef PHYSFS_SUPPORTS_ISO9660
+#define PHYSFS_SUPPORTS_ISO9660 0
+#endif
+
+/* The latest supported PHYSFS_Io::version value. */
+#define CURRENT_PHYSFS_IO_API_VERSION 0
+
+/* Opaque data for file and dir handlers... */
+typedef void PHYSFS_Dir;
+
+typedef struct
+{
+ /*
+ * Basic info about this archiver...
+ */
+ const PHYSFS_ArchiveInfo info;
+
+
+ /*
+ * DIRECTORY ROUTINES:
+ * These functions are for dir handles. Generate a handle with the
+ * openArchive() method, then pass it as the "opaque" PHYSFS_Dir to the
+ * others.
+ *
+ * Symlinks should always be followed (except in stat()); PhysicsFS will
+ * use the stat() method to check for symlinks and make a judgement on
+ * whether to continue to call other methods based on that.
+ */
+
+ /*
+ * Open a dirhandle for dir/archive data provided by (io).
+ * (name) is a filename associated with (io), but doesn't necessarily
+ * map to anything, let alone a real filename. This possibly-
+ * meaningless name is in platform-dependent notation.
+ * (forWrite) is non-zero if this is to be used for
+ * the write directory, and zero if this is to be used for an
+ * element of the search path.
+ * Returns NULL on failure. We ignore any error code you set here.
+ * Returns non-NULL on success. The pointer returned will be
+ * passed as the "opaque" parameter for later calls.
+ */
+ PHYSFS_Dir *(*openArchive)(PHYSFS_Io *io, const char *name, int forWrite);
+
+ /*
+ * List all files in (dirname). Each file is passed to (cb),
+ * where a copy is made if appropriate, so you should dispose of
+ * it properly upon return from the callback.
+ * You should omit symlinks if (omitSymLinks) is non-zero.
+ * If you have a failure, report as much as you can.
+ * (dirname) is in platform-independent notation.
+ */
+ void (*enumerateFiles)(PHYSFS_Dir *opaque, const char *dirname,
+ int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+ const char *origdir, void *callbackdata);
+
+ /*
+ * Open file for reading.
+ * This filename, (fnm), is in platform-independent notation.
+ * If you can't handle multiple opens of the same file,
+ * you can opt to fail for the second call.
+ * Fail if the file does not exist.
+ * Returns NULL on failure, and calls __PHYSFS_setError().
+ * Returns non-NULL on success. The pointer returned will be
+ * passed as the "opaque" parameter for later file calls.
+ *
+ * Regardless of success or failure, please set *exists to
+ * non-zero if the file existed (even if it's a broken symlink!),
+ * zero if it did not.
+ */
+ PHYSFS_Io *(*openRead)(PHYSFS_Dir *opaque, const char *fnm, int *exists);
+
+ /*
+ * Open file for writing.
+ * If the file does not exist, it should be created. If it exists,
+ * it should be truncated to zero bytes. The writing
+ * offset should be the start of the file.
+ * This filename is in platform-independent notation.
+ * If you can't handle multiple opens of the same file,
+ * you can opt to fail for the second call.
+ * Returns NULL on failure, and calls __PHYSFS_setError().
+ * Returns non-NULL on success. The pointer returned will be
+ * passed as the "opaque" parameter for later file calls.
+ */
+ PHYSFS_Io *(*openWrite)(PHYSFS_Dir *opaque, const char *filename);
+
+ /*
+ * Open file for appending.
+ * If the file does not exist, it should be created. The writing
+ * offset should be the end of the file.
+ * This filename is in platform-independent notation.
+ * If you can't handle multiple opens of the same file,
+ * you can opt to fail for the second call.
+ * Returns NULL on failure, and calls __PHYSFS_setError().
+ * Returns non-NULL on success. The pointer returned will be
+ * passed as the "opaque" parameter for later file calls.
+ */
+ PHYSFS_Io *(*openAppend)(PHYSFS_Dir *opaque, const char *filename);
+
+ /*
+ * Delete a file in the archive/directory.
+ * Return non-zero on success, zero on failure.
+ * This filename is in platform-independent notation.
+ * This method may be NULL.
+ * On failure, call __PHYSFS_setError().
+ */
+ int (*remove)(PHYSFS_Dir *opaque, const char *filename);
+
+ /*
+ * Create a directory in the archive/directory.
+ * If the application is trying to make multiple dirs, PhysicsFS
+ * will split them up into multiple calls before passing them to
+ * your driver.
+ * Return non-zero on success, zero on failure.
+ * This filename is in platform-independent notation.
+ * This method may be NULL.
+ * On failure, call __PHYSFS_setError().
+ */
+ int (*mkdir)(PHYSFS_Dir *opaque, const char *filename);
+
+ /*
+ * Close directories/archives, and free any associated memory,
+ * including the original PHYSFS_Io and (opaque) itself, if
+ * applicable. Implementation can assume that it won't be called if
+ * there are still files open from this archive.
+ */
+ void (*closeArchive)(PHYSFS_Dir *opaque);
+
+ /*
+ * Obtain basic file metadata.
+ * Returns non-zero on success, zero on failure.
+ * On failure, call __PHYSFS_setError().
+ */
+ int (*stat)(PHYSFS_Dir *opaque, const char *fn,
+ int *exists, PHYSFS_Stat *stat);
+} PHYSFS_Archiver;
+
+
+/*
+ * Call this to set the message returned by PHYSFS_getLastError().
+ * Please only use the ERR_* constants above, or add new constants to the
+ * above group, but I want these all in one place.
+ *
+ * Calling this with a NULL argument is a safe no-op.
+ */
+void __PHYSFS_setError(const PHYSFS_ErrorCode err);
+
+
+/* This byteorder stuff was lifted from SDL. http://www.libsdl.org/ */
+#define PHYSFS_LIL_ENDIAN 1234
+#define PHYSFS_BIG_ENDIAN 4321
+
+#if defined(__i386__) || defined(__ia64__) || \
+ defined(_M_IX86) || defined(_M_IA64) || defined(_M_X64) || \
+ (defined(__alpha__) || defined(__alpha)) || \
+ defined(__arm__) || defined(ARM) || \
+ (defined(__mips__) && defined(__MIPSEL__)) || \
+ defined(__SYMBIAN32__) || \
+ defined(__x86_64__) || \
+ defined(__LITTLE_ENDIAN__)
+#define PHYSFS_BYTEORDER PHYSFS_LIL_ENDIAN
+#else
+#define PHYSFS_BYTEORDER PHYSFS_BIG_ENDIAN
+#endif
+
+
+/*
+ * When sorting the entries in an archive, we use a modified QuickSort.
+ * When there are less then PHYSFS_QUICKSORT_THRESHOLD entries left to sort,
+ * we switch over to a BubbleSort for the remainder. Tweak to taste.
+ *
+ * You can override this setting by defining PHYSFS_QUICKSORT_THRESHOLD
+ * before #including "physfs_internal.h".
+ */
+#ifndef PHYSFS_QUICKSORT_THRESHOLD
+#define PHYSFS_QUICKSORT_THRESHOLD 4
+#endif
+
+/*
+ * Sort an array (or whatever) of (max) elements. This uses a mixture of
+ * a QuickSort and BubbleSort internally.
+ * (cmpfn) is used to determine ordering, and (swapfn) does the actual
+ * swapping of elements in the list.
+ *
+ * See zip.c for an example.
+ */
+void __PHYSFS_sort(void *entries, size_t max,
+ int (*cmpfn)(void *, size_t, size_t),
+ void (*swapfn)(void *, size_t, size_t));
+
+/*
+ * This isn't a formal error code, it's just for BAIL_MACRO.
+ * It means: there was an error, but someone else already set it for us.
+ */
+#define ERRPASS PHYSFS_ERR_OK
+
+/* These get used all over for lessening code clutter. */
+#define BAIL_MACRO(e, r) do { if (e) __PHYSFS_setError(e); return r; } while (0)
+#define BAIL_IF_MACRO(c, e, r) do { if (c) { if (e) __PHYSFS_setError(e); return r; } } while (0)
+#define BAIL_MACRO_MUTEX(e, m, r) do { if (e) __PHYSFS_setError(e); __PHYSFS_platformReleaseMutex(m); return r; } while (0)
+#define BAIL_IF_MACRO_MUTEX(c, e, m, r) do { if (c) { if (e) __PHYSFS_setError(e); __PHYSFS_platformReleaseMutex(m); return r; } } while (0)
+#define GOTO_MACRO(e, g) do { if (e) __PHYSFS_setError(e); goto g; } while (0)
+#define GOTO_IF_MACRO(c, e, g) do { if (c) { if (e) __PHYSFS_setError(e); goto g; } } while (0)
+#define GOTO_MACRO_MUTEX(e, m, g) do { if (e) __PHYSFS_setError(e); __PHYSFS_platformReleaseMutex(m); goto g; } while (0)
+#define GOTO_IF_MACRO_MUTEX(c, e, m, g) do { if (c) { if (e) __PHYSFS_setError(e); __PHYSFS_platformReleaseMutex(m); goto g; } } while (0)
+
+#define __PHYSFS_ARRAYLEN(x) ( (sizeof (x)) / (sizeof (x[0])) )
+
+#ifdef PHYSFS_NO_64BIT_SUPPORT
+#define __PHYSFS_SI64(x) ((PHYSFS_sint64) (x))
+#define __PHYSFS_UI64(x) ((PHYSFS_uint64) (x))
+#elif (defined __GNUC__)
+#define __PHYSFS_SI64(x) x##LL
+#define __PHYSFS_UI64(x) x##ULL
+#elif (defined _MSC_VER)
+#define __PHYSFS_SI64(x) x##i64
+#define __PHYSFS_UI64(x) x##ui64
+#else
+#define __PHYSFS_SI64(x) ((PHYSFS_sint64) (x))
+#define __PHYSFS_UI64(x) ((PHYSFS_uint64) (x))
+#endif
+
+
+/*
+ * Check if a ui64 will fit in the platform's address space.
+ * The initial sizeof check will optimize this macro out entirely on
+ * 64-bit (and larger?!) platforms, and the other condition will
+ * return zero or non-zero if the variable will fit in the platform's
+ * size_t, suitable to pass to malloc. This is kinda messy, but effective.
+ */
+#define __PHYSFS_ui64FitsAddressSpace(s) ( \
+ (sizeof (PHYSFS_uint64) <= sizeof (size_t)) || \
+ ((s) < (__PHYSFS_UI64(0xFFFFFFFFFFFFFFFF) >> (64-(sizeof(size_t)*8)))) \
+)
+
+
+/*
+ * This is a strcasecmp() or stricmp() replacement that expects both strings
+ * to be in UTF-8 encoding. It will do "case folding" to decide if the
+ * Unicode codepoints in the strings match.
+ *
+ * It will report which string is "greater than" the other, but be aware that
+ * this doesn't necessarily mean anything: 'a' may be "less than" 'b', but
+ * a random Kanji codepoint has no meaningful alphabetically relationship to
+ * a Greek Lambda, but being able to assign a reliable "value" makes sorting
+ * algorithms possible, if not entirely sane. Most cases should treat the
+ * return value as "equal" or "not equal".
+ */
+int __PHYSFS_utf8stricmp(const char *s1, const char *s2);
+
+/*
+ * This works like __PHYSFS_utf8stricmp(), but takes a character (NOT BYTE
+ * COUNT) argument, like strcasencmp().
+ */
+int __PHYSFS_utf8strnicmp(const char *s1, const char *s2, PHYSFS_uint32 l);
+
+/*
+ * stricmp() that guarantees to only work with low ASCII. The C runtime
+ * stricmp() might try to apply a locale/codepage/etc, which we don't want.
+ */
+int __PHYSFS_stricmpASCII(const char *s1, const char *s2);
+
+/*
+ * strnicmp() that guarantees to only work with low ASCII. The C runtime
+ * strnicmp() might try to apply a locale/codepage/etc, which we don't want.
+ */
+int __PHYSFS_strnicmpASCII(const char *s1, const char *s2, PHYSFS_uint32 l);
+
+
+/*
+ * The current allocator. Not valid before PHYSFS_init is called!
+ */
+extern PHYSFS_Allocator __PHYSFS_AllocatorHooks;
+
+/* convenience macro to make this less cumbersome internally... */
+#define allocator __PHYSFS_AllocatorHooks
+
+/*
+ * Create a PHYSFS_Io for a file in the physical filesystem.
+ * This path is in platform-dependent notation. (mode) must be 'r', 'w', or
+ * 'a' for Read, Write, or Append.
+ */
+PHYSFS_Io *__PHYSFS_createNativeIo(const char *path, const int mode);
+
+/*
+ * Create a PHYSFS_Io for a buffer of memory (READ-ONLY). If you already
+ * have one of these, just use its duplicate() method, and it'll increment
+ * its refcount without allocating a copy of the buffer.
+ */
+PHYSFS_Io *__PHYSFS_createMemoryIo(const void *buf, PHYSFS_uint64 len,
+ void (*destruct)(void *));
+
+
+/*
+ * Read (len) bytes from (io) into (buf). Returns non-zero on success,
+ * zero on i/o error. Literally: "return (io->read(io, buf, len) == len);"
+ */
+int __PHYSFS_readAll(PHYSFS_Io *io, void *buf, const PHYSFS_uint64 len);
+
+
+/* These are shared between some archivers. */
+
+typedef struct
+{
+ char name[56];
+ PHYSFS_uint32 startPos;
+ PHYSFS_uint32 size;
+} UNPKentry;
+
+void UNPK_closeArchive(PHYSFS_Dir *opaque);
+PHYSFS_Dir *UNPK_openArchive(PHYSFS_Io *io,UNPKentry *e,const PHYSFS_uint32 n);
+void UNPK_enumerateFiles(PHYSFS_Dir *opaque, const char *dname,
+ int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+ const char *origdir, void *callbackdata);
+PHYSFS_Io *UNPK_openRead(PHYSFS_Dir *opaque, const char *fnm, int *fileExists);
+PHYSFS_Io *UNPK_openWrite(PHYSFS_Dir *opaque, const char *name);
+PHYSFS_Io *UNPK_openAppend(PHYSFS_Dir *opaque, const char *name);
+int UNPK_remove(PHYSFS_Dir *opaque, const char *name);
+int UNPK_mkdir(PHYSFS_Dir *opaque, const char *name);
+int UNPK_stat(PHYSFS_Dir *opaque, const char *fn, int *exist, PHYSFS_Stat *st);
+
+
+/*--------------------------------------------------------------------------*/
+/*--------------------------------------------------------------------------*/
+/*------------ ----------------*/
+/*------------ You MUST implement the following functions ----------------*/
+/*------------ if porting to a new platform. ----------------*/
+/*------------ (see platform/unix.c for an example) ----------------*/
+/*------------ ----------------*/
+/*--------------------------------------------------------------------------*/
+/*--------------------------------------------------------------------------*/
+
+
+/*
+ * The dir separator; '/' on unix, '\\' on win32, ":" on MacOS, etc...
+ * Obviously, this isn't a function. If you need more than one char for this,
+ * you'll need to pull some old pieces of PhysicsFS out of revision control.
+ */
+#if PHYSFS_PLATFORM_WINDOWS
+#define __PHYSFS_platformDirSeparator '\\'
+#else
+#define __PHYSFS_platformDirSeparator '/'
+#endif
+
+/*
+ * Initialize the platform. This is called when PHYSFS_init() is called from
+ * the application.
+ *
+ * Return zero if there was a catastrophic failure (which prevents you from
+ * functioning at all), and non-zero otherwise.
+ */
+int __PHYSFS_platformInit(void);
+
+
+/*
+ * Deinitialize the platform. This is called when PHYSFS_deinit() is called
+ * from the application. You can use this to clean up anything you've
+ * allocated in your platform driver.
+ *
+ * Return zero if there was a catastrophic failure (which prevents you from
+ * functioning at all), and non-zero otherwise.
+ */
+int __PHYSFS_platformDeinit(void);
+
+
+/*
+ * Open a file for reading. (filename) is in platform-dependent notation. The
+ * file pointer should be positioned on the first byte of the file.
+ *
+ * The return value will be some platform-specific datatype that is opaque to
+ * the caller; it could be a (FILE *) under Unix, or a (HANDLE *) under win32.
+ *
+ * The same file can be opened for read multiple times, and each should have
+ * a unique file handle; this is frequently employed to prevent race
+ * conditions in the archivers.
+ *
+ * Call __PHYSFS_setError() and return (NULL) if the file can't be opened.
+ */
+void *__PHYSFS_platformOpenRead(const char *filename);
+
+
+/*
+ * Open a file for writing. (filename) is in platform-dependent notation. If
+ * the file exists, it should be truncated to zero bytes, and if it doesn't
+ * exist, it should be created as a zero-byte file. The file pointer should
+ * be positioned on the first byte of the file.
+ *
+ * The return value will be some platform-specific datatype that is opaque to
+ * the caller; it could be a (FILE *) under Unix, or a (HANDLE *) under win32,
+ * etc.
+ *
+ * Opening a file for write multiple times has undefined results.
+ *
+ * Call __PHYSFS_setError() and return (NULL) if the file can't be opened.
+ */
+void *__PHYSFS_platformOpenWrite(const char *filename);
+
+
+/*
+ * Open a file for appending. (filename) is in platform-dependent notation. If
+ * the file exists, the file pointer should be place just past the end of the
+ * file, so that the first write will be one byte after the current end of
+ * the file. If the file doesn't exist, it should be created as a zero-byte
+ * file. The file pointer should be positioned on the first byte of the file.
+ *
+ * The return value will be some platform-specific datatype that is opaque to
+ * the caller; it could be a (FILE *) under Unix, or a (HANDLE *) under win32,
+ * etc.
+ *
+ * Opening a file for append multiple times has undefined results.
+ *
+ * Call __PHYSFS_setError() and return (NULL) if the file can't be opened.
+ */
+void *__PHYSFS_platformOpenAppend(const char *filename);
+
+/*
+ * Read more data from a platform-specific file handle. (opaque) should be
+ * cast to whatever data type your platform uses. Read a maximum of (len)
+ * 8-bit bytes to the area pointed to by (buf). If there isn't enough data
+ * available, return the number of bytes read, and position the file pointer
+ * immediately after those bytes.
+ * On success, return (len) and position the file pointer immediately past
+ * the end of the last read byte. Return (-1) if there is a catastrophic
+ * error, and call __PHYSFS_setError() to describe the problem; the file
+ * pointer should not move in such a case. A partial read is success; only
+ * return (-1) on total failure; presumably, the next read call after a
+ * partial read will fail as such.
+ */
+PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buf, PHYSFS_uint64 len);
+
+/*
+ * Write more data to a platform-specific file handle. (opaque) should be
+ * cast to whatever data type your platform uses. Write a maximum of (len)
+ * 8-bit bytes from the area pointed to by (buffer). If there is a problem,
+ * return the number of bytes written, and position the file pointer
+ * immediately after those bytes. Return (-1) if there is a catastrophic
+ * error, and call __PHYSFS_setError() to describe the problem; the file
+ * pointer should not move in such a case. A partial write is success; only
+ * return (-1) on total failure; presumably, the next write call after a
+ * partial write will fail as such.
+ */
+PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
+ PHYSFS_uint64 len);
+
+/*
+ * Set the file pointer to a new position. (opaque) should be cast to
+ * whatever data type your platform uses. (pos) specifies the number
+ * of 8-bit bytes to seek to from the start of the file. Seeking past the
+ * end of the file is an error condition, and you should check for it.
+ *
+ * Not all file types can seek; this is to be expected by the caller.
+ *
+ * On error, call __PHYSFS_setError() and return zero. On success, return
+ * a non-zero value.
+ */
+int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos);
+
+
+/*
+ * Get the file pointer's position, in an 8-bit byte offset from the start of
+ * the file. (opaque) should be cast to whatever data type your platform
+ * uses.
+ *
+ * Not all file types can "tell"; this is to be expected by the caller.
+ *
+ * On error, call __PHYSFS_setError() and return -1. On success, return >= 0.
+ */
+PHYSFS_sint64 __PHYSFS_platformTell(void *opaque);
+
+
+/*
+ * Determine the current size of a file, in 8-bit bytes, from an open file.
+ *
+ * The caller expects that this information may not be available for all
+ * file types on all platforms.
+ *
+ * Return -1 if you can't do it, and call __PHYSFS_setError(). Otherwise,
+ * return the file length in 8-bit bytes.
+ */
+PHYSFS_sint64 __PHYSFS_platformFileLength(void *handle);
+
+
+/*
+ * !!! FIXME: comment me.
+ */
+int __PHYSFS_platformStat(const char *fn, int *exists, PHYSFS_Stat *stat);
+
+/*
+ * Flush any pending writes to disk. (opaque) should be cast to whatever data
+ * type your platform uses. Be sure to check for errors; the caller expects
+ * that this function can fail if there was a flushing error, etc.
+ *
+ * Return zero on failure, non-zero on success.
+ */
+int __PHYSFS_platformFlush(void *opaque);
+
+/*
+ * Close file and deallocate resources. (opaque) should be cast to whatever
+ * data type your platform uses. This should close the file in any scenario:
+ * flushing is a separate function call, and this function should never fail.
+ *
+ * You should clean up all resources associated with (opaque); the pointer
+ * will be considered invalid after this call.
+ */
+void __PHYSFS_platformClose(void *opaque);
+
+/*
+ * Platform implementation of PHYSFS_getCdRomDirsCallback()...
+ * CD directories are discovered and reported to the callback one at a time.
+ * Pointers passed to the callback are assumed to be invalid to the
+ * application after the callback returns, so you can free them or whatever.
+ * Callback does not assume results will be sorted in any meaningful way.
+ */
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data);
+
+/*
+ * Calculate the base dir, if your platform needs special consideration.
+ * Just return NULL if the standard routines will suffice. (see
+ * calculateBaseDir() in physfs.c ...)
+ * Your string must end with a dir separator if you don't return NULL.
+ * Caller will allocator.Free() the retval if it's not NULL.
+ */
+char *__PHYSFS_platformCalcBaseDir(const char *argv0);
+
+/*
+ * Get the platform-specific user dir.
+ * As of PhysicsFS 2.1, returning NULL means fatal error.
+ * Your string must end with a dir separator if you don't return NULL.
+ * Caller will allocator.Free() the retval if it's not NULL.
+ */
+char *__PHYSFS_platformCalcUserDir(void);
+
+
+/* This is the cached version from PHYSFS_init(). This is a fast call. */
+const char *__PHYSFS_getUserDir(void); /* not deprecated internal version. */
+
+
+/*
+ * Get the platform-specific pref dir.
+ * Returning NULL means fatal error.
+ * Your string must end with a dir separator if you don't return NULL.
+ * Caller will allocator.Free() the retval if it's not NULL.
+ * Caller will make missing directories if necessary; this just reports
+ * the final path.
+ */
+char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app);
+
+
+/*
+ * Return a pointer that uniquely identifies the current thread.
+ * On a platform without threading, (0x1) will suffice. These numbers are
+ * arbitrary; the only requirement is that no two threads have the same
+ * pointer.
+ */
+void *__PHYSFS_platformGetThreadID(void);
+
+
+/*
+ * Enumerate a directory of files. This follows the rules for the
+ * PHYSFS_Archiver->enumerateFiles() method (see above), except that the
+ * (dirName) that is passed to this function is converted to
+ * platform-DEPENDENT notation by the caller. The PHYSFS_Archiver version
+ * uses platform-independent notation. Note that ".", "..", and other
+ * metaentries should always be ignored.
+ */
+void __PHYSFS_platformEnumerateFiles(const char *dirname,
+ int omitSymLinks,
+ PHYSFS_EnumFilesCallback callback,
+ const char *origdir,
+ void *callbackdata);
+
+/*
+ * Make a directory in the actual filesystem. (path) is specified in
+ * platform-dependent notation. On error, return zero and set the error
+ * message. Return non-zero on success.
+ */
+int __PHYSFS_platformMkDir(const char *path);
+
+
+/*
+ * Remove a file or directory entry in the actual filesystem. (path) is
+ * specified in platform-dependent notation. Note that this deletes files
+ * _and_ directories, so you might need to do some determination.
+ * Non-empty directories should report an error and not delete themselves
+ * or their contents.
+ *
+ * Deleting a symlink should remove the link, not what it points to.
+ *
+ * On error, return zero and set the error message. Return non-zero on success.
+ */
+int __PHYSFS_platformDelete(const char *path);
+
+
+/*
+ * Create a platform-specific mutex. This can be whatever datatype your
+ * platform uses for mutexes, but it is cast to a (void *) for abstractness.
+ *
+ * Return (NULL) if you couldn't create one. Systems without threads can
+ * return any arbitrary non-NULL value.
+ */
+void *__PHYSFS_platformCreateMutex(void);
+
+/*
+ * Destroy a platform-specific mutex, and clean up any resources associated
+ * with it. (mutex) is a value previously returned by
+ * __PHYSFS_platformCreateMutex(). This can be a no-op on single-threaded
+ * platforms.
+ */
+void __PHYSFS_platformDestroyMutex(void *mutex);
+
+/*
+ * Grab possession of a platform-specific mutex. Mutexes should be recursive;
+ * that is, the same thread should be able to call this function multiple
+ * times in a row without causing a deadlock. This function should block
+ * until a thread can gain possession of the mutex.
+ *
+ * Return non-zero if the mutex was grabbed, zero if there was an
+ * unrecoverable problem grabbing it (this should not be a matter of
+ * timing out! We're talking major system errors; block until the mutex
+ * is available otherwise.)
+ *
+ * _DO NOT_ call __PHYSFS_setError() in here! Since setError calls this
+ * function, you'll cause an infinite recursion. This means you can't
+ * use the BAIL_*MACRO* macros, either.
+ */
+int __PHYSFS_platformGrabMutex(void *mutex);
+
+/*
+ * Relinquish possession of the mutex when this method has been called
+ * once for each time that platformGrabMutex was called. Once possession has
+ * been released, the next thread in line to grab the mutex (if any) may
+ * proceed.
+ *
+ * _DO NOT_ call __PHYSFS_setError() in here! Since setError calls this
+ * function, you'll cause an infinite recursion. This means you can't
+ * use the BAIL_*MACRO* macros, either.
+ */
+void __PHYSFS_platformReleaseMutex(void *mutex);
+
+/*
+ * Called at the start of PHYSFS_init() to prepare the allocator, if the user
+ * hasn't selected their own allocator via PHYSFS_setAllocator().
+ * If the platform has a custom allocator, it should fill in the fields of
+ * (a) with the proper function pointers and return non-zero.
+ * If the platform just wants to use malloc()/free()/etc, return zero
+ * immediately and the higher level will handle it. The Init and Deinit
+ * fields of (a) are optional...set them to NULL if you don't need them.
+ * Everything else must be implemented. All rules follow those for
+ * PHYSFS_setAllocator(). If Init isn't NULL, it will be called shortly
+ * after this function returns non-zero.
+ */
+int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* end of physfs_internal.h ... */
+
diff -r 404ddce27b23 -r c13ebed437cb misc/libphysfs/physfs_miniz.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/physfs_miniz.h Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,698 @@
+/* tinfl.c v1.11 - public domain inflate with zlib header parsing/adler32 checking (inflate-only subset of miniz.c)
+ See "unlicense" statement at the end of this file.
+ Rich Geldreich , last updated May 20, 2011
+ Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt
+
+ The entire decompressor coroutine is implemented in tinfl_decompress(). The other functions are optional high-level helpers.
+*/
+#ifndef TINFL_HEADER_INCLUDED
+#define TINFL_HEADER_INCLUDED
+
+typedef PHYSFS_uint8 mz_uint8;
+typedef PHYSFS_sint16 mz_int16;
+typedef PHYSFS_uint16 mz_uint16;
+typedef PHYSFS_uint32 mz_uint32;
+typedef unsigned int mz_uint;
+typedef PHYSFS_uint64 mz_uint64;
+
+/* For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. */
+typedef unsigned long mz_ulong;
+
+/* Heap allocation callbacks. */
+typedef void *(*mz_alloc_func)(void *opaque, unsigned int items, unsigned int size);
+typedef void (*mz_free_func)(void *opaque, void *address);
+
+#if defined(_M_IX86) || defined(_M_X64)
+/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 if integer loads and stores to unaligned addresses are acceptable on the target platform (slightly faster). */
+#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
+/* Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. */
+#define MINIZ_LITTLE_ENDIAN 1
+#endif
+
+#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__)
+/* Set MINIZ_HAS_64BIT_REGISTERS to 1 if the processor has 64-bit general purpose registers (enables 64-bit bitbuffer in inflator) */
+#define MINIZ_HAS_64BIT_REGISTERS 1
+#endif
+
+/* Works around MSVC's spammy "warning C4127: conditional expression is constant" message. */
+#ifdef _MSC_VER
+#define MZ_MACRO_END while (0, 0)
+#else
+#define MZ_MACRO_END while (0)
+#endif
+
+/* Decompression flags. */
+enum
+{
+ TINFL_FLAG_PARSE_ZLIB_HEADER = 1,
+ TINFL_FLAG_HAS_MORE_INPUT = 2,
+ TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,
+ TINFL_FLAG_COMPUTE_ADLER32 = 8
+};
+
+struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor;
+
+/* Max size of LZ dictionary. */
+#define TINFL_LZ_DICT_SIZE 32768
+
+/* Return status. */
+typedef enum
+{
+ TINFL_STATUS_BAD_PARAM = -3,
+ TINFL_STATUS_ADLER32_MISMATCH = -2,
+ TINFL_STATUS_FAILED = -1,
+ TINFL_STATUS_DONE = 0,
+ TINFL_STATUS_NEEDS_MORE_INPUT = 1,
+ TINFL_STATUS_HAS_MORE_OUTPUT = 2
+} tinfl_status;
+
+/* Initializes the decompressor to its initial state. */
+#define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END
+#define tinfl_get_adler32(r) (r)->m_check_adler32
+
+/* Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. */
+/* This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. */
+static tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags);
+
+/* Internal/private bits follow. */
+enum
+{
+ TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19,
+ TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS
+};
+
+typedef struct
+{
+ mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0];
+ mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2];
+} tinfl_huff_table;
+
+#if MINIZ_HAS_64BIT_REGISTERS
+ #define TINFL_USE_64BIT_BITBUF 1
+#endif
+
+#if TINFL_USE_64BIT_BITBUF
+ typedef mz_uint64 tinfl_bit_buf_t;
+ #define TINFL_BITBUF_SIZE (64)
+#else
+ typedef mz_uint32 tinfl_bit_buf_t;
+ #define TINFL_BITBUF_SIZE (32)
+#endif
+
+struct tinfl_decompressor_tag
+{
+ mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES];
+ tinfl_bit_buf_t m_bit_buf;
+ size_t m_dist_from_out_buf_start;
+ tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES];
+ mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137];
+};
+
+#endif /* #ifdef TINFL_HEADER_INCLUDED */
+
+/* ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.) */
+
+#ifndef TINFL_HEADER_FILE_ONLY
+
+#define MZ_MAX(a,b) (((a)>(b))?(a):(b))
+#define MZ_MIN(a,b) (((a)<(b))?(a):(b))
+#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj))
+
+#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
+ #define MZ_READ_LE16(p) *((const mz_uint16 *)(p))
+ #define MZ_READ_LE32(p) *((const mz_uint32 *)(p))
+#else
+ #define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U))
+ #define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
+#endif
+
+#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l)
+#define TINFL_MEMSET(p, c, l) memset(p, c, l)
+
+#define TINFL_CR_BEGIN switch(r->m_state) { case 0:
+#define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END
+#define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END
+#define TINFL_CR_FINISH }
+
+/* TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never */
+/* reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario. */
+#define TINFL_GET_BYTE(state_index, c) do { \
+ if (pIn_buf_cur >= pIn_buf_end) { \
+ for ( ; ; ) { \
+ if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \
+ TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \
+ if (pIn_buf_cur < pIn_buf_end) { \
+ c = *pIn_buf_cur++; \
+ break; \
+ } \
+ } else { \
+ c = 0; \
+ break; \
+ } \
+ } \
+ } else c = *pIn_buf_cur++; } MZ_MACRO_END
+
+#define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n))
+#define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END
+#define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END
+
+/* TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. */
+/* It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a */
+/* Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the */
+/* bit buffer contains >=15 bits (deflate's max. Huffman code size). */
+#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \
+ do { \
+ temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \
+ if (temp >= 0) { \
+ code_len = temp >> 9; \
+ if ((code_len) && (num_bits >= code_len)) \
+ break; \
+ } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \
+ code_len = TINFL_FAST_LOOKUP_BITS; \
+ do { \
+ temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \
+ } while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \
+ } TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \
+ } while (num_bits < 15);
+
+/* TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read */
+/* beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully */
+/* decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. */
+/* The slow path is only executed at the very end of the input buffer. */
+#define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \
+ int temp; mz_uint code_len, c; \
+ if (num_bits < 15) { \
+ if ((pIn_buf_end - pIn_buf_cur) < 2) { \
+ TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \
+ } else { \
+ bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \
+ } \
+ } \
+ if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \
+ code_len = temp >> 9, temp &= 511; \
+ else { \
+ code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \
+ } sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END
+
+static tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags)
+{
+ static const int s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 };
+ static const int s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
+ static const int s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
+ static const int s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+ static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
+ static const int s_min_table_sizes[3] = { 257, 1, 4 };
+
+ tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf;
+ const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size;
+ mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size;
+ size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start;
+
+ /* Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). */
+ if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; }
+
+ num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start;
+ TINFL_CR_BEGIN
+
+ bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1;
+ if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
+ {
+ TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1);
+ counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8));
+ if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4)))));
+ if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); }
+ }
+
+ do
+ {
+ TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1;
+ if (r->m_type == 0)
+ {
+ TINFL_SKIP_BITS(5, num_bits & 7);
+ for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); }
+ if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); }
+ while ((counter) && (num_bits))
+ {
+ TINFL_GET_BITS(51, dist, 8);
+ while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); }
+ *pOut_buf_cur++ = (mz_uint8)dist;
+ counter--;
+ }
+ while (counter)
+ {
+ size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); }
+ while (pIn_buf_cur >= pIn_buf_end)
+ {
+ if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT)
+ {
+ TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT);
+ }
+ else
+ {
+ TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED);
+ }
+ }
+ n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter);
+ TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n;
+ }
+ }
+ else if (r->m_type == 3)
+ {
+ TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED);
+ }
+ else
+ {
+ if (r->m_type == 1)
+ {
+ mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i;
+ r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32);
+ for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8;
+ }
+ else
+ {
+ for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; }
+ MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; }
+ r->m_table_sizes[2] = 19;
+ }
+ for ( ; (int)r->m_type >= 0; r->m_type--)
+ {
+ int tree_next, tree_cur; tinfl_huff_table *pTable;
+ mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree);
+ for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++;
+ used_syms = 0, total = 0; next_code[0] = next_code[1] = 0;
+ for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); }
+ if ((65536 != total) && (used_syms > 1))
+ {
+ TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED);
+ }
+ for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index)
+ {
+ mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue;
+ cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1);
+ if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; }
+ if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; }
+ rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1);
+ for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--)
+ {
+ tree_cur -= ((rev_code >>= 1) & 1);
+ if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1];
+ }
+ tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index;
+ }
+ if (r->m_type == 2)
+ {
+ for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); )
+ {
+ mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; }
+ if ((dist == 16) && (!counter))
+ {
+ TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED);
+ }
+ num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16];
+ TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s;
+ }
+ if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter)
+ {
+ TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED);
+ }
+ TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]);
+ }
+ }
+ for ( ; ; )
+ {
+ mz_uint8 *pSrc;
+ for ( ; ; )
+ {
+ if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2))
+ {
+ TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]);
+ if (counter >= 256)
+ break;
+ while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); }
+ *pOut_buf_cur++ = (mz_uint8)counter;
+ }
+ else
+ {
+ int sym2; mz_uint code_len;
+#if TINFL_USE_64BIT_BITBUF
+ if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; }
+#else
+ if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
+#endif
+ if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
+ code_len = sym2 >> 9;
+ else
+ {
+ code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
+ }
+ counter = sym2; bit_buf >>= code_len; num_bits -= code_len;
+ if (counter & 256)
+ break;
+
+#if !TINFL_USE_64BIT_BITBUF
+ if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
+#endif
+ if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
+ code_len = sym2 >> 9;
+ else
+ {
+ code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
+ }
+ bit_buf >>= code_len; num_bits -= code_len;
+
+ pOut_buf_cur[0] = (mz_uint8)counter;
+ if (sym2 & 256)
+ {
+ pOut_buf_cur++;
+ counter = sym2;
+ break;
+ }
+ pOut_buf_cur[1] = (mz_uint8)sym2;
+ pOut_buf_cur += 2;
+ }
+ }
+ if ((counter &= 511) == 256) break;
+
+ num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257];
+ if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; }
+
+ TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]);
+ num_extra = s_dist_extra[dist]; dist = s_dist_base[dist];
+ if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; }
+
+ dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start;
+ if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))
+ {
+ TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED);
+ }
+
+ pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask);
+
+ if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end)
+ {
+ while (counter--)
+ {
+ while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); }
+ *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask];
+ }
+ continue;
+ }
+#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
+ else if ((counter >= 9) && (counter <= dist))
+ {
+ const mz_uint8 *pSrc_end = pSrc + (counter & ~7);
+ do
+ {
+ ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0];
+ ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1];
+ pOut_buf_cur += 8;
+ } while ((pSrc += 8) < pSrc_end);
+ if ((counter &= 7) < 3)
+ {
+ if (counter)
+ {
+ pOut_buf_cur[0] = pSrc[0];
+ if (counter > 1)
+ pOut_buf_cur[1] = pSrc[1];
+ pOut_buf_cur += counter;
+ }
+ continue;
+ }
+ }
+#endif
+ do
+ {
+ pOut_buf_cur[0] = pSrc[0];
+ pOut_buf_cur[1] = pSrc[1];
+ pOut_buf_cur[2] = pSrc[2];
+ pOut_buf_cur += 3; pSrc += 3;
+ } while ((int)(counter -= 3) > 2);
+ if ((int)counter > 0)
+ {
+ pOut_buf_cur[0] = pSrc[0];
+ if ((int)counter > 1)
+ pOut_buf_cur[1] = pSrc[1];
+ pOut_buf_cur += counter;
+ }
+ }
+ }
+ } while (!(r->m_final & 1));
+ if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
+ {
+ TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; }
+ }
+ TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE);
+ TINFL_CR_FINISH
+
+common_exit:
+ r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start;
+ *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next;
+ if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0))
+ {
+ const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size;
+ mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552;
+ while (buf_len)
+ {
+ for (i = 0; i + 7 < block_len; i += 8, ptr += 8)
+ {
+ s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1;
+ s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1;
+ }
+ for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1;
+ s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552;
+ }
+ r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH;
+ }
+ return status;
+}
+
+/* Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other stuff is for advanced use. */
+enum { MZ_NO_FLUSH = 0, MZ_PARTIAL_FLUSH = 1, MZ_SYNC_FLUSH = 2, MZ_FULL_FLUSH = 3, MZ_FINISH = 4, MZ_BLOCK = 5 };
+
+/* Return status codes. MZ_PARAM_ERROR is non-standard. */
+enum { MZ_OK = 0, MZ_STREAM_END = 1, MZ_NEED_DICT = 2, MZ_ERRNO = -1, MZ_STREAM_ERROR = -2, MZ_DATA_ERROR = -3, MZ_MEM_ERROR = -4, MZ_BUF_ERROR = -5, MZ_VERSION_ERROR = -6, MZ_PARAM_ERROR = -10000 };
+
+/* Compression levels. */
+enum { MZ_NO_COMPRESSION = 0, MZ_BEST_SPEED = 1, MZ_BEST_COMPRESSION = 9, MZ_DEFAULT_COMPRESSION = -1 };
+
+/* Window bits */
+#define MZ_DEFAULT_WINDOW_BITS 15
+
+struct mz_internal_state;
+
+/* Compression/decompression stream struct. */
+typedef struct mz_stream_s
+{
+ const unsigned char *next_in; /* pointer to next byte to read */
+ unsigned int avail_in; /* number of bytes available at next_in */
+ mz_ulong total_in; /* total number of bytes consumed so far */
+
+ unsigned char *next_out; /* pointer to next byte to write */
+ unsigned int avail_out; /* number of bytes that can be written to next_out */
+ mz_ulong total_out; /* total number of bytes produced so far */
+
+ char *msg; /* error msg (unused) */
+ struct mz_internal_state *state; /* internal state, allocated by zalloc/zfree */
+
+ mz_alloc_func zalloc; /* optional heap allocation function (defaults to malloc) */
+ mz_free_func zfree; /* optional heap free function (defaults to free) */
+ void *opaque; /* heap alloc function user pointer */
+
+ int data_type; /* data_type (unused) */
+ mz_ulong adler; /* adler32 of the source or uncompressed data */
+ mz_ulong reserved; /* not used */
+} mz_stream;
+
+typedef mz_stream *mz_streamp;
+
+
+typedef struct
+{
+ tinfl_decompressor m_decomp;
+ mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; int m_window_bits;
+ mz_uint8 m_dict[TINFL_LZ_DICT_SIZE];
+ tinfl_status m_last_status;
+} inflate_state;
+
+static int mz_inflateInit2(mz_streamp pStream, int window_bits)
+{
+ inflate_state *pDecomp;
+ if (!pStream) return MZ_STREAM_ERROR;
+ if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) return MZ_PARAM_ERROR;
+
+ pStream->data_type = 0;
+ pStream->adler = 0;
+ pStream->msg = NULL;
+ pStream->total_in = 0;
+ pStream->total_out = 0;
+ pStream->reserved = 0;
+ /* if (!pStream->zalloc) pStream->zalloc = def_alloc_func; */
+ /* if (!pStream->zfree) pStream->zfree = def_free_func; */
+
+ pDecomp = (inflate_state*)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state));
+ if (!pDecomp) return MZ_MEM_ERROR;
+
+ pStream->state = (struct mz_internal_state *)pDecomp;
+
+ tinfl_init(&pDecomp->m_decomp);
+ pDecomp->m_dict_ofs = 0;
+ pDecomp->m_dict_avail = 0;
+ pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT;
+ pDecomp->m_first_call = 1;
+ pDecomp->m_has_flushed = 0;
+ pDecomp->m_window_bits = window_bits;
+
+ return MZ_OK;
+}
+
+static int mz_inflate(mz_streamp pStream, int flush)
+{
+ inflate_state* pState;
+ mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32;
+ size_t in_bytes, out_bytes, orig_avail_in;
+ tinfl_status status;
+
+ if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR;
+ if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH;
+ if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) return MZ_STREAM_ERROR;
+
+ pState = (inflate_state*)pStream->state;
+ if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER;
+ orig_avail_in = pStream->avail_in;
+
+ first_call = pState->m_first_call; pState->m_first_call = 0;
+ if (pState->m_last_status < 0) return MZ_DATA_ERROR;
+
+ if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR;
+ pState->m_has_flushed |= (flush == MZ_FINISH);
+
+ if ((flush == MZ_FINISH) && (first_call))
+ {
+ /* MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. */
+ decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;
+ in_bytes = pStream->avail_in; out_bytes = pStream->avail_out;
+ status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags);
+ pState->m_last_status = status;
+ pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes;
+ pStream->adler = tinfl_get_adler32(&pState->m_decomp);
+ pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes;
+
+ if (status < 0)
+ return MZ_DATA_ERROR;
+ else if (status != TINFL_STATUS_DONE)
+ {
+ pState->m_last_status = TINFL_STATUS_FAILED;
+ return MZ_BUF_ERROR;
+ }
+ return MZ_STREAM_END;
+ }
+ /* flush != MZ_FINISH then we must assume there's more input. */
+ if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT;
+
+ if (pState->m_dict_avail)
+ {
+ n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
+ memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
+ pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n;
+ pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
+ return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK;
+ }
+
+ for ( ; ; )
+ {
+ in_bytes = pStream->avail_in;
+ out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs;
+
+ status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags);
+ pState->m_last_status = status;
+
+ pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes;
+ pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp);
+
+ pState->m_dict_avail = (mz_uint)out_bytes;
+
+ n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
+ memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
+ pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n;
+ pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
+
+ if (status < 0)
+ return MZ_DATA_ERROR; /* Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). */
+ else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in))
+ return MZ_BUF_ERROR; /* Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. */
+ else if (flush == MZ_FINISH)
+ {
+ /* The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. */
+ if (status == TINFL_STATUS_DONE)
+ return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END;
+ /* status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. */
+ else if (!pStream->avail_out)
+ return MZ_BUF_ERROR;
+ }
+ else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail))
+ break;
+ }
+
+ return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK;
+}
+
+static int mz_inflateEnd(mz_streamp pStream)
+{
+ if (!pStream)
+ return MZ_STREAM_ERROR;
+ if (pStream->state)
+ {
+ pStream->zfree(pStream->opaque, pStream->state);
+ pStream->state = NULL;
+ }
+ return MZ_OK;
+}
+
+/* make this a drop-in replacement for zlib... */
+ #define voidpf void*
+ #define uInt unsigned int
+ #define z_stream mz_stream
+ #define inflateInit2 mz_inflateInit2
+ #define inflate mz_inflate
+ #define inflateEnd mz_inflateEnd
+ #define Z_SYNC_FLUSH MZ_SYNC_FLUSH
+ #define Z_FINISH MZ_FINISH
+ #define Z_OK MZ_OK
+ #define Z_STREAM_END MZ_STREAM_END
+ #define Z_NEED_DICT MZ_NEED_DICT
+ #define Z_ERRNO MZ_ERRNO
+ #define Z_STREAM_ERROR MZ_STREAM_ERROR
+ #define Z_DATA_ERROR MZ_DATA_ERROR
+ #define Z_MEM_ERROR MZ_MEM_ERROR
+ #define Z_BUF_ERROR MZ_BUF_ERROR
+ #define Z_VERSION_ERROR MZ_VERSION_ERROR
+ #define MAX_WBITS 15
+
+#endif /* #ifndef TINFL_HEADER_FILE_ONLY */
+
+/*
+ This is free and unencumbered software released into the public domain.
+
+ Anyone is free to copy, modify, publish, use, compile, sell, or
+ distribute this software, either in source code form or as a compiled
+ binary, for any purpose, commercial or non-commercial, and by any
+ means.
+
+ In jurisdictions that recognize copyright laws, the author or authors
+ of this software dedicate any and all copyright interest in the
+ software to the public domain. We make this dedication for the benefit
+ of the public at large and to the detriment of our heirs and
+ successors. We intend this dedication to be an overt act of
+ relinquishment in perpetuity of all present and future rights to this
+ software under copyright law.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+
+ For more information, please refer to
+*/
diff -r 404ddce27b23 -r c13ebed437cb misc/libphysfs/physfs_platforms.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/physfs_platforms.h Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,58 @@
+#ifndef _INCL_PHYSFS_PLATFORMS
+#define _INCL_PHYSFS_PLATFORMS
+
+#ifndef __PHYSICSFS_INTERNAL__
+#error Do not include this header from your applications.
+#endif
+
+/*
+ * These only define the platforms to determine which files in the platforms
+ * directory should be compiled. For example, technically BeOS can be called
+ * a "unix" system, but since it doesn't use unix.c, we don't define
+ * PHYSFS_PLATFORM_UNIX on that system.
+ */
+
+#if (defined __HAIKU__)
+# define PHYSFS_PLATFORM_HAIKU 1
+# define PHYSFS_PLATFORM_BEOS 1
+# define PHYSFS_PLATFORM_POSIX 1
+#elif ((defined __BEOS__) || (defined __beos__))
+# define PHYSFS_PLATFORM_BEOS 1
+# define PHYSFS_PLATFORM_POSIX 1
+#elif (defined _WIN32_WCE) || (defined _WIN64_WCE)
+# error PocketPC support was dropped from PhysicsFS 2.1. Sorry.
+#elif (((defined _WIN32) || (defined _WIN64)) && (!defined __CYGWIN__))
+# define PHYSFS_PLATFORM_WINDOWS 1
+#elif (defined OS2)
+# error OS/2 support was dropped from PhysicsFS 2.1. Sorry.
+#elif ((defined __MACH__) && (defined __APPLE__))
+/* To check if iphone or not, we need to include this file */
+# include
+# if ((TARGET_IPHONE_SIMULATOR) || (TARGET_OS_IPHONE))
+# define PHYSFS_NO_CDROM_SUPPORT 1
+# endif
+# define PHYSFS_PLATFORM_MACOSX 1
+# define PHYSFS_PLATFORM_POSIX 1
+#elif defined(macintosh)
+# error Classic Mac OS support was dropped from PhysicsFS 2.0. Move to OS X.
+#elif defined(__linux)
+# define PHYSFS_PLATFORM_LINUX 1
+# define PHYSFS_PLATFORM_UNIX 1
+# define PHYSFS_PLATFORM_POSIX 1
+#elif defined(__sun) || defined(sun)
+# define PHYSFS_PLATFORM_SOLARIS 1
+# define PHYSFS_PLATFORM_UNIX 1
+# define PHYSFS_PLATFORM_POSIX 1
+#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__)
+# define PHYSFS_PLATFORM_BSD 1
+# define PHYSFS_PLATFORM_UNIX 1
+# define PHYSFS_PLATFORM_POSIX 1
+#elif defined(unix) || defined(__unix__)
+# define PHYSFS_PLATFORM_UNIX 1
+# define PHYSFS_PLATFORM_POSIX 1
+#else
+# error Unknown platform.
+#endif
+
+#endif /* include-once blocker. */
+
diff -r 404ddce27b23 -r c13ebed437cb misc/libphysfs/physfs_unicode.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/physfs_unicode.c Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,528 @@
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+
+/*
+ * From rfc3629, the UTF-8 spec:
+ * http://www.ietf.org/rfc/rfc3629.txt
+ *
+ * Char. number range | UTF-8 octet sequence
+ * (hexadecimal) | (binary)
+ * --------------------+---------------------------------------------
+ * 0000 0000-0000 007F | 0xxxxxxx
+ * 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
+ * 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
+ * 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ */
+
+
+/*
+ * This may not be the best value, but it's one that isn't represented
+ * in Unicode (0x10FFFF is the largest codepoint value). We return this
+ * value from utf8codepoint() if there's bogus bits in the
+ * stream. utf8codepoint() will turn this value into something
+ * reasonable (like a question mark), for text that wants to try to recover,
+ * whereas utf8valid() will use the value to determine if a string has bad
+ * bits.
+ */
+#define UNICODE_BOGUS_CHAR_VALUE 0xFFFFFFFF
+
+/*
+ * This is the codepoint we currently return when there was bogus bits in a
+ * UTF-8 string. May not fly in Asian locales?
+ */
+#define UNICODE_BOGUS_CHAR_CODEPOINT '?'
+
+static PHYSFS_uint32 utf8codepoint(const char **_str)
+{
+ const char *str = *_str;
+ PHYSFS_uint32 retval = 0;
+ PHYSFS_uint32 octet = (PHYSFS_uint32) ((PHYSFS_uint8) *str);
+ PHYSFS_uint32 octet2, octet3, octet4;
+
+ if (octet == 0) /* null terminator, end of string. */
+ return 0;
+
+ else if (octet < 128) /* one octet char: 0 to 127 */
+ {
+ (*_str)++; /* skip to next possible start of codepoint. */
+ return octet;
+ } /* else if */
+
+ else if ((octet > 127) && (octet < 192)) /* bad (starts with 10xxxxxx). */
+ {
+ /*
+ * Apparently each of these is supposed to be flagged as a bogus
+ * char, instead of just resyncing to the next valid codepoint.
+ */
+ (*_str)++; /* skip to next possible start of codepoint. */
+ return UNICODE_BOGUS_CHAR_VALUE;
+ } /* else if */
+
+ else if (octet < 224) /* two octets */
+ {
+ (*_str)++; /* advance at least one byte in case of an error */
+ octet -= (128+64);
+ octet2 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+ if ((octet2 & (128+64)) != 128) /* Format isn't 10xxxxxx? */
+ return UNICODE_BOGUS_CHAR_VALUE;
+
+ *_str += 1; /* skip to next possible start of codepoint. */
+ retval = ((octet << 6) | (octet2 - 128));
+ if ((retval >= 0x80) && (retval <= 0x7FF))
+ return retval;
+ } /* else if */
+
+ else if (octet < 240) /* three octets */
+ {
+ (*_str)++; /* advance at least one byte in case of an error */
+ octet -= (128+64+32);
+ octet2 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+ if ((octet2 & (128+64)) != 128) /* Format isn't 10xxxxxx? */
+ return UNICODE_BOGUS_CHAR_VALUE;
+
+ octet3 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+ if ((octet3 & (128+64)) != 128) /* Format isn't 10xxxxxx? */
+ return UNICODE_BOGUS_CHAR_VALUE;
+
+ *_str += 2; /* skip to next possible start of codepoint. */
+ retval = ( ((octet << 12)) | ((octet2-128) << 6) | ((octet3-128)) );
+
+ /* There are seven "UTF-16 surrogates" that are illegal in UTF-8. */
+ switch (retval)
+ {
+ case 0xD800:
+ case 0xDB7F:
+ case 0xDB80:
+ case 0xDBFF:
+ case 0xDC00:
+ case 0xDF80:
+ case 0xDFFF:
+ return UNICODE_BOGUS_CHAR_VALUE;
+ } /* switch */
+
+ /* 0xFFFE and 0xFFFF are illegal, too, so we check them at the edge. */
+ if ((retval >= 0x800) && (retval <= 0xFFFD))
+ return retval;
+ } /* else if */
+
+ else if (octet < 248) /* four octets */
+ {
+ (*_str)++; /* advance at least one byte in case of an error */
+ octet -= (128+64+32+16);
+ octet2 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+ if ((octet2 & (128+64)) != 128) /* Format isn't 10xxxxxx? */
+ return UNICODE_BOGUS_CHAR_VALUE;
+
+ octet3 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+ if ((octet3 & (128+64)) != 128) /* Format isn't 10xxxxxx? */
+ return UNICODE_BOGUS_CHAR_VALUE;
+
+ octet4 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+ if ((octet4 & (128+64)) != 128) /* Format isn't 10xxxxxx? */
+ return UNICODE_BOGUS_CHAR_VALUE;
+
+ *_str += 3; /* skip to next possible start of codepoint. */
+ retval = ( ((octet << 18)) | ((octet2 - 128) << 12) |
+ ((octet3 - 128) << 6) | ((octet4 - 128)) );
+ if ((retval >= 0x10000) && (retval <= 0x10FFFF))
+ return retval;
+ } /* else if */
+
+ /*
+ * Five and six octet sequences became illegal in rfc3629.
+ * We throw the codepoint away, but parse them to make sure we move
+ * ahead the right number of bytes and don't overflow the buffer.
+ */
+
+ else if (octet < 252) /* five octets */
+ {
+ (*_str)++; /* advance at least one byte in case of an error */
+ octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+ if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */
+ return UNICODE_BOGUS_CHAR_VALUE;
+
+ octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+ if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */
+ return UNICODE_BOGUS_CHAR_VALUE;
+
+ octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+ if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */
+ return UNICODE_BOGUS_CHAR_VALUE;
+
+ octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+ if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */
+ return UNICODE_BOGUS_CHAR_VALUE;
+
+ *_str += 4; /* skip to next possible start of codepoint. */
+ return UNICODE_BOGUS_CHAR_VALUE;
+ } /* else if */
+
+ else /* six octets */
+ {
+ (*_str)++; /* advance at least one byte in case of an error */
+ octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+ if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */
+ return UNICODE_BOGUS_CHAR_VALUE;
+
+ octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+ if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */
+ return UNICODE_BOGUS_CHAR_VALUE;
+
+ octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+ if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */
+ return UNICODE_BOGUS_CHAR_VALUE;
+
+ octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+ if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */
+ return UNICODE_BOGUS_CHAR_VALUE;
+
+ octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+ if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */
+ return UNICODE_BOGUS_CHAR_VALUE;
+
+ *_str += 6; /* skip to next possible start of codepoint. */
+ return UNICODE_BOGUS_CHAR_VALUE;
+ } /* else if */
+
+ return UNICODE_BOGUS_CHAR_VALUE;
+} /* utf8codepoint */
+
+
+void PHYSFS_utf8ToUcs4(const char *src, PHYSFS_uint32 *dst, PHYSFS_uint64 len)
+{
+ len -= sizeof (PHYSFS_uint32); /* save room for null char. */
+ while (len >= sizeof (PHYSFS_uint32))
+ {
+ PHYSFS_uint32 cp = utf8codepoint(&src);
+ if (cp == 0)
+ break;
+ else if (cp == UNICODE_BOGUS_CHAR_VALUE)
+ cp = UNICODE_BOGUS_CHAR_CODEPOINT;
+ *(dst++) = cp;
+ len -= sizeof (PHYSFS_uint32);
+ } /* while */
+
+ *dst = 0;
+} /* PHYSFS_utf8ToUcs4 */
+
+
+void PHYSFS_utf8ToUcs2(const char *src, PHYSFS_uint16 *dst, PHYSFS_uint64 len)
+{
+ len -= sizeof (PHYSFS_uint16); /* save room for null char. */
+ while (len >= sizeof (PHYSFS_uint16))
+ {
+ PHYSFS_uint32 cp = utf8codepoint(&src);
+ if (cp == 0)
+ break;
+ else if (cp == UNICODE_BOGUS_CHAR_VALUE)
+ cp = UNICODE_BOGUS_CHAR_CODEPOINT;
+
+ if (cp > 0xFFFF) /* UTF-16 surrogates (bogus chars in UCS-2) */
+ cp = UNICODE_BOGUS_CHAR_CODEPOINT;
+
+ *(dst++) = cp;
+ len -= sizeof (PHYSFS_uint16);
+ } /* while */
+
+ *dst = 0;
+} /* PHYSFS_utf8ToUcs2 */
+
+
+void PHYSFS_utf8ToUtf16(const char *src, PHYSFS_uint16 *dst, PHYSFS_uint64 len)
+{
+ len -= sizeof (PHYSFS_uint16); /* save room for null char. */
+ while (len >= sizeof (PHYSFS_uint16))
+ {
+ PHYSFS_uint32 cp = utf8codepoint(&src);
+ if (cp == 0)
+ break;
+ else if (cp == UNICODE_BOGUS_CHAR_VALUE)
+ cp = UNICODE_BOGUS_CHAR_CODEPOINT;
+
+ if (cp > 0xFFFF) /* encode as surrogate pair */
+ {
+ if (len < (sizeof (PHYSFS_uint16) * 2))
+ break; /* not enough room for the pair, stop now. */
+
+ cp -= 0x10000; /* Make this a 20-bit value */
+
+ *(dst++) = 0xD800 + ((cp >> 10) & 0x3FF);
+ len -= sizeof (PHYSFS_uint16);
+
+ cp = 0xDC00 + (cp & 0x3FF);
+ } /* if */
+
+ *(dst++) = cp;
+ len -= sizeof (PHYSFS_uint16);
+ } /* while */
+
+ *dst = 0;
+} /* PHYSFS_utf8ToUtf16 */
+
+static void utf8fromcodepoint(PHYSFS_uint32 cp, char **_dst, PHYSFS_uint64 *_len)
+{
+ char *dst = *_dst;
+ PHYSFS_uint64 len = *_len;
+
+ if (len == 0)
+ return;
+
+ if (cp > 0x10FFFF)
+ cp = UNICODE_BOGUS_CHAR_CODEPOINT;
+ else if ((cp == 0xFFFE) || (cp == 0xFFFF)) /* illegal values. */
+ cp = UNICODE_BOGUS_CHAR_CODEPOINT;
+ else
+ {
+ /* There are seven "UTF-16 surrogates" that are illegal in UTF-8. */
+ switch (cp)
+ {
+ case 0xD800:
+ case 0xDB7F:
+ case 0xDB80:
+ case 0xDBFF:
+ case 0xDC00:
+ case 0xDF80:
+ case 0xDFFF:
+ cp = UNICODE_BOGUS_CHAR_CODEPOINT;
+ } /* switch */
+ } /* else */
+
+ /* Do the encoding... */
+ if (cp < 0x80)
+ {
+ *(dst++) = (char) cp;
+ len--;
+ } /* if */
+
+ else if (cp < 0x800)
+ {
+ if (len < 2)
+ len = 0;
+ else
+ {
+ *(dst++) = (char) ((cp >> 6) | 128 | 64);
+ *(dst++) = (char) (cp & 0x3F) | 128;
+ len -= 2;
+ } /* else */
+ } /* else if */
+
+ else if (cp < 0x10000)
+ {
+ if (len < 3)
+ len = 0;
+ else
+ {
+ *(dst++) = (char) ((cp >> 12) | 128 | 64 | 32);
+ *(dst++) = (char) ((cp >> 6) & 0x3F) | 128;
+ *(dst++) = (char) (cp & 0x3F) | 128;
+ len -= 3;
+ } /* else */
+ } /* else if */
+
+ else
+ {
+ if (len < 4)
+ len = 0;
+ else
+ {
+ *(dst++) = (char) ((cp >> 18) | 128 | 64 | 32 | 16);
+ *(dst++) = (char) ((cp >> 12) & 0x3F) | 128;
+ *(dst++) = (char) ((cp >> 6) & 0x3F) | 128;
+ *(dst++) = (char) (cp & 0x3F) | 128;
+ len -= 4;
+ } /* else if */
+ } /* else */
+
+ *_dst = dst;
+ *_len = len;
+} /* utf8fromcodepoint */
+
+#define UTF8FROMTYPE(typ, src, dst, len) \
+ if (len == 0) return; \
+ len--; \
+ while (len) \
+ { \
+ const PHYSFS_uint32 cp = (PHYSFS_uint32) ((typ) (*(src++))); \
+ if (cp == 0) break; \
+ utf8fromcodepoint(cp, &dst, &len); \
+ } \
+ *dst = '\0'; \
+
+void PHYSFS_utf8FromUcs4(const PHYSFS_uint32 *src, char *dst, PHYSFS_uint64 len)
+{
+ UTF8FROMTYPE(PHYSFS_uint32, src, dst, len);
+} /* PHYSFS_utf8FromUcs4 */
+
+void PHYSFS_utf8FromUcs2(const PHYSFS_uint16 *src, char *dst, PHYSFS_uint64 len)
+{
+ UTF8FROMTYPE(PHYSFS_uint64, src, dst, len);
+} /* PHYSFS_utf8FromUcs2 */
+
+/* latin1 maps to unicode codepoints directly, we just utf-8 encode it. */
+void PHYSFS_utf8FromLatin1(const char *src, char *dst, PHYSFS_uint64 len)
+{
+ UTF8FROMTYPE(PHYSFS_uint8, src, dst, len);
+} /* PHYSFS_utf8FromLatin1 */
+
+#undef UTF8FROMTYPE
+
+
+void PHYSFS_utf8FromUtf16(const PHYSFS_uint16 *src, char *dst, PHYSFS_uint64 len)
+{
+ if (len == 0)
+ return;
+
+ len--;
+ while (len)
+ {
+ PHYSFS_uint32 cp = (PHYSFS_uint32) *(src++);
+ if (cp == 0)
+ break;
+
+ /* Orphaned second half of surrogate pair? */
+ if ((cp >= 0xDC00) && (cp <= 0xDFFF))
+ cp = UNICODE_BOGUS_CHAR_CODEPOINT;
+ else if ((cp >= 0xD800) && (cp <= 0xDBFF)) /* start surrogate pair! */
+ {
+ const PHYSFS_uint32 pair = (PHYSFS_uint32) *src;
+ if ((pair < 0xDC00) || (pair > 0xDFFF))
+ cp = UNICODE_BOGUS_CHAR_CODEPOINT;
+ else
+ {
+ src++; /* eat the other surrogate. */
+ cp = (((cp - 0xD800) << 10) | (pair - 0xDC00));
+ } /* else */
+ } /* else if */
+
+ utf8fromcodepoint(cp, &dst, &len);
+ } /* while */
+
+ *dst = '\0';
+} /* PHYSFS_utf8FromUtf16 */
+
+
+typedef struct CaseFoldMapping
+{
+ PHYSFS_uint32 from;
+ PHYSFS_uint32 to0;
+ PHYSFS_uint32 to1;
+ PHYSFS_uint32 to2;
+} CaseFoldMapping;
+
+typedef struct CaseFoldHashBucket
+{
+ const PHYSFS_uint8 count;
+ const CaseFoldMapping *list;
+} CaseFoldHashBucket;
+
+#include "physfs_casefolding.h"
+
+static void locate_case_fold_mapping(const PHYSFS_uint32 from,
+ PHYSFS_uint32 *to)
+{
+ PHYSFS_uint32 i;
+ const PHYSFS_uint8 hashed = ((from ^ (from >> 8)) & 0xFF);
+ const CaseFoldHashBucket *bucket = &case_fold_hash[hashed];
+ const CaseFoldMapping *mapping = bucket->list;
+
+ for (i = 0; i < bucket->count; i++, mapping++)
+ {
+ if (mapping->from == from)
+ {
+ to[0] = mapping->to0;
+ to[1] = mapping->to1;
+ to[2] = mapping->to2;
+ return;
+ } /* if */
+ } /* for */
+
+ /* Not found...there's no remapping for this codepoint. */
+ to[0] = from;
+ to[1] = 0;
+ to[2] = 0;
+} /* locate_case_fold_mapping */
+
+
+static int utf8codepointcmp(const PHYSFS_uint32 cp1, const PHYSFS_uint32 cp2)
+{
+ PHYSFS_uint32 folded1[3], folded2[3];
+ locate_case_fold_mapping(cp1, folded1);
+ locate_case_fold_mapping(cp2, folded2);
+ return ( (folded1[0] == folded2[0]) &&
+ (folded1[1] == folded2[1]) &&
+ (folded1[2] == folded2[2]) );
+} /* utf8codepointcmp */
+
+
+int __PHYSFS_utf8stricmp(const char *str1, const char *str2)
+{
+ while (1)
+ {
+ const PHYSFS_uint32 cp1 = utf8codepoint(&str1);
+ const PHYSFS_uint32 cp2 = utf8codepoint(&str2);
+ if (!utf8codepointcmp(cp1, cp2)) break;
+ if (cp1 == 0) return 1;
+ } /* while */
+
+ return 0;
+} /* __PHYSFS_utf8stricmp */
+
+
+int __PHYSFS_utf8strnicmp(const char *str1, const char *str2, PHYSFS_uint32 n)
+{
+ while (n > 0)
+ {
+ const PHYSFS_uint32 cp1 = utf8codepoint(&str1);
+ const PHYSFS_uint32 cp2 = utf8codepoint(&str2);
+ if (!utf8codepointcmp(cp1, cp2)) return 0;
+ if (cp1 == 0) return 1;
+ n--;
+ } /* while */
+
+ return 1; /* matched to n chars. */
+} /* __PHYSFS_utf8strnicmp */
+
+
+int __PHYSFS_stricmpASCII(const char *str1, const char *str2)
+{
+ while (1)
+ {
+ const char ch1 = *(str1++);
+ const char ch2 = *(str2++);
+ const char cp1 = ((ch1 >= 'A') && (ch1 <= 'Z')) ? (ch1+32) : ch1;
+ const char cp2 = ((ch2 >= 'A') && (ch2 <= 'Z')) ? (ch2+32) : ch2;
+ if (cp1 < cp2)
+ return -1;
+ else if (cp1 > cp2)
+ return 1;
+ else if (cp1 == 0) /* they're both null chars? */
+ break;
+ } /* while */
+
+ return 0;
+} /* __PHYSFS_stricmpASCII */
+
+
+int __PHYSFS_strnicmpASCII(const char *str1, const char *str2, PHYSFS_uint32 n)
+{
+ while (n-- > 0)
+ {
+ const char ch1 = *(str1++);
+ const char ch2 = *(str2++);
+ const char cp1 = ((ch1 >= 'A') && (ch1 <= 'Z')) ? (ch1+32) : ch1;
+ const char cp2 = ((ch2 >= 'A') && (ch2 <= 'Z')) ? (ch2+32) : ch2;
+ if (cp1 < cp2)
+ return -1;
+ else if (cp1 > cp2)
+ return 1;
+ else if (cp1 == 0) /* they're both null chars? */
+ return 0;
+ } /* while */
+
+ return 0;
+} /* __PHYSFS_strnicmpASCII */
+
+
+/* end of physfs_unicode.c ... */
+
diff -r 404ddce27b23 -r c13ebed437cb misc/libphysfs/platform_beos.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/platform_beos.cpp Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,239 @@
+/*
+ * BeOS platform-dependent support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ * This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_platforms.h"
+
+#ifdef PHYSFS_PLATFORM_BEOS
+
+#ifdef PHYSFS_PLATFORM_HAIKU
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#else
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#endif
+
+#include
+#include
+
+#include "physfs_internal.h"
+
+int __PHYSFS_platformInit(void)
+{
+ return 1; /* always succeed. */
+} /* __PHYSFS_platformInit */
+
+
+int __PHYSFS_platformDeinit(void)
+{
+ return 1; /* always succeed. */
+} /* __PHYSFS_platformDeinit */
+
+
+static char *getMountPoint(const char *devname, char *buf, size_t bufsize)
+{
+ BVolumeRoster mounts;
+ BVolume vol;
+
+ mounts.Rewind();
+ while (mounts.GetNextVolume(&vol) == B_NO_ERROR)
+ {
+ fs_info fsinfo;
+ fs_stat_dev(vol.Device(), &fsinfo);
+ if (strcmp(devname, fsinfo.device_name) == 0)
+ {
+ BDirectory directory;
+ BEntry entry;
+ BPath path;
+ const char *str;
+
+ if ( (vol.GetRootDirectory(&directory) < B_OK) ||
+ (directory.GetEntry(&entry) < B_OK) ||
+ (entry.GetPath(&path) < B_OK) ||
+ ( (str = path.Path()) == NULL) )
+ return NULL;
+
+ strncpy(buf, str, bufsize-1);
+ buf[bufsize-1] = '\0';
+ return buf;
+ } /* if */
+ } /* while */
+
+ return NULL;
+} /* getMountPoint */
+
+
+ /*
+ * This function is lifted from Simple Directmedia Layer (SDL):
+ * http://www.libsdl.org/ ... this is zlib-licensed code, too.
+ */
+static void tryDir(const char *d, PHYSFS_StringCallback callback, void *data)
+{
+ BDirectory dir;
+ dir.SetTo(d);
+ if (dir.InitCheck() != B_NO_ERROR)
+ return;
+
+ dir.Rewind();
+ BEntry entry;
+ while (dir.GetNextEntry(&entry) >= 0)
+ {
+ BPath path;
+ const char *name;
+ entry_ref e;
+
+ if (entry.GetPath(&path) != B_NO_ERROR)
+ continue;
+
+ name = path.Path();
+
+ if (entry.GetRef(&e) != B_NO_ERROR)
+ continue;
+
+ if (entry.IsDirectory())
+ {
+ if (strcmp(e.name, "floppy") != 0)
+ tryDir(name, callback, data);
+ continue;
+ } /* if */
+
+ if (strcmp(e.name, "raw") != 0) /* ignore partitions. */
+ continue;
+
+ const int devfd = open(name, O_RDONLY);
+ if (devfd < 0)
+ continue;
+
+ device_geometry g;
+ const int rc = ioctl(devfd, B_GET_GEOMETRY, &g, sizeof (g));
+ close(devfd);
+ if (rc < 0)
+ continue;
+
+ if (g.device_type != B_CD)
+ continue;
+
+ char mntpnt[B_FILE_NAME_LENGTH];
+ if (getMountPoint(name, mntpnt, sizeof (mntpnt)))
+ callback(data, mntpnt);
+ } /* while */
+} /* tryDir */
+
+
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
+{
+ tryDir("/dev/disk", cb, data);
+} /* __PHYSFS_platformDetectAvailableCDs */
+
+
+static team_id getTeamID(void)
+{
+ thread_info info;
+ thread_id tid = find_thread(NULL);
+ get_thread_info(tid, &info);
+ return info.team;
+} /* getTeamID */
+
+
+char *__PHYSFS_platformCalcBaseDir(const char *argv0)
+{
+ image_info info;
+ int32 cookie = 0;
+
+ while (get_next_image_info(0, &cookie, &info) == B_OK)
+ {
+ if (info.type == B_APP_IMAGE)
+ break;
+ } /* while */
+
+ BEntry entry(info.name, true);
+ BPath path;
+ status_t rc = entry.GetPath(&path); /* (path) now has binary's path. */
+ assert(rc == B_OK);
+ rc = path.GetParent(&path); /* chop filename, keep directory. */
+ assert(rc == B_OK);
+ const char *str = path.Path();
+ assert(str != NULL);
+ const size_t len = strlen(str);
+ char *retval = (char *) allocator.Malloc(len + 2);
+ BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ strcpy(retval, str);
+ retval[len] = '/';
+ retval[len+1] = '\0';
+ return retval;
+} /* __PHYSFS_platformCalcBaseDir */
+
+
+char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
+{
+ const char *userdir = __PHYSFS_getUserDir();
+ const char *append = "config/settings/";
+ const size_t len = strlen(userdir) + strlen(append) + strlen(app) + 2;
+ char *retval = allocator.Malloc(len);
+ BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ snprintf(retval, len, "%s%s%s/", userdir, append, app);
+ return retval;
+} /* __PHYSFS_platformCalcPrefDir */
+
+
+void *__PHYSFS_platformGetThreadID(void)
+{
+ return (void *) find_thread(NULL);
+} /* __PHYSFS_platformGetThreadID */
+
+
+void *__PHYSFS_platformCreateMutex(void)
+{
+ return new BLocker("PhysicsFS lock", true);
+} /* __PHYSFS_platformCreateMutex */
+
+
+void __PHYSFS_platformDestroyMutex(void *mutex)
+{
+ delete ((BLocker *) mutex);
+} /* __PHYSFS_platformDestroyMutex */
+
+
+int __PHYSFS_platformGrabMutex(void *mutex)
+{
+ return ((BLocker *) mutex)->Lock() ? 1 : 0;
+} /* __PHYSFS_platformGrabMutex */
+
+
+void __PHYSFS_platformReleaseMutex(void *mutex)
+{
+ ((BLocker *) mutex)->Unlock();
+} /* __PHYSFS_platformReleaseMutex */
+
+
+int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
+{
+ return 0; /* just use malloc() and friends. */
+} /* __PHYSFS_platformSetDefaultAllocator */
+
+#endif /* PHYSFS_PLATFORM_BEOS */
+
+/* end of beos.cpp ... */
+
diff -r 404ddce27b23 -r c13ebed437cb misc/libphysfs/platform_macosx.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/platform_macosx.c Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,326 @@
+/*
+ * Mac OS X support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ * This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_platforms.h"
+
+#ifdef PHYSFS_PLATFORM_MACOSX
+
+#include
+
+#if !defined(PHYSFS_NO_CDROM_SUPPORT)
+#include /* !!! FIXME */
+#include
+#include
+#include
+#include
+#endif
+
+/* Seems to get defined in some system header... */
+#ifdef Free
+#undef Free
+#endif
+
+#include "physfs_internal.h"
+
+
+/* Wrap PHYSFS_Allocator in a CFAllocator... */
+static CFAllocatorRef cfallocator = NULL;
+
+static CFStringRef cfallocDesc(const void *info)
+{
+ return CFStringCreateWithCString(cfallocator, "PhysicsFS",
+ kCFStringEncodingASCII);
+} /* cfallocDesc */
+
+
+static void *cfallocMalloc(CFIndex allocSize, CFOptionFlags hint, void *info)
+{
+ return allocator.Malloc(allocSize);
+} /* cfallocMalloc */
+
+
+static void cfallocFree(void *ptr, void *info)
+{
+ allocator.Free(ptr);
+} /* cfallocFree */
+
+
+static void *cfallocRealloc(void *ptr, CFIndex newsize,
+ CFOptionFlags hint, void *info)
+{
+ if ((ptr == NULL) || (newsize <= 0))
+ return NULL; /* ADC docs say you should always return NULL here. */
+ return allocator.Realloc(ptr, newsize);
+} /* cfallocRealloc */
+
+
+int __PHYSFS_platformInit(void)
+{
+ /* set up a CFAllocator, so Carbon can use the physfs allocator, too. */
+ CFAllocatorContext ctx;
+ memset(&ctx, '\0', sizeof (ctx));
+ ctx.copyDescription = cfallocDesc;
+ ctx.allocate = cfallocMalloc;
+ ctx.reallocate = cfallocRealloc;
+ ctx.deallocate = cfallocFree;
+ cfallocator = CFAllocatorCreate(kCFAllocatorUseContext, &ctx);
+ BAIL_IF_MACRO(!cfallocator, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+ return 1; /* success. */
+} /* __PHYSFS_platformInit */
+
+
+int __PHYSFS_platformDeinit(void)
+{
+ CFRelease(cfallocator);
+ cfallocator = NULL;
+ return 1; /* always succeed. */
+} /* __PHYSFS_platformDeinit */
+
+
+
+/* CD-ROM detection code... */
+
+/*
+ * Code based on sample from Apple Developer Connection:
+ * http://developer.apple.com/samplecode/Sample_Code/Devices_and_Hardware/Disks/VolumeToBSDNode/VolumeToBSDNode.c.htm
+ */
+
+#if !defined(PHYSFS_NO_CDROM_SUPPORT)
+
+static int darwinIsWholeMedia(io_service_t service)
+{
+ int retval = 0;
+ CFTypeRef wholeMedia;
+
+ if (!IOObjectConformsTo(service, kIOMediaClass))
+ return 0;
+
+ wholeMedia = IORegistryEntryCreateCFProperty(service,
+ CFSTR(kIOMediaWholeKey),
+ cfallocator, 0);
+ if (wholeMedia == NULL)
+ return 0;
+
+ retval = CFBooleanGetValue(wholeMedia);
+ CFRelease(wholeMedia);
+
+ return retval;
+} /* darwinIsWholeMedia */
+
+
+static int darwinIsMountedDisc(char *bsdName, mach_port_t masterPort)
+{
+ int retval = 0;
+ CFMutableDictionaryRef matchingDict;
+ kern_return_t rc;
+ io_iterator_t iter;
+ io_service_t service;
+
+ if ((matchingDict = IOBSDNameMatching(masterPort, 0, bsdName)) == NULL)
+ return 0;
+
+ rc = IOServiceGetMatchingServices(masterPort, matchingDict, &iter);
+ if ((rc != KERN_SUCCESS) || (!iter))
+ return 0;
+
+ service = IOIteratorNext(iter);
+ IOObjectRelease(iter);
+ if (!service)
+ return 0;
+
+ rc = IORegistryEntryCreateIterator(service, kIOServicePlane,
+ kIORegistryIterateRecursively | kIORegistryIterateParents, &iter);
+
+ if (!iter)
+ return 0;
+
+ if (rc != KERN_SUCCESS)
+ {
+ IOObjectRelease(iter);
+ return 0;
+ } /* if */
+
+ IOObjectRetain(service); /* add an extra object reference... */
+
+ do
+ {
+ if (darwinIsWholeMedia(service))
+ {
+ if ( (IOObjectConformsTo(service, kIOCDMediaClass)) ||
+ (IOObjectConformsTo(service, kIODVDMediaClass)) )
+ {
+ retval = 1;
+ } /* if */
+ } /* if */
+ IOObjectRelease(service);
+ } while ((service = IOIteratorNext(iter)) && (!retval));
+
+ IOObjectRelease(iter);
+ IOObjectRelease(service);
+
+ return retval;
+} /* darwinIsMountedDisc */
+
+#endif /* !defined(PHYSFS_NO_CDROM_SUPPORT) */
+
+
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
+{
+#if !defined(PHYSFS_NO_CDROM_SUPPORT)
+ const char *devPrefix = "/dev/";
+ const int prefixLen = strlen(devPrefix);
+ mach_port_t masterPort = 0;
+ struct statfs *mntbufp;
+ int i, mounts;
+
+ if (IOMasterPort(MACH_PORT_NULL, &masterPort) != KERN_SUCCESS)
+ BAIL_MACRO(PHYSFS_ERR_OS_ERROR, ) /*return void*/;
+
+ mounts = getmntinfo(&mntbufp, MNT_WAIT); /* NOT THREAD SAFE! */
+ for (i = 0; i < mounts; i++)
+ {
+ char *dev = mntbufp[i].f_mntfromname;
+ char *mnt = mntbufp[i].f_mntonname;
+ if (strncmp(dev, devPrefix, prefixLen) != 0) /* a virtual device? */
+ continue;
+
+ dev += prefixLen;
+ if (darwinIsMountedDisc(dev, masterPort))
+ cb(data, mnt);
+ } /* for */
+#endif /* !defined(PHYSFS_NO_CDROM_SUPPORT) */
+} /* __PHYSFS_platformDetectAvailableCDs */
+
+
+static char *convertCFString(CFStringRef cfstr)
+{
+ CFIndex len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr),
+ kCFStringEncodingUTF8) + 1;
+ char *retval = (char *) allocator.Malloc(len);
+ BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+
+ if (CFStringGetCString(cfstr, retval, len, kCFStringEncodingUTF8))
+ {
+ /* shrink overallocated buffer if possible... */
+ CFIndex newlen = strlen(retval) + 1;
+ if (newlen < len)
+ {
+ void *ptr = allocator.Realloc(retval, newlen);
+ if (ptr != NULL)
+ retval = (char *) ptr;
+ } /* if */
+ } /* if */
+
+ else /* probably shouldn't fail, but just in case... */
+ {
+ allocator.Free(retval);
+ BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ } /* else */
+
+ return retval;
+} /* convertCFString */
+
+
+char *__PHYSFS_platformCalcBaseDir(const char *argv0)
+{
+ CFURLRef cfurl = NULL;
+ CFStringRef cfstr = NULL;
+ CFMutableStringRef cfmutstr = NULL;
+ char *retval = NULL;
+
+ cfurl = CFBundleCopyBundleURL(CFBundleGetMainBundle());
+ BAIL_IF_MACRO(cfurl == NULL, PHYSFS_ERR_OS_ERROR, NULL);
+ cfstr = CFURLCopyFileSystemPath(cfurl, kCFURLPOSIXPathStyle);
+ CFRelease(cfurl);
+ BAIL_IF_MACRO(!cfstr, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ cfmutstr = CFStringCreateMutableCopy(cfallocator, 0, cfstr);
+ CFRelease(cfstr);
+ BAIL_IF_MACRO(!cfmutstr, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ CFStringAppendCString(cfmutstr, "/", kCFStringEncodingUTF8);
+ retval = convertCFString(cfmutstr);
+ CFRelease(cfmutstr);
+
+ return retval; /* whew. */
+} /* __PHYSFS_platformCalcBaseDir */
+
+
+char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
+{
+ /* !!! FIXME: there's a real API to determine this */
+ const char *userdir = __PHYSFS_getUserDir();
+ const char *append = "Library/Application Support/";
+ const size_t len = strlen(userdir) + strlen(append) + strlen(app) + 2;
+ char *retval = allocator.Malloc(len);
+ BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ snprintf(retval, len, "%s%s%s/", userdir, append, app);
+ return retval;
+} /* __PHYSFS_platformCalcPrefDir */
+
+
+/* Platform allocator uses default CFAllocator at PHYSFS_init() time. */
+
+static CFAllocatorRef cfallocdef = NULL;
+
+static int macosxAllocatorInit(void)
+{
+ int retval = 0;
+ cfallocdef = CFAllocatorGetDefault();
+ retval = (cfallocdef != NULL);
+ if (retval)
+ CFRetain(cfallocdef);
+ return retval;
+} /* macosxAllocatorInit */
+
+
+static void macosxAllocatorDeinit(void)
+{
+ if (cfallocdef != NULL)
+ {
+ CFRelease(cfallocdef);
+ cfallocdef = NULL;
+ } /* if */
+} /* macosxAllocatorDeinit */
+
+
+static void *macosxAllocatorMalloc(PHYSFS_uint64 s)
+{
+ if (!__PHYSFS_ui64FitsAddressSpace(s))
+ BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ return CFAllocatorAllocate(cfallocdef, (CFIndex) s, 0);
+} /* macosxAllocatorMalloc */
+
+
+static void *macosxAllocatorRealloc(void *ptr, PHYSFS_uint64 s)
+{
+ if (!__PHYSFS_ui64FitsAddressSpace(s))
+ BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ return CFAllocatorReallocate(cfallocdef, ptr, (CFIndex) s, 0);
+} /* macosxAllocatorRealloc */
+
+
+static void macosxAllocatorFree(void *ptr)
+{
+ CFAllocatorDeallocate(cfallocdef, ptr);
+} /* macosxAllocatorFree */
+
+
+int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
+{
+ allocator.Init = macosxAllocatorInit;
+ allocator.Deinit = macosxAllocatorDeinit;
+ allocator.Malloc = macosxAllocatorMalloc;
+ allocator.Realloc = macosxAllocatorRealloc;
+ allocator.Free = macosxAllocatorFree;
+ return 1; /* return non-zero: we're supplying custom allocator. */
+} /* __PHYSFS_platformSetDefaultAllocator */
+
+#endif /* PHYSFS_PLATFORM_MACOSX */
+
+/* end of macosx.c ... */
+
diff -r 404ddce27b23 -r c13ebed437cb misc/libphysfs/platform_posix.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/platform_posix.c Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,479 @@
+/*
+ * Posix-esque support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ * This file written by Ryan C. Gordon.
+ */
+
+/* !!! FIXME: check for EINTR? */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_platforms.h"
+
+#ifdef PHYSFS_PLATFORM_POSIX
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#if ((!defined PHYSFS_NO_THREAD_SUPPORT) && (!defined PHYSFS_PLATFORM_BEOS))
+#include
+#endif
+
+#include "physfs_internal.h"
+
+
+static PHYSFS_ErrorCode errcodeFromErrnoError(const int err)
+{
+ switch (err)
+ {
+ case 0: return PHYSFS_ERR_OK;
+ case EACCES: return PHYSFS_ERR_PERMISSION;
+ case EPERM: return PHYSFS_ERR_PERMISSION;
+ case EDQUOT: return PHYSFS_ERR_NO_SPACE;
+ case EIO: return PHYSFS_ERR_IO;
+ case ELOOP: return PHYSFS_ERR_SYMLINK_LOOP;
+ case EMLINK: return PHYSFS_ERR_NO_SPACE;
+ case ENAMETOOLONG: return PHYSFS_ERR_BAD_FILENAME;
+ case ENOENT: return PHYSFS_ERR_NO_SUCH_PATH;
+ case ENOSPC: return PHYSFS_ERR_NO_SPACE;
+ case ENOTDIR: return PHYSFS_ERR_NO_SUCH_PATH;
+ case EISDIR: return PHYSFS_ERR_NOT_A_FILE;
+ case EROFS: return PHYSFS_ERR_READ_ONLY;
+ case ETXTBSY: return PHYSFS_ERR_BUSY;
+ case EBUSY: return PHYSFS_ERR_BUSY;
+ case ENOMEM: return PHYSFS_ERR_OUT_OF_MEMORY;
+ case ENOTEMPTY: return PHYSFS_ERR_DIR_NOT_EMPTY;
+ default: return PHYSFS_ERR_OS_ERROR;
+ } /* switch */
+} /* errcodeFromErrnoError */
+
+
+static inline PHYSFS_ErrorCode errcodeFromErrno(void)
+{
+ return errcodeFromErrnoError(errno);
+} /* errcodeFromErrno */
+
+
+static char *getUserDirByUID(void)
+{
+ uid_t uid = getuid();
+ struct passwd *pw;
+ char *retval = NULL;
+
+ pw = getpwuid(uid);
+ if ((pw != NULL) && (pw->pw_dir != NULL) && (*pw->pw_dir != '\0'))
+ {
+ const size_t dlen = strlen(pw->pw_dir);
+ const size_t add_dirsep = (pw->pw_dir[dlen-1] != '/') ? 1 : 0;
+ retval = (char *) allocator.Malloc(dlen + 1 + add_dirsep);
+ if (retval != NULL)
+ {
+ strcpy(retval, pw->pw_dir);
+ if (add_dirsep)
+ {
+ retval[dlen] = '/';
+ retval[dlen+1] = '\0';
+ } /* if */
+ } /* if */
+ } /* if */
+
+ return retval;
+} /* getUserDirByUID */
+
+
+char *__PHYSFS_platformCalcUserDir(void)
+{
+ char *retval = NULL;
+ char *envr = getenv("HOME");
+
+ /* if the environment variable was set, make sure it's really a dir. */
+ if (envr != NULL)
+ {
+ struct stat statbuf;
+ if ((stat(envr, &statbuf) != -1) && (S_ISDIR(statbuf.st_mode)))
+ {
+ const size_t envrlen = strlen(envr);
+ const size_t add_dirsep = (envr[envrlen-1] != '/') ? 1 : 0;
+ retval = allocator.Malloc(envrlen + 1 + add_dirsep);
+ if (retval)
+ {
+ strcpy(retval, envr);
+ if (add_dirsep)
+ {
+ retval[envrlen] = '/';
+ retval[envrlen+1] = '\0';
+ } /* if */
+ } /* if */
+ } /* if */
+ } /* if */
+
+ if (retval == NULL)
+ retval = getUserDirByUID();
+
+ return retval;
+} /* __PHYSFS_platformCalcUserDir */
+
+
+void __PHYSFS_platformEnumerateFiles(const char *dirname,
+ int omitSymLinks,
+ PHYSFS_EnumFilesCallback callback,
+ const char *origdir,
+ void *callbackdata)
+{
+ DIR *dir;
+ struct dirent *ent;
+ int bufsize = 0;
+ char *buf = NULL;
+ int dlen = 0;
+
+ if (omitSymLinks) /* !!! FIXME: this malloc sucks. */
+ {
+ dlen = strlen(dirname);
+ bufsize = dlen + 256;
+ buf = (char *) allocator.Malloc(bufsize);
+ if (buf == NULL)
+ return;
+ strcpy(buf, dirname);
+ if (buf[dlen - 1] != '/')
+ {
+ buf[dlen++] = '/';
+ buf[dlen] = '\0';
+ } /* if */
+ } /* if */
+
+ errno = 0;
+ dir = opendir(dirname);
+ if (dir == NULL)
+ {
+ allocator.Free(buf);
+ return;
+ } /* if */
+
+ while ((ent = readdir(dir)) != NULL)
+ {
+ if (strcmp(ent->d_name, ".") == 0)
+ continue;
+
+ if (strcmp(ent->d_name, "..") == 0)
+ continue;
+
+ if (omitSymLinks)
+ {
+ PHYSFS_Stat statbuf;
+ int exists = 0;
+ char *p;
+ int len = strlen(ent->d_name) + dlen + 1;
+ if (len > bufsize)
+ {
+ p = (char *) allocator.Realloc(buf, len);
+ if (p == NULL)
+ continue;
+ buf = p;
+ bufsize = len;
+ } /* if */
+
+ strcpy(buf + dlen, ent->d_name);
+
+ if (!__PHYSFS_platformStat(buf, &exists, &statbuf))
+ continue;
+ else if (!exists)
+ continue; /* probably can't happen, but just in case. */
+ else if (statbuf.filetype == PHYSFS_FILETYPE_SYMLINK)
+ continue;
+ } /* if */
+
+ callback(callbackdata, origdir, ent->d_name);
+ } /* while */
+
+ allocator.Free(buf);
+ closedir(dir);
+} /* __PHYSFS_platformEnumerateFiles */
+
+
+int __PHYSFS_platformMkDir(const char *path)
+{
+ const int rc = mkdir(path, S_IRWXU);
+ BAIL_IF_MACRO(rc == -1, errcodeFromErrno(), 0);
+ return 1;
+} /* __PHYSFS_platformMkDir */
+
+
+static void *doOpen(const char *filename, int mode)
+{
+ const int appending = (mode & O_APPEND);
+ int fd;
+ int *retval;
+ errno = 0;
+
+ /* O_APPEND doesn't actually behave as we'd like. */
+ mode &= ~O_APPEND;
+
+ fd = open(filename, mode, S_IRUSR | S_IWUSR);
+ BAIL_IF_MACRO(fd < 0, errcodeFromErrno(), NULL);
+
+ if (appending)
+ {
+ if (lseek(fd, 0, SEEK_END) < 0)
+ {
+ const int err = errno;
+ close(fd);
+ BAIL_MACRO(errcodeFromErrnoError(err), NULL);
+ } /* if */
+ } /* if */
+
+ retval = (int *) allocator.Malloc(sizeof (int));
+ if (!retval)
+ {
+ close(fd);
+ BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ } /* if */
+
+ *retval = fd;
+ return ((void *) retval);
+} /* doOpen */
+
+
+void *__PHYSFS_platformOpenRead(const char *filename)
+{
+ return doOpen(filename, O_RDONLY);
+} /* __PHYSFS_platformOpenRead */
+
+
+void *__PHYSFS_platformOpenWrite(const char *filename)
+{
+ return doOpen(filename, O_WRONLY | O_CREAT | O_TRUNC);
+} /* __PHYSFS_platformOpenWrite */
+
+
+void *__PHYSFS_platformOpenAppend(const char *filename)
+{
+ return doOpen(filename, O_WRONLY | O_CREAT | O_APPEND);
+} /* __PHYSFS_platformOpenAppend */
+
+
+PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
+ PHYSFS_uint64 len)
+{
+ const int fd = *((int *) opaque);
+ ssize_t rc = 0;
+
+ if (!__PHYSFS_ui64FitsAddressSpace(len))
+ BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1);
+
+ rc = read(fd, buffer, (size_t) len);
+ BAIL_IF_MACRO(rc == -1, errcodeFromErrno(), -1);
+ assert(rc >= 0);
+ assert(rc <= len);
+ return (PHYSFS_sint64) rc;
+} /* __PHYSFS_platformRead */
+
+
+PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
+ PHYSFS_uint64 len)
+{
+ const int fd = *((int *) opaque);
+ ssize_t rc = 0;
+
+ if (!__PHYSFS_ui64FitsAddressSpace(len))
+ BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1);
+
+ rc = write(fd, (void *) buffer, (size_t) len);
+ BAIL_IF_MACRO(rc == -1, errcodeFromErrno(), rc);
+ assert(rc >= 0);
+ assert(rc <= len);
+ return (PHYSFS_sint64) rc;
+} /* __PHYSFS_platformWrite */
+
+
+int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos)
+{
+ const int fd = *((int *) opaque);
+ const int rc = lseek(fd, (off_t) pos, SEEK_SET);
+ BAIL_IF_MACRO(rc == -1, errcodeFromErrno(), 0);
+ return 1;
+} /* __PHYSFS_platformSeek */
+
+
+PHYSFS_sint64 __PHYSFS_platformTell(void *opaque)
+{
+ const int fd = *((int *) opaque);
+ PHYSFS_sint64 retval;
+ retval = (PHYSFS_sint64) lseek(fd, 0, SEEK_CUR);
+ BAIL_IF_MACRO(retval == -1, errcodeFromErrno(), -1);
+ return retval;
+} /* __PHYSFS_platformTell */
+
+
+PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
+{
+ const int fd = *((int *) opaque);
+ struct stat statbuf;
+ BAIL_IF_MACRO(fstat(fd, &statbuf) == -1, errcodeFromErrno(), -1);
+ return ((PHYSFS_sint64) statbuf.st_size);
+} /* __PHYSFS_platformFileLength */
+
+
+int __PHYSFS_platformFlush(void *opaque)
+{
+ const int fd = *((int *) opaque);
+ BAIL_IF_MACRO(fsync(fd) == -1, errcodeFromErrno(), 0);
+ return 1;
+} /* __PHYSFS_platformFlush */
+
+
+void __PHYSFS_platformClose(void *opaque)
+{
+ const int fd = *((int *) opaque);
+ (void) close(fd); /* we don't check this. You should have used flush! */
+ allocator.Free(opaque);
+} /* __PHYSFS_platformClose */
+
+
+int __PHYSFS_platformDelete(const char *path)
+{
+ BAIL_IF_MACRO(remove(path) == -1, errcodeFromErrno(), 0);
+ return 1;
+} /* __PHYSFS_platformDelete */
+
+
+int __PHYSFS_platformStat(const char *filename, int *exists, PHYSFS_Stat *st)
+{
+ struct stat statbuf;
+
+ if (lstat(filename, &statbuf) == -1)
+ {
+ *exists = (errno != ENOENT);
+ BAIL_MACRO(errcodeFromErrno(), 0);
+ } /* if */
+
+ *exists = 1;
+
+ if (S_ISREG(statbuf.st_mode))
+ {
+ st->filetype = PHYSFS_FILETYPE_REGULAR;
+ st->filesize = statbuf.st_size;
+ } /* if */
+
+ else if(S_ISDIR(statbuf.st_mode))
+ {
+ st->filetype = PHYSFS_FILETYPE_DIRECTORY;
+ st->filesize = 0;
+ } /* else if */
+
+ else
+ {
+ st->filetype = PHYSFS_FILETYPE_OTHER;
+ st->filesize = statbuf.st_size;
+ } /* else */
+
+ st->modtime = statbuf.st_mtime;
+ st->createtime = statbuf.st_ctime;
+ st->accesstime = statbuf.st_atime;
+
+ /* !!! FIXME: maybe we should just report full permissions? */
+ st->readonly = access(filename, W_OK);
+ return 1;
+} /* __PHYSFS_platformStat */
+
+
+#ifndef PHYSFS_PLATFORM_BEOS /* BeOS has its own code in platform_beos.cpp */
+#if (defined PHYSFS_NO_THREAD_SUPPORT)
+
+void *__PHYSFS_platformGetThreadID(void) { return ((void *) 0x0001); }
+void *__PHYSFS_platformCreateMutex(void) { return ((void *) 0x0001); }
+void __PHYSFS_platformDestroyMutex(void *mutex) {}
+int __PHYSFS_platformGrabMutex(void *mutex) { return 1; }
+void __PHYSFS_platformReleaseMutex(void *mutex) {}
+
+#else
+
+typedef struct
+{
+ pthread_mutex_t mutex;
+ pthread_t owner;
+ PHYSFS_uint32 count;
+} PthreadMutex;
+
+
+void *__PHYSFS_platformGetThreadID(void)
+{
+ return ( (void *) ((size_t) pthread_self()) );
+} /* __PHYSFS_platformGetThreadID */
+
+
+void *__PHYSFS_platformCreateMutex(void)
+{
+ int rc;
+ PthreadMutex *m = (PthreadMutex *) allocator.Malloc(sizeof (PthreadMutex));
+ BAIL_IF_MACRO(!m, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ rc = pthread_mutex_init(&m->mutex, NULL);
+ if (rc != 0)
+ {
+ allocator.Free(m);
+ BAIL_MACRO(PHYSFS_ERR_OS_ERROR, NULL);
+ } /* if */
+
+ m->count = 0;
+ m->owner = (pthread_t) 0xDEADBEEF;
+ return ((void *) m);
+} /* __PHYSFS_platformCreateMutex */
+
+
+void __PHYSFS_platformDestroyMutex(void *mutex)
+{
+ PthreadMutex *m = (PthreadMutex *) mutex;
+
+ /* Destroying a locked mutex is a bug, but we'll try to be helpful. */
+ if ((m->owner == pthread_self()) && (m->count > 0))
+ pthread_mutex_unlock(&m->mutex);
+
+ pthread_mutex_destroy(&m->mutex);
+ allocator.Free(m);
+} /* __PHYSFS_platformDestroyMutex */
+
+
+int __PHYSFS_platformGrabMutex(void *mutex)
+{
+ PthreadMutex *m = (PthreadMutex *) mutex;
+ pthread_t tid = pthread_self();
+ if (m->owner != tid)
+ {
+ if (pthread_mutex_lock(&m->mutex) != 0)
+ return 0;
+ m->owner = tid;
+ } /* if */
+
+ m->count++;
+ return 1;
+} /* __PHYSFS_platformGrabMutex */
+
+
+void __PHYSFS_platformReleaseMutex(void *mutex)
+{
+ PthreadMutex *m = (PthreadMutex *) mutex;
+ assert(m->owner == pthread_self()); /* catch programming errors. */
+ assert(m->count > 0); /* catch programming errors. */
+ if (m->owner == pthread_self())
+ {
+ if (--m->count == 0)
+ {
+ m->owner = (pthread_t) 0xDEADBEEF;
+ pthread_mutex_unlock(&m->mutex);
+ } /* if */
+ } /* if */
+} /* __PHYSFS_platformReleaseMutex */
+
+#endif /* !PHYSFS_NO_THREAD_SUPPORT */
+#endif /* !PHYSFS_PLATFORM_BEOS */
+
+#endif /* PHYSFS_PLATFORM_POSIX */
+
+/* end of posix.c ... */
+
diff -r 404ddce27b23 -r c13ebed437cb misc/libphysfs/platform_unix.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/platform_unix.c Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,344 @@
+/*
+ * Unix support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ * This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_platforms.h"
+
+#ifdef PHYSFS_PLATFORM_UNIX
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#if PHYSFS_PLATFORM_LINUX && !defined(PHYSFS_HAVE_MNTENT_H)
+#define PHYSFS_HAVE_MNTENT_H 1
+#elif PHYSFS_PLATFORM_SOLARIS && !defined(PHYSFS_HAVE_SYS_MNTTAB_H)
+#define PHYSFS_HAVE_SYS_MNTTAB_H 1
+#elif PHYSFS_PLATFORM_BSD && !defined(PHYSFS_HAVE_SYS_UCRED_H)
+#define PHYSFS_HAVE_SYS_UCRED_H 1
+#endif
+
+#ifdef PHYSFS_HAVE_SYS_UCRED_H
+# ifdef PHYSFS_HAVE_MNTENT_H
+# undef PHYSFS_HAVE_MNTENT_H /* don't do both... */
+# endif
+# include
+# include
+#endif
+
+#ifdef PHYSFS_HAVE_MNTENT_H
+#include
+#endif
+
+#ifdef PHYSFS_HAVE_SYS_MNTTAB_H
+#include
+#endif
+
+#include "physfs_internal.h"
+
+int __PHYSFS_platformInit(void)
+{
+ return 1; /* always succeed. */
+} /* __PHYSFS_platformInit */
+
+
+int __PHYSFS_platformDeinit(void)
+{
+ return 1; /* always succeed. */
+} /* __PHYSFS_platformDeinit */
+
+
+/* Stub version for platforms without CD-ROM support. */
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
+{
+#if (defined PHYSFS_NO_CDROM_SUPPORT)
+ /* no-op. */
+
+#elif (defined PHYSFS_HAVE_SYS_UCRED_H)
+ int i;
+ struct statfs *mntbufp = NULL;
+ int mounts = getmntinfo(&mntbufp, MNT_WAIT);
+
+ for (i = 0; i < mounts; i++)
+ {
+ int add_it = 0;
+
+ if (strcmp(mntbufp[i].f_fstypename, "iso9660") == 0)
+ add_it = 1;
+ else if (strcmp( mntbufp[i].f_fstypename, "cd9660") == 0)
+ add_it = 1;
+
+ /* add other mount types here */
+
+ if (add_it)
+ cb(data, mntbufp[i].f_mntonname);
+ } /* for */
+
+#elif (defined PHYSFS_HAVE_MNTENT_H)
+ FILE *mounts = NULL;
+ struct mntent *ent = NULL;
+
+ mounts = setmntent("/etc/mtab", "r");
+ BAIL_IF_MACRO(mounts == NULL, PHYSFS_ERR_IO, /*return void*/);
+
+ while ( (ent = getmntent(mounts)) != NULL )
+ {
+ int add_it = 0;
+ if (strcmp(ent->mnt_type, "iso9660") == 0)
+ add_it = 1;
+ else if (strcmp(ent->mnt_type, "udf") == 0)
+ add_it = 1;
+
+ /* !!! FIXME: these might pick up floppy drives, right? */
+ else if (strcmp(ent->mnt_type, "auto") == 0)
+ add_it = 1;
+ else if (strcmp(ent->mnt_type, "supermount") == 0)
+ add_it = 1;
+
+ /* !!! FIXME: udf? automount? */
+
+ /* add other mount types here */
+
+ if (add_it)
+ cb(data, ent->mnt_dir);
+ } /* while */
+
+ endmntent(mounts);
+
+#elif (defined PHYSFS_HAVE_SYS_MNTTAB_H)
+ FILE *mounts = fopen(MNTTAB, "r");
+ struct mnttab ent;
+
+ BAIL_IF_MACRO(mounts == NULL, PHYSFS_ERR_IO, /*return void*/);
+ while (getmntent(mounts, &ent) == 0)
+ {
+ int add_it = 0;
+ if (strcmp(ent.mnt_fstype, "hsfs") == 0)
+ add_it = 1;
+
+ /* add other mount types here */
+
+ if (add_it)
+ cb(data, ent.mnt_mountp);
+ } /* while */
+
+ fclose(mounts);
+
+#else
+#error Unknown platform. Should have defined PHYSFS_NO_CDROM_SUPPORT, perhaps.
+#endif
+} /* __PHYSFS_platformDetectAvailableCDs */
+
+
+/*
+ * See where program (bin) resides in the $PATH specified by (envr).
+ * returns a copy of the first element in envr that contains it, or NULL
+ * if it doesn't exist or there were other problems. PHYSFS_SetError() is
+ * called if we have a problem.
+ *
+ * (envr) will be scribbled over, and you are expected to allocator.Free() the
+ * return value when you're done with it.
+ */
+static char *findBinaryInPath(const char *bin, char *envr)
+{
+ size_t alloc_size = 0;
+ char *exe = NULL;
+ char *start = envr;
+ char *ptr;
+
+ assert(bin != NULL);
+ assert(envr != NULL);
+
+ do
+ {
+ size_t size;
+ size_t binlen;
+
+ ptr = strchr(start, ':'); /* find next $PATH separator. */
+ if (ptr)
+ *ptr = '\0';
+
+ binlen = strlen(bin);
+ size = strlen(start) + binlen + 2;
+ if (size > alloc_size)
+ {
+ char *x = (char *) allocator.Realloc(exe, size);
+ if (!x)
+ {
+ if (exe != NULL)
+ allocator.Free(exe);
+ BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ } /* if */
+
+ alloc_size = size;
+ exe = x;
+ } /* if */
+
+ /* build full binary path... */
+ strcpy(exe, start);
+ if ((exe[0] == '\0') || (exe[strlen(exe) - 1] != '/'))
+ strcat(exe, "/");
+ strcat(exe, bin);
+
+ if (access(exe, X_OK) == 0) /* Exists as executable? We're done. */
+ {
+ exe[size - binlen] = '\0'; /* chop off filename, leave '/' */
+ return exe;
+ } /* if */
+
+ start = ptr + 1; /* start points to beginning of next element. */
+ } while (ptr != NULL);
+
+ if (exe != NULL)
+ allocator.Free(exe);
+
+ return NULL; /* doesn't exist in path. */
+} /* findBinaryInPath */
+
+
+static char *readSymLink(const char *path)
+{
+ ssize_t len = 64;
+ ssize_t rc = -1;
+ char *retval = NULL;
+
+ while (1)
+ {
+ char *ptr = (char *) allocator.Realloc(retval, (size_t) len);
+ if (ptr == NULL)
+ break; /* out of memory. */
+ retval = ptr;
+
+ rc = readlink(path, retval, len);
+ if (rc == -1)
+ break; /* not a symlink, i/o error, etc. */
+
+ else if (rc < len)
+ {
+ retval[rc] = '\0'; /* readlink doesn't null-terminate. */
+ return retval; /* we're good to go. */
+ } /* else if */
+
+ len *= 2; /* grow buffer, try again. */
+ } /* while */
+
+ if (retval != NULL)
+ allocator.Free(retval);
+ return NULL;
+} /* readSymLink */
+
+
+char *__PHYSFS_platformCalcBaseDir(const char *argv0)
+{
+ char *retval = NULL;
+ const char *envr = NULL;
+
+ /*
+ * Try to avoid using argv0 unless forced to. If there's a Linux-like
+ * /proc filesystem, you can get the full path to the current process from
+ * the /proc/self/exe symlink.
+ */
+ retval = readSymLink("/proc/self/exe");
+ if (retval == NULL)
+ {
+ /* older kernels don't have /proc/self ... try PID version... */
+ const unsigned long long pid = (unsigned long long) getpid();
+ char path[64];
+ const int rc = (int) snprintf(path,sizeof(path),"/proc/%llu/exe",pid);
+ if ( (rc > 0) && (rc < sizeof(path)) )
+ retval = readSymLink(path);
+ } /* if */
+
+ if (retval != NULL) /* chop off filename. */
+ {
+ char *ptr = strrchr(retval, '/');
+ if (ptr != NULL)
+ *(ptr+1) = '\0';
+ else /* shouldn't happen, but just in case... */
+ {
+ allocator.Free(retval);
+ retval = NULL;
+ } /* else */
+ } /* if */
+
+ /* No /proc/self/exe, but we have an argv[0] we can parse? */
+ if ((retval == NULL) && (argv0 != NULL))
+ {
+ /* fast path: default behaviour can handle this. */
+ if (strchr(argv0, '/') != NULL)
+ return NULL; /* higher level parses out real path from argv0. */
+
+ /* If there's no dirsep on argv0, then look through $PATH for it. */
+ envr = getenv("PATH");
+ if (envr != NULL)
+ {
+ char *path = (char *) __PHYSFS_smallAlloc(strlen(envr) + 1);
+ BAIL_IF_MACRO(!path, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ strcpy(path, envr);
+ retval = findBinaryInPath(argv0, path);
+ __PHYSFS_smallFree(path);
+ } /* if */
+ } /* if */
+
+ if (retval != NULL)
+ {
+ /* try to shrink buffer... */
+ char *ptr = (char *) allocator.Realloc(retval, strlen(retval) + 1);
+ if (ptr != NULL)
+ retval = ptr; /* oh well if it failed. */
+ } /* if */
+
+ return retval;
+} /* __PHYSFS_platformCalcBaseDir */
+
+
+char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
+{
+ /*
+ * We use XDG's base directory spec, even if you're not on Linux.
+ * This isn't strictly correct, but the results are relatively sane
+ * in any case.
+ *
+ * http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
+ */
+ const char *envr = getenv("XDG_DATA_HOME");
+ const char *append = "/";
+ char *retval = NULL;
+ size_t len = 0;
+
+ if (!envr)
+ {
+ /* You end up with "$HOME/.local/share/Game Name 2" */
+ envr = __PHYSFS_getUserDir();
+ BAIL_IF_MACRO(!envr, ERRPASS, NULL); /* oh well. */
+ append = ".local/share/";
+ } /* if */
+
+ len = strlen(envr) + strlen(append) + strlen(app) + 2;
+ retval = (char *) allocator.Malloc(len);
+ BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ snprintf(retval, len, "%s%s%s/", envr, append, app);
+ return retval;
+} /* __PHYSFS_platformCalcPrefDir */
+
+
+int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
+{
+ return 0; /* just use malloc() and friends. */
+} /* __PHYSFS_platformSetDefaultAllocator */
+
+#endif /* PHYSFS_PLATFORM_UNIX */
+
+/* end of unix.c ... */
+
diff -r 404ddce27b23 -r c13ebed437cb misc/libphysfs/platform_windows.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/platform_windows.c Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,936 @@
+/*
+ * Windows support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ * This file written by Ryan C. Gordon, and made sane by Gregory S. Read.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_platforms.h"
+
+#ifdef PHYSFS_PLATFORM_WINDOWS
+
+/* Forcibly disable UNICODE macro, since we manage this ourselves. */
+#ifdef UNICODE
+#undef UNICODE
+#endif
+
+#define WIN32_LEAN_AND_MEAN 1
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "physfs_internal.h"
+
+#define LOWORDER_UINT64(pos) ((PHYSFS_uint32) (pos & 0xFFFFFFFF))
+#define HIGHORDER_UINT64(pos) ((PHYSFS_uint32) ((pos >> 32) & 0xFFFFFFFF))
+
+/*
+ * Users without the platform SDK don't have this defined. The original docs
+ * for SetFilePointer() just said to compare with 0xFFFFFFFF, so this should
+ * work as desired.
+ */
+#define PHYSFS_INVALID_SET_FILE_POINTER 0xFFFFFFFF
+
+/* just in case... */
+#define PHYSFS_INVALID_FILE_ATTRIBUTES 0xFFFFFFFF
+
+/* Not defined before the Vista SDK. */
+#define PHYSFS_IO_REPARSE_TAG_SYMLINK 0xA000000C
+
+
+#define UTF8_TO_UNICODE_STACK_MACRO(w_assignto, str) { \
+ if (str == NULL) \
+ w_assignto = NULL; \
+ else { \
+ const PHYSFS_uint64 len = (PHYSFS_uint64) ((strlen(str) + 1) * 2); \
+ w_assignto = (WCHAR *) __PHYSFS_smallAlloc(len); \
+ if (w_assignto != NULL) \
+ PHYSFS_utf8ToUtf16(str, (PHYSFS_uint16 *) w_assignto, len); \
+ } \
+} \
+
+/* Note this counts WCHARs, not codepoints! */
+static PHYSFS_uint64 wStrLen(const WCHAR *wstr)
+{
+ PHYSFS_uint64 len = 0;
+ while (*(wstr++))
+ len++;
+ return len;
+} /* wStrLen */
+
+static char *unicodeToUtf8Heap(const WCHAR *w_str)
+{
+ char *retval = NULL;
+ if (w_str != NULL)
+ {
+ void *ptr = NULL;
+ const PHYSFS_uint64 len = (wStrLen(w_str) * 4) + 1;
+ retval = allocator.Malloc(len);
+ BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ PHYSFS_utf8FromUtf16((const PHYSFS_uint16 *) w_str, retval, len);
+ ptr = allocator.Realloc(retval, strlen(retval) + 1); /* shrink. */
+ if (ptr != NULL)
+ retval = (char *) ptr;
+ } /* if */
+ return retval;
+} /* unicodeToUtf8Heap */
+
+/* !!! FIXME: do we really need readonly? If not, do we need this struct? */
+typedef struct
+{
+ HANDLE handle;
+ int readonly;
+} WinApiFile;
+
+static HANDLE detectCDThreadHandle = NULL;
+static HWND detectCDHwnd = 0;
+static volatile int initialDiscDetectionComplete = 0;
+static volatile DWORD drivesWithMediaBitmap = 0;
+
+
+static PHYSFS_ErrorCode errcodeFromWinApiError(const DWORD err)
+{
+ /*
+ * win32 error codes are sort of a tricky thing; Microsoft intentionally
+ * doesn't list which ones a given API might trigger, there are several
+ * with overlapping and unclear meanings...and there's 16 thousand of
+ * them in Windows 7. It looks like the ones we care about are in the
+ * first 500, but I can't say this list is perfect; we might miss
+ * important values or misinterpret others.
+ *
+ * Don't treat this list as anything other than a work in progress.
+ */
+ switch (err)
+ {
+ case ERROR_SUCCESS: return PHYSFS_ERR_OK;
+ case ERROR_ACCESS_DENIED: return PHYSFS_ERR_PERMISSION;
+ case ERROR_NETWORK_ACCESS_DENIED: return PHYSFS_ERR_PERMISSION;
+ case ERROR_NOT_READY: return PHYSFS_ERR_IO;
+ case ERROR_CRC: return PHYSFS_ERR_IO;
+ case ERROR_SEEK: return PHYSFS_ERR_IO;
+ case ERROR_SECTOR_NOT_FOUND: return PHYSFS_ERR_IO;
+ case ERROR_NOT_DOS_DISK: return PHYSFS_ERR_IO;
+ case ERROR_WRITE_FAULT: return PHYSFS_ERR_IO;
+ case ERROR_READ_FAULT: return PHYSFS_ERR_IO;
+ case ERROR_DEV_NOT_EXIST: return PHYSFS_ERR_IO;
+ /* !!! FIXME: ?? case ELOOP: return PHYSFS_ERR_SYMLINK_LOOP; */
+ case ERROR_BUFFER_OVERFLOW: return PHYSFS_ERR_BAD_FILENAME;
+ case ERROR_INVALID_NAME: return PHYSFS_ERR_BAD_FILENAME;
+ case ERROR_BAD_PATHNAME: return PHYSFS_ERR_BAD_FILENAME;
+ case ERROR_DIRECTORY: return PHYSFS_ERR_BAD_FILENAME;
+ case ERROR_FILE_NOT_FOUND: return PHYSFS_ERR_NO_SUCH_PATH;
+ case ERROR_PATH_NOT_FOUND: return PHYSFS_ERR_NO_SUCH_PATH;
+ case ERROR_DELETE_PENDING: return PHYSFS_ERR_NO_SUCH_PATH;
+ case ERROR_INVALID_DRIVE: return PHYSFS_ERR_NO_SUCH_PATH;
+ case ERROR_HANDLE_DISK_FULL: return PHYSFS_ERR_NO_SPACE;
+ case ERROR_DISK_FULL: return PHYSFS_ERR_NO_SPACE;
+ /* !!! FIXME: ?? case ENOTDIR: return PHYSFS_ERR_NO_SUCH_PATH; */
+ /* !!! FIXME: ?? case EISDIR: return PHYSFS_ERR_NOT_A_FILE; */
+ case ERROR_WRITE_PROTECT: return PHYSFS_ERR_READ_ONLY;
+ case ERROR_LOCK_VIOLATION: return PHYSFS_ERR_BUSY;
+ case ERROR_SHARING_VIOLATION: return PHYSFS_ERR_BUSY;
+ case ERROR_CURRENT_DIRECTORY: return PHYSFS_ERR_BUSY;
+ case ERROR_DRIVE_LOCKED: return PHYSFS_ERR_BUSY;
+ case ERROR_PATH_BUSY: return PHYSFS_ERR_BUSY;
+ case ERROR_BUSY: return PHYSFS_ERR_BUSY;
+ case ERROR_NOT_ENOUGH_MEMORY: return PHYSFS_ERR_OUT_OF_MEMORY;
+ case ERROR_OUTOFMEMORY: return PHYSFS_ERR_OUT_OF_MEMORY;
+ case ERROR_DIR_NOT_EMPTY: return PHYSFS_ERR_DIR_NOT_EMPTY;
+ default: return PHYSFS_ERR_OS_ERROR;
+ } /* switch */
+} /* errcodeFromWinApiError */
+
+static inline PHYSFS_ErrorCode errcodeFromWinApi(void)
+{
+ return errcodeFromWinApiError(GetLastError());
+} /* errcodeFromWinApi */
+
+
+typedef BOOL (WINAPI *fnSTEM)(DWORD, LPDWORD b);
+
+static DWORD pollDiscDrives(void)
+{
+ /* Try to use SetThreadErrorMode(), which showed up in Windows 7. */
+ HANDLE lib = LoadLibraryA("kernel32.dll");
+ fnSTEM stem = NULL;
+ char drive[4] = { 'x', ':', '\\', '\0' };
+ DWORD oldErrorMode = 0;
+ DWORD drives = 0;
+ DWORD i;
+
+ if (lib)
+ stem = (fnSTEM) GetProcAddress(lib, "SetThreadErrorMode");
+
+ if (stem)
+ stem(SEM_FAILCRITICALERRORS, &oldErrorMode);
+ else
+ oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+
+ /* Do detection. This may block if a disc is spinning up. */
+ for (i = 'A'; i <= 'Z'; i++)
+ {
+ DWORD tmp = 0;
+ drive[0] = (char) i;
+ if (GetDriveTypeA(drive) != DRIVE_CDROM)
+ continue;
+
+ /* If this function succeeds, there's media in the drive */
+ if (GetVolumeInformationA(drive, NULL, 0, NULL, NULL, &tmp, NULL, 0))
+ drives |= (1 << (i - 'A'));
+ } /* for */
+
+ if (stem)
+ stem(oldErrorMode, NULL);
+ else
+ SetErrorMode(oldErrorMode);
+
+ if (lib)
+ FreeLibrary(lib);
+
+ return drives;
+} /* pollDiscDrives */
+
+
+static LRESULT CALLBACK detectCDWndProc(HWND hwnd, UINT msg,
+ WPARAM wp, LPARAM lparam)
+{
+ PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR) lparam;
+ PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME) lparam;
+ const int removed = (wp == DBT_DEVICEREMOVECOMPLETE);
+
+ if (msg == WM_DESTROY)
+ return 0;
+ else if ((msg != WM_DEVICECHANGE) ||
+ ((wp != DBT_DEVICEARRIVAL) && (wp != DBT_DEVICEREMOVECOMPLETE)) ||
+ (lpdb->dbch_devicetype != DBT_DEVTYP_VOLUME) ||
+ ((lpdbv->dbcv_flags & DBTF_MEDIA) == 0))
+ {
+ return DefWindowProcW(hwnd, msg, wp, lparam);
+ } /* else if */
+
+ if (removed)
+ drivesWithMediaBitmap &= ~lpdbv->dbcv_unitmask;
+ else
+ drivesWithMediaBitmap |= lpdbv->dbcv_unitmask;
+
+ return TRUE;
+} /* detectCDWndProc */
+
+
+static DWORD WINAPI detectCDThread(LPVOID lpParameter)
+{
+ const char *classname = "PhysicsFSDetectCDCatcher";
+ const char *winname = "PhysicsFSDetectCDMsgWindow";
+ HINSTANCE hInstance = GetModuleHandleW(NULL);
+ ATOM class_atom = 0;
+ WNDCLASSEXA wce;
+ MSG msg;
+
+ memset(&wce, '\0', sizeof (wce));
+ wce.cbSize = sizeof (wce);
+ wce.lpfnWndProc = detectCDWndProc;
+ wce.lpszClassName = classname;
+ wce.hInstance = hInstance;
+ class_atom = RegisterClassExA(&wce);
+ if (class_atom == 0)
+ {
+ initialDiscDetectionComplete = 1; /* let main thread go on. */
+ return 0;
+ } /* if */
+
+ detectCDHwnd = CreateWindowExA(0, classname, winname, WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, HWND_DESKTOP, NULL, hInstance, NULL);
+
+ if (detectCDHwnd == NULL)
+ {
+ initialDiscDetectionComplete = 1; /* let main thread go on. */
+ UnregisterClassA(classname, hInstance);
+ return 0;
+ } /* if */
+
+ /* We'll get events when discs come and go from now on. */
+
+ /* Do initial detection, possibly blocking awhile... */
+ drivesWithMediaBitmap = pollDiscDrives();
+ initialDiscDetectionComplete = 1; /* let main thread go on. */
+
+ do
+ {
+ const BOOL rc = GetMessageW(&msg, detectCDHwnd, 0, 0);
+ if ((rc == 0) || (rc == -1))
+ break; /* don't care if WM_QUIT or error break this loop. */
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ } while (1);
+
+ /* we've been asked to quit. */
+ DestroyWindow(detectCDHwnd);
+
+ do
+ {
+ const BOOL rc = GetMessage(&msg, detectCDHwnd, 0, 0);
+ if ((rc == 0) || (rc == -1))
+ break;
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ } while (1);
+
+ UnregisterClassA(classname, hInstance);
+
+ return 0;
+} /* detectCDThread */
+
+
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
+{
+ char drive_str[4] = { 'x', ':', '\\', '\0' };
+ DWORD drives = 0;
+ DWORD i;
+
+ /*
+ * If you poll a drive while a user is inserting a disc, the OS will
+ * block this thread until the drive has spun up. So we swallow the risk
+ * once for initial detection, and spin a thread that will get device
+ * events thereafter, for apps that use this interface to poll for
+ * disc insertion.
+ */
+ if (!detectCDThreadHandle)
+ {
+ initialDiscDetectionComplete = 0;
+ detectCDThreadHandle = CreateThread(NULL,0,detectCDThread,NULL,0,NULL);
+ if (detectCDThreadHandle == NULL)
+ return; /* oh well. */
+
+ while (!initialDiscDetectionComplete)
+ Sleep(50);
+ } /* if */
+
+ drives = drivesWithMediaBitmap; /* whatever the thread has seen, we take. */
+ for (i = 'A'; i <= 'Z'; i++)
+ {
+ if (drives & (1 << (i - 'A')))
+ {
+ drive_str[0] = (char) i;
+ cb(data, drive_str);
+ } /* if */
+ } /* for */
+} /* __PHYSFS_platformDetectAvailableCDs */
+
+
+char *__PHYSFS_platformCalcBaseDir(const char *argv0)
+{
+ DWORD buflen = 64;
+ LPWSTR modpath = NULL;
+ char *retval = NULL;
+
+ while (1)
+ {
+ DWORD rc;
+ void *ptr;
+
+ if ( (ptr = allocator.Realloc(modpath, buflen*sizeof(WCHAR))) == NULL )
+ {
+ allocator.Free(modpath);
+ BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ } /* if */
+ modpath = (LPWSTR) ptr;
+
+ rc = GetModuleFileNameW(NULL, modpath, buflen);
+ if (rc == 0)
+ {
+ allocator.Free(modpath);
+ BAIL_MACRO(errcodeFromWinApi(), NULL);
+ } /* if */
+
+ if (rc < buflen)
+ {
+ buflen = rc;
+ break;
+ } /* if */
+
+ buflen *= 2;
+ } /* while */
+
+ if (buflen > 0) /* just in case... */
+ {
+ WCHAR *ptr = (modpath + buflen) - 1;
+ while (ptr != modpath)
+ {
+ if (*ptr == '\\')
+ break;
+ ptr--;
+ } /* while */
+
+ if ((ptr == modpath) && (*ptr != '\\'))
+ __PHYSFS_setError(PHYSFS_ERR_OTHER_ERROR); /* oh well. */
+ else
+ {
+ *(ptr+1) = '\0'; /* chop off filename. */
+ retval = unicodeToUtf8Heap(modpath);
+ } /* else */
+ } /* else */
+ allocator.Free(modpath);
+
+ return retval; /* w00t. */
+} /* __PHYSFS_platformCalcBaseDir */
+
+
+char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
+{
+ /*
+ * Vista and later has a new API for this, but SHGetFolderPath works there,
+ * and apparently just wraps the new API. This is the new way to do it:
+ *
+ * SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_CREATE,
+ * NULL, &wszPath);
+ */
+
+ WCHAR path[MAX_PATH];
+ char *utf8 = NULL;
+ size_t len = 0;
+ char *retval = NULL;
+
+ if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE,
+ NULL, 0, path)))
+ BAIL_MACRO(PHYSFS_ERR_OS_ERROR, NULL);
+
+ utf8 = unicodeToUtf8Heap(path);
+ BAIL_IF_MACRO(!utf8, ERRPASS, NULL);
+ len = strlen(utf8) + strlen(org) + strlen(app) + 4;
+ retval = allocator.Malloc(len);
+ if (!retval)
+ {
+ allocator.Free(utf8);
+ BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ } /* if */
+
+ sprintf(retval, "%s\\%s\\%s\\", utf8, org, app);
+ return retval;
+} /* __PHYSFS_platformCalcPrefDir */
+
+
+char *__PHYSFS_platformCalcUserDir(void)
+{
+ typedef BOOL (WINAPI *fnGetUserProfDirW)(HANDLE, LPWSTR, LPDWORD);
+ fnGetUserProfDirW pGetDir = NULL;
+ HANDLE lib = NULL;
+ HANDLE accessToken = NULL; /* Security handle to process */
+ char *retval = NULL;
+
+ lib = LoadLibraryA("userenv.dll");
+ BAIL_IF_MACRO(!lib, errcodeFromWinApi(), NULL);
+ pGetDir=(fnGetUserProfDirW) GetProcAddress(lib,"GetUserProfileDirectoryW");
+ GOTO_IF_MACRO(!pGetDir, errcodeFromWinApi(), done);
+
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &accessToken))
+ GOTO_MACRO(errcodeFromWinApi(), done);
+ else
+ {
+ DWORD psize = 0;
+ WCHAR dummy = 0;
+ LPWSTR wstr = NULL;
+ BOOL rc = 0;
+
+ /*
+ * Should fail. Will write the size of the profile path in
+ * psize. Also note that the second parameter can't be
+ * NULL or the function fails.
+ */
+ rc = pGetDir(accessToken, &dummy, &psize);
+ assert(!rc); /* !!! FIXME: handle this gracefully. */
+ (void) rc;
+
+ /* Allocate memory for the profile directory */
+ wstr = (LPWSTR) __PHYSFS_smallAlloc((psize + 1) * sizeof (WCHAR));
+ if (wstr != NULL)
+ {
+ if (pGetDir(accessToken, wstr, &psize))
+ {
+ /* Make sure it ends in a dirsep. We allocated +1 for this. */
+ if (wstr[psize - 2] != '\\')
+ {
+ wstr[psize - 1] = '\\';
+ wstr[psize - 0] = '\0';
+ } /* if */
+ retval = unicodeToUtf8Heap(wstr);
+ } /* if */
+ __PHYSFS_smallFree(wstr);
+ } /* if */
+
+ CloseHandle(accessToken);
+ } /* if */
+
+done:
+ FreeLibrary(lib);
+ return retval; /* We made it: hit the showers. */
+} /* __PHYSFS_platformCalcUserDir */
+
+
+void *__PHYSFS_platformGetThreadID(void)
+{
+ return ( (void *) ((size_t) GetCurrentThreadId()) );
+} /* __PHYSFS_platformGetThreadID */
+
+
+static int isSymlinkAttrs(const DWORD attr, const DWORD tag)
+{
+ return ( (attr & FILE_ATTRIBUTE_REPARSE_POINT) &&
+ (tag == PHYSFS_IO_REPARSE_TAG_SYMLINK) );
+} /* isSymlinkAttrs */
+
+
+void __PHYSFS_platformEnumerateFiles(const char *dirname,
+ int omitSymLinks,
+ PHYSFS_EnumFilesCallback callback,
+ const char *origdir,
+ void *callbackdata)
+{
+ HANDLE dir = INVALID_HANDLE_VALUE;
+ WIN32_FIND_DATAW entw;
+ size_t len = strlen(dirname);
+ char *searchPath = NULL;
+ WCHAR *wSearchPath = NULL;
+
+ /* Allocate a new string for path, maybe '\\', "*", and NULL terminator */
+ searchPath = (char *) __PHYSFS_smallAlloc(len + 3);
+ if (searchPath == NULL)
+ return;
+
+ /* Copy current dirname */
+ strcpy(searchPath, dirname);
+
+ /* if there's no '\\' at the end of the path, stick one in there. */
+ if (searchPath[len - 1] != '\\')
+ {
+ searchPath[len++] = '\\';
+ searchPath[len] = '\0';
+ } /* if */
+
+ /* Append the "*" to the end of the string */
+ strcat(searchPath, "*");
+
+ UTF8_TO_UNICODE_STACK_MACRO(wSearchPath, searchPath);
+ if (!wSearchPath)
+ return; /* oh well. */
+
+ dir = FindFirstFileW(wSearchPath, &entw);
+
+ __PHYSFS_smallFree(wSearchPath);
+ __PHYSFS_smallFree(searchPath);
+ if (dir == INVALID_HANDLE_VALUE)
+ return;
+
+ do
+ {
+ const DWORD attr = entw.dwFileAttributes;
+ const DWORD tag = entw.dwReserved0;
+ const WCHAR *fn = entw.cFileName;
+ char *utf8;
+
+ if ((fn[0] == '.') && (fn[1] == '\0'))
+ continue;
+ if ((fn[0] == '.') && (fn[1] == '.') && (fn[2] == '\0'))
+ continue;
+ if ((omitSymLinks) && (isSymlinkAttrs(attr, tag)))
+ continue;
+
+ utf8 = unicodeToUtf8Heap(fn);
+ if (utf8 != NULL)
+ {
+ callback(callbackdata, origdir, utf8);
+ allocator.Free(utf8);
+ } /* if */
+ } while (FindNextFileW(dir, &entw) != 0);
+
+ FindClose(dir);
+} /* __PHYSFS_platformEnumerateFiles */
+
+
+int __PHYSFS_platformMkDir(const char *path)
+{
+ WCHAR *wpath;
+ DWORD rc;
+ UTF8_TO_UNICODE_STACK_MACRO(wpath, path);
+ rc = CreateDirectoryW(wpath, NULL);
+ __PHYSFS_smallFree(wpath);
+ BAIL_IF_MACRO(rc == 0, errcodeFromWinApi(), 0);
+ return 1;
+} /* __PHYSFS_platformMkDir */
+
+
+int __PHYSFS_platformInit(void)
+{
+ return 1; /* It's all good */
+} /* __PHYSFS_platformInit */
+
+
+int __PHYSFS_platformDeinit(void)
+{
+ if (detectCDThreadHandle)
+ {
+ if (detectCDHwnd)
+ PostMessageW(detectCDHwnd, WM_QUIT, 0, 0);
+ CloseHandle(detectCDThreadHandle);
+ detectCDThreadHandle = NULL;
+ initialDiscDetectionComplete = 0;
+ drivesWithMediaBitmap = 0;
+ } /* if */
+
+ return 1; /* It's all good */
+} /* __PHYSFS_platformDeinit */
+
+
+static void *doOpen(const char *fname, DWORD mode, DWORD creation, int rdonly)
+{
+ HANDLE fileh;
+ WinApiFile *retval;
+ WCHAR *wfname;
+
+ UTF8_TO_UNICODE_STACK_MACRO(wfname, fname);
+ BAIL_IF_MACRO(!wfname, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ fileh = CreateFileW(wfname, mode, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, creation, FILE_ATTRIBUTE_NORMAL, NULL);
+ __PHYSFS_smallFree(wfname);
+
+ BAIL_IF_MACRO(fileh == INVALID_HANDLE_VALUE,errcodeFromWinApi(), NULL);
+
+ retval = (WinApiFile *) allocator.Malloc(sizeof (WinApiFile));
+ if (!retval)
+ {
+ CloseHandle(fileh);
+ BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ } /* if */
+
+ retval->readonly = rdonly;
+ retval->handle = fileh;
+ return retval;
+} /* doOpen */
+
+
+void *__PHYSFS_platformOpenRead(const char *filename)
+{
+ return doOpen(filename, GENERIC_READ, OPEN_EXISTING, 1);
+} /* __PHYSFS_platformOpenRead */
+
+
+void *__PHYSFS_platformOpenWrite(const char *filename)
+{
+ return doOpen(filename, GENERIC_WRITE, CREATE_ALWAYS, 0);
+} /* __PHYSFS_platformOpenWrite */
+
+
+void *__PHYSFS_platformOpenAppend(const char *filename)
+{
+ void *retval = doOpen(filename, GENERIC_WRITE, OPEN_ALWAYS, 0);
+ if (retval != NULL)
+ {
+ HANDLE h = ((WinApiFile *) retval)->handle;
+ DWORD rc = SetFilePointer(h, 0, NULL, FILE_END);
+ if (rc == PHYSFS_INVALID_SET_FILE_POINTER)
+ {
+ const PHYSFS_ErrorCode err = errcodeFromWinApi();
+ CloseHandle(h);
+ allocator.Free(retval);
+ BAIL_MACRO(err, NULL);
+ } /* if */
+ } /* if */
+
+ return retval;
+} /* __PHYSFS_platformOpenAppend */
+
+
+PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buf, PHYSFS_uint64 len)
+{
+ HANDLE Handle = ((WinApiFile *) opaque)->handle;
+ PHYSFS_sint64 totalRead = 0;
+
+ if (!__PHYSFS_ui64FitsAddressSpace(len))
+ BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1);
+
+ while (len > 0)
+ {
+ const DWORD thislen = (len > 0xFFFFFFFF) ? 0xFFFFFFFF : (DWORD) len;
+ DWORD numRead = 0;
+ if (!ReadFile(Handle, buf, thislen, &numRead, NULL))
+ BAIL_MACRO(errcodeFromWinApi(), -1);
+ len -= (PHYSFS_uint64) numRead;
+ totalRead += (PHYSFS_sint64) numRead;
+ if (numRead != thislen)
+ break;
+ } /* while */
+
+ return totalRead;
+} /* __PHYSFS_platformRead */
+
+
+PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
+ PHYSFS_uint64 len)
+{
+ HANDLE Handle = ((WinApiFile *) opaque)->handle;
+ PHYSFS_sint64 totalWritten = 0;
+
+ if (!__PHYSFS_ui64FitsAddressSpace(len))
+ BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1);
+
+ while (len > 0)
+ {
+ const DWORD thislen = (len > 0xFFFFFFFF) ? 0xFFFFFFFF : (DWORD) len;
+ DWORD numWritten = 0;
+ if (!WriteFile(Handle, buffer, thislen, &numWritten, NULL))
+ BAIL_MACRO(errcodeFromWinApi(), -1);
+ len -= (PHYSFS_uint64) numWritten;
+ totalWritten += (PHYSFS_sint64) numWritten;
+ if (numWritten != thislen)
+ break;
+ } /* while */
+
+ return totalWritten;
+} /* __PHYSFS_platformWrite */
+
+
+int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos)
+{
+ HANDLE Handle = ((WinApiFile *) opaque)->handle;
+ LONG HighOrderPos;
+ PLONG pHighOrderPos;
+ DWORD rc;
+
+ /* Get the high order 32-bits of the position */
+ HighOrderPos = HIGHORDER_UINT64(pos);
+
+ /*
+ * MSDN: "If you do not need the high-order 32 bits, this
+ * pointer must be set to NULL."
+ */
+ pHighOrderPos = (HighOrderPos) ? &HighOrderPos : NULL;
+
+ /* Move pointer "pos" count from start of file */
+ rc = SetFilePointer(Handle, LOWORDER_UINT64(pos),
+ pHighOrderPos, FILE_BEGIN);
+
+ if ( (rc == PHYSFS_INVALID_SET_FILE_POINTER) &&
+ (GetLastError() != NO_ERROR) )
+ {
+ BAIL_MACRO(errcodeFromWinApi(), 0);
+ } /* if */
+
+ return 1; /* No error occured */
+} /* __PHYSFS_platformSeek */
+
+
+PHYSFS_sint64 __PHYSFS_platformTell(void *opaque)
+{
+ HANDLE Handle = ((WinApiFile *) opaque)->handle;
+ LONG HighPos = 0;
+ DWORD LowPos;
+ PHYSFS_sint64 retval;
+
+ /* Get current position */
+ LowPos = SetFilePointer(Handle, 0, &HighPos, FILE_CURRENT);
+ if ( (LowPos == PHYSFS_INVALID_SET_FILE_POINTER) &&
+ (GetLastError() != NO_ERROR) )
+ {
+ BAIL_MACRO(errcodeFromWinApi(), -1);
+ } /* if */
+ else
+ {
+ /* Combine the high/low order to create the 64-bit position value */
+ retval = (((PHYSFS_uint64) HighPos) << 32) | LowPos;
+ assert(retval >= 0);
+ } /* else */
+
+ return retval;
+} /* __PHYSFS_platformTell */
+
+
+PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
+{
+ HANDLE Handle = ((WinApiFile *) opaque)->handle;
+ DWORD SizeHigh;
+ DWORD SizeLow;
+ PHYSFS_sint64 retval;
+
+ SizeLow = GetFileSize(Handle, &SizeHigh);
+ if ( (SizeLow == PHYSFS_INVALID_SET_FILE_POINTER) &&
+ (GetLastError() != NO_ERROR) )
+ {
+ BAIL_MACRO(errcodeFromWinApi(), -1);
+ } /* if */
+ else
+ {
+ /* Combine the high/low order to create the 64-bit position value */
+ retval = (((PHYSFS_uint64) SizeHigh) << 32) | SizeLow;
+ assert(retval >= 0);
+ } /* else */
+
+ return retval;
+} /* __PHYSFS_platformFileLength */
+
+
+int __PHYSFS_platformFlush(void *opaque)
+{
+ WinApiFile *fh = ((WinApiFile *) opaque);
+ if (!fh->readonly)
+ BAIL_IF_MACRO(!FlushFileBuffers(fh->handle), errcodeFromWinApi(), 0);
+
+ return 1;
+} /* __PHYSFS_platformFlush */
+
+
+void __PHYSFS_platformClose(void *opaque)
+{
+ HANDLE Handle = ((WinApiFile *) opaque)->handle;
+ (void) CloseHandle(Handle); /* ignore errors. You should have flushed! */
+ allocator.Free(opaque);
+} /* __PHYSFS_platformClose */
+
+
+static int doPlatformDelete(LPWSTR wpath)
+{
+ const int isdir = (GetFileAttributesW(wpath) & FILE_ATTRIBUTE_DIRECTORY);
+ const BOOL rc = (isdir) ? RemoveDirectoryW(wpath) : DeleteFileW(wpath);
+ BAIL_IF_MACRO(!rc, errcodeFromWinApi(), 0);
+ return 1; /* if you made it here, it worked. */
+} /* doPlatformDelete */
+
+
+int __PHYSFS_platformDelete(const char *path)
+{
+ int retval = 0;
+ LPWSTR wpath = NULL;
+ UTF8_TO_UNICODE_STACK_MACRO(wpath, path);
+ BAIL_IF_MACRO(!wpath, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+ retval = doPlatformDelete(wpath);
+ __PHYSFS_smallFree(wpath);
+ return retval;
+} /* __PHYSFS_platformDelete */
+
+
+void *__PHYSFS_platformCreateMutex(void)
+{
+ LPCRITICAL_SECTION lpcs;
+ lpcs = (LPCRITICAL_SECTION) allocator.Malloc(sizeof (CRITICAL_SECTION));
+ BAIL_IF_MACRO(!lpcs, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+ InitializeCriticalSection(lpcs);
+ return lpcs;
+} /* __PHYSFS_platformCreateMutex */
+
+
+void __PHYSFS_platformDestroyMutex(void *mutex)
+{
+ DeleteCriticalSection((LPCRITICAL_SECTION) mutex);
+ allocator.Free(mutex);
+} /* __PHYSFS_platformDestroyMutex */
+
+
+int __PHYSFS_platformGrabMutex(void *mutex)
+{
+ EnterCriticalSection((LPCRITICAL_SECTION) mutex);
+ return 1;
+} /* __PHYSFS_platformGrabMutex */
+
+
+void __PHYSFS_platformReleaseMutex(void *mutex)
+{
+ LeaveCriticalSection((LPCRITICAL_SECTION) mutex);
+} /* __PHYSFS_platformReleaseMutex */
+
+
+static PHYSFS_sint64 FileTimeToPhysfsTime(const FILETIME *ft)
+{
+ SYSTEMTIME st_utc;
+ SYSTEMTIME st_localtz;
+ TIME_ZONE_INFORMATION tzi;
+ DWORD tzid;
+ PHYSFS_sint64 retval;
+ struct tm tm;
+ BOOL rc;
+
+ BAIL_IF_MACRO(!FileTimeToSystemTime(ft, &st_utc), errcodeFromWinApi(), -1);
+ tzid = GetTimeZoneInformation(&tzi);
+ BAIL_IF_MACRO(tzid == TIME_ZONE_ID_INVALID, errcodeFromWinApi(), -1);
+ rc = SystemTimeToTzSpecificLocalTime(&tzi, &st_utc, &st_localtz);
+ BAIL_IF_MACRO(!rc, errcodeFromWinApi(), -1);
+
+ /* Convert to a format that mktime() can grok... */
+ tm.tm_sec = st_localtz.wSecond;
+ tm.tm_min = st_localtz.wMinute;
+ tm.tm_hour = st_localtz.wHour;
+ tm.tm_mday = st_localtz.wDay;
+ tm.tm_mon = st_localtz.wMonth - 1;
+ tm.tm_year = st_localtz.wYear - 1900;
+ tm.tm_wday = -1 /*st_localtz.wDayOfWeek*/;
+ tm.tm_yday = -1;
+ tm.tm_isdst = -1;
+
+ /* Convert to a format PhysicsFS can grok... */
+ retval = (PHYSFS_sint64) mktime(&tm);
+ BAIL_IF_MACRO(retval == -1, PHYSFS_ERR_OS_ERROR, -1);
+ return retval;
+} /* FileTimeToPhysfsTime */
+
+int __PHYSFS_platformStat(const char *filename, int *exists, PHYSFS_Stat *stat)
+{
+ WIN32_FILE_ATTRIBUTE_DATA winstat;
+ WCHAR *wstr = NULL;
+ DWORD err = 0;
+ BOOL rc = 0;
+
+ UTF8_TO_UNICODE_STACK_MACRO(wstr, filename);
+ BAIL_IF_MACRO(!wstr, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+ rc = GetFileAttributesExW(wstr, GetFileExInfoStandard, &winstat);
+ err = (!rc) ? GetLastError() : 0;
+ *exists = ((err != ERROR_FILE_NOT_FOUND) && (err != ERROR_PATH_NOT_FOUND));
+ __PHYSFS_smallFree(wstr);
+ BAIL_IF_MACRO(!rc, errcodeFromWinApiError(err), 0);
+
+ stat->modtime = FileTimeToPhysfsTime(&winstat.ftLastWriteTime);
+ stat->accesstime = FileTimeToPhysfsTime(&winstat.ftLastAccessTime);
+ stat->createtime = FileTimeToPhysfsTime(&winstat.ftCreationTime);
+
+ if(winstat.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
+ stat->filesize = 0;
+ } /* if */
+
+ else if(winstat.dwFileAttributes & (FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_DEVICE))
+ {
+ /* !!! FIXME: what are reparse points? */
+ stat->filetype = PHYSFS_FILETYPE_OTHER;
+ /* !!! FIXME: don't rely on this */
+ stat->filesize = 0;
+ } /* else if */
+
+ /* !!! FIXME: check for symlinks on Vista. */
+
+ else
+ {
+ stat->filetype = PHYSFS_FILETYPE_REGULAR;
+ stat->filesize = (((PHYSFS_uint64) winstat.nFileSizeHigh) << 32) | winstat.nFileSizeLow;
+ } /* else */
+
+ stat->readonly = ((winstat.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0);
+
+ return 1;
+} /* __PHYSFS_platformStat */
+
+
+/* !!! FIXME: Don't use C runtime for allocators? */
+int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
+{
+ return 0; /* just use malloc() and friends. */
+} /* __PHYSFS_platformSetDefaultAllocator */
+
+#endif /* PHYSFS_PLATFORM_WINDOWS */
+
+/* end of windows.c ... */
+
+
diff -r 404ddce27b23 -r c13ebed437cb misc/libphyslayer/Android.mk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphyslayer/Android.mk Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,17 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := physlayer
+
+LOCAL_CFLAGS := -O2
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH) $(MISC_DIR)/liblua $(MISC_DIR)/liblua $(JNI_DIR)/SDL/include
+
+LOCAL_SRC_FILES := hwpacksmounter.c \
+ physfslualoader.c \
+ physfsrwops.c \
+
+LOCAL_SHARED_LIBRARIES += SDL lua
+
+include $(BUILD_SHARED_LIBRARY)
diff -r 404ddce27b23 -r c13ebed437cb misc/libphyslayer/CMakeLists.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphyslayer/CMakeLists.txt Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,36 @@
+
+find_package(SDL REQUIRED)
+include_directories(${PHYSFS_INCLUDE_DIR})
+include_directories(${SDL_INCLUDE_DIR})
+include_directories(${LUA_INCLUDE_DIR})
+
+## extra functions needed by Hedgewars
+## TODO: maybe it's better to have them in a separate library?
+set(PHYSLAYER_SRCS
+ physfsrwops.c
+ physfslualoader.c
+ hwpacksmounter.c
+)
+
+set(build_type STATIC)
+set(lib_prefix ${CMAKE_STATIC_LIBRARY_PREFIX})
+set(lib_suffix ${CMAKE_STATIC_LIBRARY_SUFFIX})
+
+if(WIN32)
+ set(build_type SHARED)
+ set(lib_prefix ${CMAKE_SHARED_LIBRARY_PREFIX})
+ set(lib_suffix ${CMAKE_SHARED_LIBRARY_SUFFIX})
+endif(WIN32)
+
+#compiles and links actual library
+add_library (physlayer ${build_type} ${PHYSLAYER_SRCS})
+
+if(WIN32)
+ target_link_libraries(physlayer ${SDL_LIBRARY} ${LUA_LIBRARY} ${PHYSFS_LIBRARY})
+ install(TARGETS physlayer RUNTIME DESTINATION ${target_library_install_dir})
+endif()
+
+## added standard variables (FORCE or cmake won't pick 'em)
+set(PHYSLAYER_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/misc/libphyslayer/ CACHE STRING "" FORCE)
+set(PHYSLAYER_LIBRARY ${LIBRARY_OUTPUT_PATH}/${lib_prefix}physlayer${lib_suffix} CACHE STRING "" FORCE)
+
diff -r 404ddce27b23 -r c13ebed437cb misc/libphyslayer/Xcode/Physlayer.xcodeproj/project.pbxproj
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphyslayer/Xcode/Physlayer.xcodeproj/project.pbxproj Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,256 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 45;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 617D793D16D933880091D4D6 /* hwpacksmounter.c in Sources */ = {isa = PBXBuildFile; fileRef = 617D793816D933880091D4D6 /* hwpacksmounter.c */; };
+ 617D793E16D933880091D4D6 /* hwpacksmounter.h in Headers */ = {isa = PBXBuildFile; fileRef = 617D793916D933880091D4D6 /* hwpacksmounter.h */; };
+ 617D793F16D933880091D4D6 /* physfslualoader.c in Sources */ = {isa = PBXBuildFile; fileRef = 617D793A16D933880091D4D6 /* physfslualoader.c */; };
+ 617D794016D933880091D4D6 /* physfsrwops.c in Sources */ = {isa = PBXBuildFile; fileRef = 617D793B16D933880091D4D6 /* physfsrwops.c */; };
+ 617D794116D933880091D4D6 /* physfsrwops.h in Headers */ = {isa = PBXBuildFile; fileRef = 617D793C16D933880091D4D6 /* physfsrwops.h */; };
+ AA747D9F0F9514B9006C5449 /* Physlayer_Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = AA747D9E0F9514B9006C5449 /* Physlayer_Prefix.pch */; };
+ AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AACBBE490F95108600F1A2B1 /* Foundation.framework */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 617D793816D933880091D4D6 /* hwpacksmounter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = hwpacksmounter.c; path = ../hwpacksmounter.c; sourceTree = SOURCE_ROOT; };
+ 617D793916D933880091D4D6 /* hwpacksmounter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hwpacksmounter.h; path = ../hwpacksmounter.h; sourceTree = SOURCE_ROOT; };
+ 617D793A16D933880091D4D6 /* physfslualoader.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = physfslualoader.c; path = ../physfslualoader.c; sourceTree = SOURCE_ROOT; };
+ 617D793B16D933880091D4D6 /* physfsrwops.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = physfsrwops.c; path = ../physfsrwops.c; sourceTree = SOURCE_ROOT; };
+ 617D793C16D933880091D4D6 /* physfsrwops.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = physfsrwops.h; path = ../physfsrwops.h; sourceTree = SOURCE_ROOT; };
+ AA747D9E0F9514B9006C5449 /* Physlayer_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Physlayer_Prefix.pch; sourceTree = SOURCE_ROOT; };
+ AACBBE490F95108600F1A2B1 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+ D2AAC07E0554694100DB518D /* libPhyslayer.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPhyslayer.a; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ D2AAC07C0554694100DB518D /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 034768DFFF38A50411DB9C8B /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ D2AAC07E0554694100DB518D /* libPhyslayer.a */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 0867D691FE84028FC02AAC07 /* Physlayer */ = {
+ isa = PBXGroup;
+ children = (
+ 08FB77AEFE84172EC02AAC07 /* Sources */,
+ 32C88DFF0371C24200C91783 /* Other Sources */,
+ 0867D69AFE84028FC02AAC07 /* Frameworks */,
+ 034768DFFF38A50411DB9C8B /* Products */,
+ );
+ name = Physlayer;
+ sourceTree = "";
+ };
+ 0867D69AFE84028FC02AAC07 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ AACBBE490F95108600F1A2B1 /* Foundation.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "";
+ };
+ 08FB77AEFE84172EC02AAC07 /* Sources */ = {
+ isa = PBXGroup;
+ children = (
+ 617D793816D933880091D4D6 /* hwpacksmounter.c */,
+ 617D793916D933880091D4D6 /* hwpacksmounter.h */,
+ 617D793A16D933880091D4D6 /* physfslualoader.c */,
+ 617D793B16D933880091D4D6 /* physfsrwops.c */,
+ 617D793C16D933880091D4D6 /* physfsrwops.h */,
+ );
+ name = Sources;
+ sourceTree = "";
+ };
+ 32C88DFF0371C24200C91783 /* Other Sources */ = {
+ isa = PBXGroup;
+ children = (
+ AA747D9E0F9514B9006C5449 /* Physlayer_Prefix.pch */,
+ );
+ name = "Other Sources";
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ D2AAC07A0554694100DB518D /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ AA747D9F0F9514B9006C5449 /* Physlayer_Prefix.pch in Headers */,
+ 617D793E16D933880091D4D6 /* hwpacksmounter.h in Headers */,
+ 617D794116D933880091D4D6 /* physfsrwops.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ D2AAC07D0554694100DB518D /* Physlayer */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "Physlayer" */;
+ buildPhases = (
+ D2AAC07A0554694100DB518D /* Headers */,
+ D2AAC07B0554694100DB518D /* Sources */,
+ D2AAC07C0554694100DB518D /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Physlayer;
+ productName = Physlayer;
+ productReference = D2AAC07E0554694100DB518D /* libPhyslayer.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 0867D690FE84028FC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "Physlayer" */;
+ compatibilityVersion = "Xcode 3.1";
+ developmentRegion = English;
+ hasScannedForEncodings = 1;
+ knownRegions = (
+ English,
+ Japanese,
+ French,
+ German,
+ );
+ mainGroup = 0867D691FE84028FC02AAC07 /* Physlayer */;
+ productRefGroup = 034768DFFF38A50411DB9C8B /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ D2AAC07D0554694100DB518D /* Physlayer */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+ D2AAC07B0554694100DB518D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 617D793D16D933880091D4D6 /* hwpacksmounter.c in Sources */,
+ 617D793F16D933880091D4D6 /* physfslualoader.c in Sources */,
+ 617D794016D933880091D4D6 /* physfsrwops.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 1DEB921F08733DC00010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ COPY_PHASE_STRIP = NO;
+ DSTROOT = /tmp/Physlayer.dst;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = Physlayer_Prefix.pch;
+ INSTALL_PATH = /usr/local/lib;
+ PRODUCT_NAME = Physlayer;
+ };
+ name = Debug;
+ };
+ 1DEB922008733DC00010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ DSTROOT = /tmp/Physlayer.dst;
+ GCC_MODEL_TUNING = G5;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = Physlayer_Prefix.pch;
+ INSTALL_PATH = /usr/local/lib;
+ PRODUCT_NAME = Physlayer;
+ };
+ name = Release;
+ };
+ 1DEB922308733DC00010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ GCC_C_LANGUAGE_STANDARD = c99;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ "\"$(SRCROOT)/../../libphysfs\"",
+ "\"$(SRCROOT)/../../liblua\"",
+ "\"$(SRCROOT)/../../../../Library/SDL/include\"",
+ );
+ OTHER_LDFLAGS = "-ObjC";
+ PREBINDING = NO;
+ SDKROOT = iphoneos;
+ };
+ name = Debug;
+ };
+ 1DEB922408733DC00010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ GCC_C_LANGUAGE_STANDARD = c99;
+ GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ "\"$(SRCROOT)/../../libphysfs\"",
+ "\"$(SRCROOT)/../../liblua\"",
+ "\"$(SRCROOT)/../../../../Library/SDL/include\"",
+ );
+ OTHER_LDFLAGS = "-ObjC";
+ PREBINDING = NO;
+ SDKROOT = iphoneos;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "Physlayer" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB921F08733DC00010E9CD /* Debug */,
+ 1DEB922008733DC00010E9CD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "Physlayer" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB922308733DC00010E9CD /* Debug */,
+ 1DEB922408733DC00010E9CD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 0867D690FE84028FC02AAC07 /* Project object */;
+}
diff -r 404ddce27b23 -r c13ebed437cb misc/libphyslayer/Xcode/Physlayer_Prefix.pch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphyslayer/Xcode/Physlayer_Prefix.pch Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,7 @@
+//
+// Prefix header for all source files of the 'CocoaTouchStaticLibrary' target in the 'CocoaTouchStaticLibrary' project.
+//
+
+#ifdef __OBJC__
+ #import
+#endif
diff -r 404ddce27b23 -r c13ebed437cb misc/libphyslayer/hwpacksmounter.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphyslayer/hwpacksmounter.c Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,35 @@
+#include
+#include
+#include
+
+#include "hwpacksmounter.h"
+
+PHYSFS_DECL void hedgewarsMountPackages()
+{
+ char ** filesList = PHYSFS_enumerateFiles("/");
+ char **i;
+
+ for (i = filesList; *i != NULL; i++)
+ {
+ char * fileName = *i;
+ int fileNameLength = strlen(fileName);
+ if (fileNameLength > 4)
+ if (strcmp(fileName + fileNameLength - 4, ".hwp") == 0)
+ {
+ const char * dir = PHYSFS_getRealDir(fileName);
+ if(dir)
+ {
+ char * fullPath = (char *)malloc(strlen(dir) + fileNameLength + 2);
+ strcpy(fullPath, dir);
+ strcat(fullPath, "/");
+ strcat(fullPath, fileName);
+
+ PHYSFS_mount(fullPath, NULL, 0);
+
+ free(fullPath);
+ }
+ }
+ }
+
+ PHYSFS_freeList(filesList);
+}
diff -r 404ddce27b23 -r c13ebed437cb misc/libphyslayer/hwpacksmounter.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphyslayer/hwpacksmounter.h Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,17 @@
+#ifndef HEDGEWARS_PACKAGES_MOUNTER_H
+#define HEDGEWARS_PACKAGES_MOUNTER_H
+
+#include "physfs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+PHYSFS_DECL void hedgewarsMountPackages();
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff -r 404ddce27b23 -r c13ebed437cb misc/libphyslayer/physfslualoader.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphyslayer/physfslualoader.c Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,30 @@
+#include "lua.h"
+#include "physfs.h"
+
+#define BUFSIZE 1024
+
+void *physfsReaderBuffer;
+
+PHYSFS_DECL const char * physfsReader(lua_State *L, PHYSFS_File *f, size_t *size)
+{
+
+ if(PHYSFS_eof(f))
+ {
+ return NULL;
+ }
+ else
+ {
+ *size = PHYSFS_readBytes(f, physfsReaderBuffer, BUFSIZE);
+
+ if(*size == 0)
+ return NULL;
+ else
+ return physfsReaderBuffer;
+ }
+}
+
+PHYSFS_DECL void physfsReaderSetBuffer(void *buffer)
+{
+ physfsReaderBuffer = buffer;
+}
+
diff -r 404ddce27b23 -r c13ebed437cb misc/libphyslayer/physfsrwops.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphyslayer/physfsrwops.c Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,219 @@
+/*
+ * This code provides a glue layer between PhysicsFS and Simple Directmedia
+ * Layer's (SDL) RWops i/o abstraction.
+ *
+ * License: this code is public domain. I make no warranty that it is useful,
+ * correct, harmless, or environmentally safe.
+ *
+ * This particular file may be used however you like, including copying it
+ * verbatim into a closed-source project, exploiting it commercially, and
+ * removing any trace of my name from the source (although I hope you won't
+ * do that). I welcome enhancements and corrections to this file, but I do
+ * not require you to send me patches if you make changes. This code has
+ * NO WARRANTY.
+ *
+ * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
+ * Please see LICENSE.txt in the root of the source tree.
+ *
+ * SDL 1.2 falls under the LGPL license. SDL 1.3+ is zlib, like PhysicsFS.
+ * You can get SDL at http://www.libsdl.org/
+ *
+ * This file was written by Ryan C. Gordon. (icculus@icculus.org).
+ */
+
+#include /* used for SEEK_SET, SEEK_CUR, SEEK_END ... */
+#include "physfsrwops.h"
+
+/* SDL's RWOPS interface changed a little in SDL 1.3... */
+#if defined(SDL_VERSION_ATLEAST)
+#if SDL_VERSION_ATLEAST(1, 3, 0)
+#define TARGET_SDL13 1
+#endif
+#endif
+
+#if TARGET_SDL13
+static long SDLCALL physfsrwops_seek(struct SDL_RWops *rw, long offset, int whence)
+#else
+static int physfsrwops_seek(SDL_RWops *rw, int offset, int whence)
+#endif
+{
+ PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
+ PHYSFS_sint64 pos = 0;
+
+ if (whence == SEEK_SET)
+ pos = (PHYSFS_sint64) offset;
+
+ else if (whence == SEEK_CUR)
+ {
+ const PHYSFS_sint64 current = PHYSFS_tell(handle);
+ if (current == -1)
+ {
+ SDL_SetError("Can't find position in file: %s",
+ PHYSFS_getLastError());
+ return -1;
+ } /* if */
+
+ if (offset == 0) /* this is a "tell" call. We're done. */
+ {
+ #if TARGET_SDL13
+ return (long) current;
+ #else
+ return (int) current;
+ #endif
+ } /* if */
+
+ pos = current + ((PHYSFS_sint64) offset);
+ } /* else if */
+
+ else if (whence == SEEK_END)
+ {
+ const PHYSFS_sint64 len = PHYSFS_fileLength(handle);
+ if (len == -1)
+ {
+ SDL_SetError("Can't find end of file: %s", PHYSFS_getLastError());
+ return -1;
+ } /* if */
+
+ pos = len + ((PHYSFS_sint64) offset);
+ } /* else if */
+
+ else
+ {
+ SDL_SetError("Invalid 'whence' parameter.");
+ return -1;
+ } /* else */
+
+ if ( pos < 0 )
+ {
+ SDL_SetError("Attempt to seek past start of file.");
+ return -1;
+ } /* if */
+
+ if (!PHYSFS_seek(handle, (PHYSFS_uint64) pos))
+ {
+ SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+ return -1;
+ } /* if */
+
+ #if TARGET_SDL13
+ return (long) pos;
+ #else
+ return (int) pos;
+ #endif
+} /* physfsrwops_seek */
+
+
+#if TARGET_SDL13
+static size_t SDLCALL physfsrwops_read(struct SDL_RWops *rw, void *ptr,
+ size_t size, size_t maxnum)
+#else
+static int physfsrwops_read(SDL_RWops *rw, void *ptr, int size, int maxnum)
+#endif
+{
+ PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
+ const PHYSFS_uint64 readlen = (PHYSFS_uint64) (maxnum * size);
+ const PHYSFS_sint64 rc = PHYSFS_readBytes(handle, ptr, readlen);
+ if (rc != ((PHYSFS_sint64) readlen))
+ {
+ if (!PHYSFS_eof(handle)) /* not EOF? Must be an error. */
+ SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+ } /* if */
+
+ #if TARGET_SDL13
+ return (size_t) rc;
+ #else
+ return (int) rc;
+ #endif
+} /* physfsrwops_read */
+
+
+#if TARGET_SDL13
+static size_t SDLCALL physfsrwops_write(struct SDL_RWops *rw, const void *ptr,
+ size_t size, size_t num)
+#else
+static int physfsrwops_write(SDL_RWops *rw, const void *ptr, int size, int num)
+#endif
+{
+ PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
+ const PHYSFS_uint64 writelen = (PHYSFS_uint64) (num * size);
+ const PHYSFS_sint64 rc = PHYSFS_writeBytes(handle, ptr, writelen);
+ if (rc != ((PHYSFS_sint64) writelen))
+ SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+
+ #if TARGET_SDL13
+ return (size_t) rc;
+ #else
+ return (int) rc;
+ #endif
+} /* physfsrwops_write */
+
+
+static int physfsrwops_close(SDL_RWops *rw)
+{
+ PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
+ if (!PHYSFS_close(handle))
+ {
+ SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+ return -1;
+ } /* if */
+
+ SDL_FreeRW(rw);
+ return 0;
+} /* physfsrwops_close */
+
+
+static SDL_RWops *create_rwops(PHYSFS_File *handle)
+{
+ SDL_RWops *retval = NULL;
+
+ if (handle == NULL)
+ SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+ else
+ {
+ retval = SDL_AllocRW();
+ if (retval != NULL)
+ {
+ retval->seek = physfsrwops_seek;
+ retval->read = physfsrwops_read;
+ retval->write = physfsrwops_write;
+ retval->close = physfsrwops_close;
+ retval->hidden.unknown.data1 = handle;
+ } /* if */
+ } /* else */
+
+ return retval;
+} /* create_rwops */
+
+
+SDL_RWops *PHYSFSRWOPS_makeRWops(PHYSFS_File *handle)
+{
+ SDL_RWops *retval = NULL;
+ if (handle == NULL)
+ SDL_SetError("NULL pointer passed to PHYSFSRWOPS_makeRWops().");
+ else
+ retval = create_rwops(handle);
+
+ return retval;
+} /* PHYSFSRWOPS_makeRWops */
+
+
+SDL_RWops *PHYSFSRWOPS_openRead(const char *fname)
+{
+ return create_rwops(PHYSFS_openRead(fname));
+} /* PHYSFSRWOPS_openRead */
+
+
+SDL_RWops *PHYSFSRWOPS_openWrite(const char *fname)
+{
+ return create_rwops(PHYSFS_openWrite(fname));
+} /* PHYSFSRWOPS_openWrite */
+
+
+SDL_RWops *PHYSFSRWOPS_openAppend(const char *fname)
+{
+ return create_rwops(PHYSFS_openAppend(fname));
+} /* PHYSFSRWOPS_openAppend */
+
+
+/* end of physfsrwops.c ... */
+
diff -r 404ddce27b23 -r c13ebed437cb misc/libphyslayer/physfsrwops.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphyslayer/physfsrwops.h Tue Apr 02 21:00:57 2013 +0200
@@ -0,0 +1,88 @@
+/*
+ * This code provides a glue layer between PhysicsFS and Simple Directmedia
+ * Layer's (SDL) RWops i/o abstraction.
+ *
+ * License: this code is public domain. I make no warranty that it is useful,
+ * correct, harmless, or environmentally safe.
+ *
+ * This particular file may be used however you like, including copying it
+ * verbatim into a closed-source project, exploiting it commercially, and
+ * removing any trace of my name from the source (although I hope you won't
+ * do that). I welcome enhancements and corrections to this file, but I do
+ * not require you to send me patches if you make changes. This code has
+ * NO WARRANTY.
+ *
+ * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
+ * Please see LICENSE.txt in the root of the source tree.
+ *
+ * SDL falls under the LGPL license. You can get SDL at http://www.libsdl.org/
+ *
+ * This file was written by Ryan C. Gordon. (icculus@icculus.org).
+ */
+
+#ifndef _INCLUDE_PHYSFSRWOPS_H_
+#define _INCLUDE_PHYSFSRWOPS_H_
+
+#include "physfs.h"
+#include "SDL.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Open a platform-independent filename for reading, and make it accessible
+ * via an SDL_RWops structure. The file will be closed in PhysicsFS when the
+ * RWops is closed. PhysicsFS should be configured to your liking before
+ * opening files through this method.
+ *
+ * @param filename File to open in platform-independent notation.
+ * @return A valid SDL_RWops structure on success, NULL on error. Specifics
+ * of the error can be gleaned from PHYSFS_getLastError().
+ */
+PHYSFS_DECL SDL_RWops *PHYSFSRWOPS_openRead(const char *fname);
+
+/**
+ * Open a platform-independent filename for writing, and make it accessible
+ * via an SDL_RWops structure. The file will be closed in PhysicsFS when the
+ * RWops is closed. PhysicsFS should be configured to your liking before
+ * opening files through this method.
+ *
+ * @param filename File to open in platform-independent notation.
+ * @return A valid SDL_RWops structure on success, NULL on error. Specifics
+ * of the error can be gleaned from PHYSFS_getLastError().
+ */
+PHYSFS_DECL SDL_RWops *PHYSFSRWOPS_openWrite(const char *fname);
+
+/**
+ * Open a platform-independent filename for appending, and make it accessible
+ * via an SDL_RWops structure. The file will be closed in PhysicsFS when the
+ * RWops is closed. PhysicsFS should be configured to your liking before
+ * opening files through this method.
+ *
+ * @param filename File to open in platform-independent notation.
+ * @return A valid SDL_RWops structure on success, NULL on error. Specifics
+ * of the error can be gleaned from PHYSFS_getLastError().
+ */
+PHYSFS_DECL SDL_RWops *PHYSFSRWOPS_openAppend(const char *fname);
+
+/**
+ * Make a SDL_RWops from an existing PhysicsFS file handle. You should
+ * dispose of any references to the handle after successful creation of
+ * the RWops. The actual PhysicsFS handle will be destroyed when the
+ * RWops is closed.
+ *
+ * @param handle a valid PhysicsFS file handle.
+ * @return A valid SDL_RWops structure on success, NULL on error. Specifics
+ * of the error can be gleaned from PHYSFS_getLastError().
+ */
+PHYSFS_DECL SDL_RWops *PHYSFSRWOPS_makeRWops(PHYSFS_File *handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* include-once blocker */
+
+/* end of physfsrwops.h ... */
+
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/Android.mk
--- a/misc/physfs/Android.mk Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-include $(call all-subdir-makefiles)
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/CMakeLists.txt
--- a/misc/physfs/CMakeLists.txt Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,315 +0,0 @@
-# PhysicsFS; a portable, flexible file i/o abstraction.
-# Copyright (C) 2007 Ryan C. Gordon.
-#
-# Please see the file LICENSE.txt in the source's root directory.
-
-## lines starting with '##' are lines overridden/modified/added by Hedgewars configuration
-##CMAKE_MINIMUM_REQUIRED(VERSION 2.4)
-##PROJECT(PhysicsFS)
-set(PHYSFS_VERSION 2.1.0)
-
-# Increment this if/when we break backwards compatibility.
-set(PHYSFS_SOVERSION 1)
-
-# I hate that they define "WIN32" ... we're about to move to Win64...I hope!
-if(WIN32 AND NOT WINDOWS)
- set(WINDOWS TRUE)
-endif(WIN32 AND NOT WINDOWS)
-
-# Bleh, let's do it for "APPLE" too.
-if(APPLE AND NOT MACOSX)
- set(MACOSX TRUE)
-endif(APPLE AND NOT MACOSX)
-
-# For now, Haiku and BeOS are the same, as far as the build system cares.
-if(HAIKU AND NOT BEOS)
- set(BEOS TRUE)
-endif(HAIKU AND NOT BEOS)
-
-if(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
- set(SOLARIS TRUE)
-endif(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
-
-include(CheckIncludeFile)
-include(CheckLibraryExists)
-include(CheckCSourceCompiles)
-
-## SDL is needed by extra
-find_package(SDL REQUIRED)
-include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src) ##
-include_directories(${SDL_INCLUDE_DIR}) ##
-include_directories(${LUA_INCLUDE_DIR}) ##
-
-if(MACOSX)
- # Fallback to older OS X on PowerPC to support wider range of systems...
- if(CMAKE_OSX_ARCHITECTURES MATCHES ppc)
- add_definitions(-DMAC_OS_X_VERSION_MIN_REQUIRED=1020)
- set(OTHER_LDFLAGS ${OTHER_LDFLAGS} " -mmacosx-version-min=10.2")
- endif(CMAKE_OSX_ARCHITECTURES MATCHES ppc)
-
- # Need these everywhere...
- add_definitions(-fno-common)
- find_library(iokit_framework NAMES IOKit)
- list(APPEND OTHER_LDFLAGS ${iokit_framework})
-endif(MACOSX)
-
-# Add some gcc-specific command lines.
-if(CMAKE_COMPILER_IS_GNUCC)
- # Always build with debug symbols...you can strip it later.
- add_definitions(-g -pipe -Werror -fsigned-char)
-
- # Stupid BeOS generates warnings in the system headers.
- if(NOT BEOS)
- add_definitions(-Wall)
- endif(NOT BEOS)
-
- CHECK_C_SOURCE_COMPILES("
- #if ((defined(__GNUC__)) && (__GNUC__ >= 4))
- int main(int argc, char **argv) { int is_gcc4 = 1; return 0; }
- #else
- #error This is not gcc4.
- #endif
- " PHYSFS_IS_GCC4)
-
- if(PHYSFS_IS_GCC4)
- # Not supported on several operating systems at this time.
- if(NOT SOLARIS AND NOT WINDOWS)
- add_definitions(-fvisibility=hidden)
- endif(NOT SOLARIS AND NOT WINDOWS)
- endif(PHYSFS_IS_GCC4)
-
- # Don't use -rpath.
- set(CMAKE_SKIP_RPATH ON CACHE BOOL "Skip RPATH" FORCE)
-endif(CMAKE_COMPILER_IS_GNUCC)
-
-if(CMAKE_C_COMPILER_ID STREQUAL "SunPro")
- add_definitions(-erroff=E_EMPTY_TRANSLATION_UNIT)
- add_definitions(-xldscope=hidden)
-endif(CMAKE_C_COMPILER_ID STREQUAL "SunPro")
-
-if(MSVC)
- # VS.NET 8.0 got really really anal about strcpy, etc, which even if we
- # cleaned up our code, zlib, etc still use...so disable the warning.
- add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
-endif(MSVC)
-
-
-# Basic chunks of source code ...
-set(LZMA_SRCS
- src/lzma/C/7zCrc.c
- src/lzma/C/Archive/7z/7zBuffer.c
- src/lzma/C/Archive/7z/7zDecode.c
- src/lzma/C/Archive/7z/7zExtract.c
- src/lzma/C/Archive/7z/7zHeader.c
- src/lzma/C/Archive/7z/7zIn.c
- src/lzma/C/Archive/7z/7zItem.c
- src/lzma/C/Archive/7z/7zMethodID.c
- src/lzma/C/Compress/Branch/BranchX86.c
- src/lzma/C/Compress/Branch/BranchX86_2.c
- src/lzma/C/Compress/Lzma/LzmaDecode.c
-)
-
-if(BEOS)
- # We add this explicitly, since we don't want CMake to think this
- # is a C++ project unless we're on BeOS.
- set(PHYSFS_BEOS_SRCS src/platform_beos.cpp)
- find_library(BE_LIBRARY be)
- find_library(ROOT_LIBRARY root)
- set(optionAL_LIBRARY_LIBS ${optionAL_LIBRARY_LIBS} ${BE_LIBRARY} ${ROOT_LIBRARY})
-endif(BEOS)
-
-## extra functions needed by Hedgewars
-## TODO: maybe it's better to have them in a separate library?
-set(PHYSFS_HEDGE_SRCS
- extras/physfsrwops.c
- extras/physfslualoader.c
- extras/hwpacksmounter.c
-)
-
-# Almost everything is "compiled" here, but things that don't apply to the
-# build are #ifdef'd out. This is to make it easy to embed PhysicsFS into
-# another project or bring up a new build system: just compile all the source
-# code and #define the things you want.
-set(PHYSFS_SRCS
- src/physfs.c
- src/physfs_byteorder.c
- src/physfs_unicode.c
- src/platform_posix.c
- src/platform_unix.c
- src/platform_macosx.c
- src/platform_windows.c
- src/archiver_dir.c
- src/archiver_unpacked.c
- src/archiver_grp.c
- src/archiver_hog.c
- src/archiver_lzma.c
- src/archiver_mvl.c
- src/archiver_qpak.c
- src/archiver_wad.c
- src/archiver_zip.c
- src/archiver_iso9660.c
- ${PHYSFS_BEOS_SRCS}
- ${PHYSFS_HEDGE_SRCS} ##
-)
-
-
-# platform layers ...
-
-if(UNIX)
- if(BEOS)
- set(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
- set(PHYSFS_HAVE_THREAD_SUPPORT TRUE)
- set(HAVE_PTHREAD_H TRUE)
- else(BEOS)
- CHECK_INCLUDE_FILE(sys/ucred.h HAVE_UCRED_H)
- if(HAVE_UCRED_H)
- add_definitions(-DPHYSFS_HAVE_SYS_UCRED_H=1)
- set(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
- endif(HAVE_UCRED_H)
-
- CHECK_INCLUDE_FILE(mntent.h HAVE_MNTENT_H)
- if(HAVE_MNTENT_H)
- add_definitions(-DPHYSFS_HAVE_MNTENT_H=1)
- set(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
- endif(HAVE_MNTENT_H)
-
- # !!! FIXME: Solaris fails this, because mnttab.h implicitly
- # !!! FIXME: depends on other system headers. :(
- #CHECK_INCLUDE_FILE(sys/mnttab.h HAVE_SYS_MNTTAB_H)
- CHECK_C_SOURCE_COMPILES("
- #include
- #include
- int main(int argc, char **argv) { return 0; }
- " HAVE_SYS_MNTTAB_H)
-
- if(HAVE_SYS_MNTTAB_H)
- add_definitions(-DPHYSFS_HAVE_SYS_MNTTAB_H=1)
- set(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
- endif(HAVE_SYS_MNTTAB_H)
-
- CHECK_INCLUDE_FILE(pthread.h HAVE_PTHREAD_H)
- if(HAVE_PTHREAD_H)
- set(PHYSFS_HAVE_THREAD_SUPPORT TRUE)
- endif(HAVE_PTHREAD_H)
- endif(BEOS)
-endif(UNIX)
-
-if(WINDOWS)
- set(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
- set(PHYSFS_HAVE_THREAD_SUPPORT TRUE)
-endif(WINDOWS)
-
-if(NOT PHYSFS_HAVE_CDROM_SUPPORT)
- add_definitions(-DPHYSFS_NO_CDROM_SUPPORT=1)
- message(WARNING " ***")
- message(WARNING " *** There is no CD-ROM support in this build!")
- message(WARNING " *** PhysicsFS will just pretend there are no discs.")
- message(WARNING " *** This may be fine, depending on how PhysicsFS is used,")
- message(WARNING " *** but is this what you REALLY wanted?")
- message(WARNING " *** (Maybe fix CMakeLists.txt, or write a platform driver?)")
- message(WARNING " ***")
-endif(NOT PHYSFS_HAVE_CDROM_SUPPORT)
-
-if(PHYSFS_HAVE_THREAD_SUPPORT)
- add_definitions(-D_REENTRANT -D_THREAD_SAFE)
-else(PHYSFS_HAVE_THREAD_SUPPORT)
- add_definitions(-DPHYSFS_NO_THREAD_SUPPORT=1)
- message(WARNING " ***")
- message(WARNING " *** There is no thread support in this build!")
- message(WARNING " *** PhysicsFS will NOT be reentrant!")
- message(WARNING " *** This may be fine, depending on how PhysicsFS is used,")
- message(WARNING " *** but is this what you REALLY wanted?")
- message(WARNING " *** (Maybe fix CMakeLists.txt, or write a platform driver?)")
- message(WARNING " ***")
-endif(PHYSFS_HAVE_THREAD_SUPPORT)
-
-
-# Archivers ...
-
-option(PHYSFS_ARCHIVE_ZIP "Enable ZIP support" TRUE)
-if(PHYSFS_ARCHIVE_ZIP)
- add_definitions(-DPHYSFS_SUPPORTS_ZIP=1)
- set(PHYSFS_FEATURES "ZIP")
-endif(PHYSFS_ARCHIVE_ZIP)
-
-option(PHYSFS_ARCHIVE_7Z "Enable 7zip support" FALSE)
-if(PHYSFS_ARCHIVE_7Z)
- add_definitions(-DPHYSFS_SUPPORTS_7Z=1)
- list(APPEND PHYSFS_SRCS ${LZMA_SRCS})
- set(PHYSFS_FEATURES "${PHYSFS_FEATURES} 7zip")
-endif(PHYSFS_ARCHIVE_7Z)
-
-option(PHYSFS_ARCHIVE_GRP "Enable Build Engine GRP support" TRUE)
-if(PHYSFS_ARCHIVE_GRP)
- add_definitions(-DPHYSFS_SUPPORTS_GRP=1)
- set(PHYSFS_FEATURES "${PHYSFS_FEATURES} GRP")
-endif(PHYSFS_ARCHIVE_GRP)
-
-option(PHYSFS_ARCHIVE_WAD "Enable Doom WAD support" TRUE)
-if(PHYSFS_ARCHIVE_WAD)
- add_definitions(-DPHYSFS_SUPPORTS_WAD=1)
- set(PHYSFS_FEATURES "${PHYSFS_FEATURES} WAD")
-endif(PHYSFS_ARCHIVE_WAD)
-
-option(PHYSFS_ARCHIVE_HOG "Enable Descent I/II HOG support" TRUE)
-if(PHYSFS_ARCHIVE_HOG)
- add_definitions(-DPHYSFS_SUPPORTS_HOG=1)
- set(PHYSFS_FEATURES "${PHYSFS_FEATURES} HOG")
-endif(PHYSFS_ARCHIVE_HOG)
-
-option(PHYSFS_ARCHIVE_MVL "Enable Descent I/II MVL support" TRUE)
-if(PHYSFS_ARCHIVE_MVL)
- add_definitions(-DPHYSFS_SUPPORTS_MVL=1)
- set(PHYSFS_FEATURES "${PHYSFS_FEATURES} MVL")
-endif(PHYSFS_ARCHIVE_MVL)
-
-option(PHYSFS_ARCHIVE_QPAK "Enable Quake I/II QPAK support" TRUE)
-if(PHYSFS_ARCHIVE_QPAK)
- add_definitions(-DPHYSFS_SUPPORTS_QPAK=1)
- set(PHYSFS_FEATURES "${PHYSFS_FEATURES} QPAK")
-endif(PHYSFS_ARCHIVE_QPAK)
-
-option(PHYSFS_ARCHIVE_ISO9660 "Enable ISO9660 support" TRUE)
-if(PHYSFS_ARCHIVE_ISO9660)
- add_definitions(-DPHYSFS_SUPPORTS_ISO9660=1)
- set(PHYSFS_FEATURES "${PHYSFS_FEATURES} CD-ROM")
-endif(PHYSFS_ARCHIVE_ISO9660)
-
-##as needed by Hedgewars configuration
-if(WINDOWS)
- option(PHYSFS_BUILD_STATIC "Build static library" FALSE)
- option(PHYSFS_BUILD_SHARED "Build shared library" TRUE)
- list(APPEND OTHER_LDFLAGS ${SDL_LIBRARY})
-else(WINDOWS)
- option(PHYSFS_BUILD_STATIC "Build static library" TRUE)
- option(PHYSFS_BUILD_SHARED "Build shared library" FALSE)
-endif(WINDOWS)
-
-if(PHYSFS_BUILD_STATIC)
- add_library(physfs STATIC ${PHYSFS_SRCS})
- set_target_properties(physfs PROPERTIES OUTPUT_NAME "physfs")
-endif(PHYSFS_BUILD_STATIC)
-
-if(PHYSFS_BUILD_SHARED)
- add_library(physfs SHARED ${PHYSFS_SRCS})
- set_target_properties(physfs PROPERTIES VERSION ${PHYSFS_VERSION})
- set_target_properties(physfs PROPERTIES SOVERSION ${PHYSFS_SOVERSION})
- target_link_libraries(physfs ${optionAL_LIBRARY_LIBS} ${OTHER_LDFLAGS})
- install(TARGETS physfs RUNTIME DESTINATION ${target_library_install_dir}) ##
-endif(PHYSFS_BUILD_SHARED)
-
-if(NOT PHYSFS_BUILD_SHARED AND NOT PHYSFS_BUILD_STATIC)
- message(FATAL "Both shared and static libraries are disabled!")
-endif(NOT PHYSFS_BUILD_SHARED AND NOT PHYSFS_BUILD_STATIC)
-
-# CMake FAQ says I need this...
-if(PHYSFS_BUILD_SHARED AND PHYSFS_BUILD_STATIC)
- set_target_properties(physfs PROPERTIES CLEAN_DIRECT_OUTPUT 1)
-endif(PHYSFS_BUILD_SHARED AND PHYSFS_BUILD_STATIC)
-
-
-## removed install, language bindings and test program
-## simplified configuration output
-
-message(STATUS "PhysicsFS will build with ${PHYSFS_FEATURES} support")
-
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/Xcode/Physfs.xcodeproj/project.pbxproj
--- a/misc/physfs/Xcode/Physfs.xcodeproj/project.pbxproj Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,354 +0,0 @@
-// !$*UTF8*$!
-{
- archiveVersion = 1;
- classes = {
- };
- objectVersion = 45;
- objects = {
-
-/* Begin PBXBuildFile section */
- 610FB79016613776002FB2A7 /* archiver_dir.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB77916613776002FB2A7 /* archiver_dir.c */; };
- 610FB79116613776002FB2A7 /* archiver_grp.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB77A16613776002FB2A7 /* archiver_grp.c */; };
- 610FB79216613776002FB2A7 /* archiver_hog.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB77B16613776002FB2A7 /* archiver_hog.c */; };
- 610FB79316613776002FB2A7 /* archiver_iso9660.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB77C16613776002FB2A7 /* archiver_iso9660.c */; };
- 610FB79416613776002FB2A7 /* archiver_lzma.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB77D16613776002FB2A7 /* archiver_lzma.c */; };
- 610FB79516613776002FB2A7 /* archiver_mvl.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB77E16613776002FB2A7 /* archiver_mvl.c */; };
- 610FB79616613776002FB2A7 /* archiver_qpak.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB77F16613776002FB2A7 /* archiver_qpak.c */; };
- 610FB79716613776002FB2A7 /* archiver_unpacked.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB78016613776002FB2A7 /* archiver_unpacked.c */; };
- 610FB79816613776002FB2A7 /* archiver_wad.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB78116613776002FB2A7 /* archiver_wad.c */; };
- 610FB79916613776002FB2A7 /* archiver_zip.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB78216613776002FB2A7 /* archiver_zip.c */; };
- 610FB79A16613776002FB2A7 /* physfs_byteorder.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB78316613776002FB2A7 /* physfs_byteorder.c */; };
- 610FB79B16613776002FB2A7 /* physfs_casefolding.h in Headers */ = {isa = PBXBuildFile; fileRef = 610FB78416613776002FB2A7 /* physfs_casefolding.h */; };
- 610FB79C16613776002FB2A7 /* physfs_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 610FB78516613776002FB2A7 /* physfs_internal.h */; };
- 610FB79D16613776002FB2A7 /* physfs_miniz.h in Headers */ = {isa = PBXBuildFile; fileRef = 610FB78616613776002FB2A7 /* physfs_miniz.h */; };
- 610FB79E16613776002FB2A7 /* physfs_platforms.h in Headers */ = {isa = PBXBuildFile; fileRef = 610FB78716613776002FB2A7 /* physfs_platforms.h */; };
- 610FB79F16613776002FB2A7 /* physfs_unicode.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB78816613776002FB2A7 /* physfs_unicode.c */; };
- 610FB7A016613776002FB2A7 /* physfs.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB78916613776002FB2A7 /* physfs.c */; };
- 610FB7A116613776002FB2A7 /* physfs.h in Headers */ = {isa = PBXBuildFile; fileRef = 610FB78A16613776002FB2A7 /* physfs.h */; };
- 610FB7A216613776002FB2A7 /* platform_beos.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 610FB78B16613776002FB2A7 /* platform_beos.cpp */; };
- 610FB7A316613776002FB2A7 /* platform_macosx.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB78C16613776002FB2A7 /* platform_macosx.c */; };
- 610FB7A416613776002FB2A7 /* platform_posix.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB78D16613776002FB2A7 /* platform_posix.c */; };
- 610FB7A516613776002FB2A7 /* platform_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB78E16613776002FB2A7 /* platform_unix.c */; };
- 610FB7A616613776002FB2A7 /* platform_windows.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB78F16613776002FB2A7 /* platform_windows.c */; };
- 610FB7AE16613813002FB2A7 /* hwpacksmounter.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB7A916613813002FB2A7 /* hwpacksmounter.c */; };
- 610FB7AF16613813002FB2A7 /* hwpacksmounter.h in Headers */ = {isa = PBXBuildFile; fileRef = 610FB7AA16613813002FB2A7 /* hwpacksmounter.h */; };
- 610FB7B016613813002FB2A7 /* physfslualoader.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB7AB16613813002FB2A7 /* physfslualoader.c */; };
- 610FB7B116613813002FB2A7 /* physfsrwops.c in Sources */ = {isa = PBXBuildFile; fileRef = 610FB7AC16613813002FB2A7 /* physfsrwops.c */; };
- 610FB7B216613813002FB2A7 /* physfsrwops.h in Headers */ = {isa = PBXBuildFile; fileRef = 610FB7AD16613813002FB2A7 /* physfsrwops.h */; };
- AA747D9F0F9514B9006C5449 /* Physfs_Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = AA747D9E0F9514B9006C5449 /* Physfs_Prefix.pch */; };
- AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AACBBE490F95108600F1A2B1 /* Foundation.framework */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXFileReference section */
- 610FB77916613776002FB2A7 /* archiver_dir.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_dir.c; path = ../src/archiver_dir.c; sourceTree = SOURCE_ROOT; };
- 610FB77A16613776002FB2A7 /* archiver_grp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_grp.c; path = ../src/archiver_grp.c; sourceTree = SOURCE_ROOT; };
- 610FB77B16613776002FB2A7 /* archiver_hog.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_hog.c; path = ../src/archiver_hog.c; sourceTree = SOURCE_ROOT; };
- 610FB77C16613776002FB2A7 /* archiver_iso9660.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_iso9660.c; path = ../src/archiver_iso9660.c; sourceTree = SOURCE_ROOT; };
- 610FB77D16613776002FB2A7 /* archiver_lzma.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_lzma.c; path = ../src/archiver_lzma.c; sourceTree = SOURCE_ROOT; };
- 610FB77E16613776002FB2A7 /* archiver_mvl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_mvl.c; path = ../src/archiver_mvl.c; sourceTree = SOURCE_ROOT; };
- 610FB77F16613776002FB2A7 /* archiver_qpak.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_qpak.c; path = ../src/archiver_qpak.c; sourceTree = SOURCE_ROOT; };
- 610FB78016613776002FB2A7 /* archiver_unpacked.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_unpacked.c; path = ../src/archiver_unpacked.c; sourceTree = SOURCE_ROOT; };
- 610FB78116613776002FB2A7 /* archiver_wad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_wad.c; path = ../src/archiver_wad.c; sourceTree = SOURCE_ROOT; };
- 610FB78216613776002FB2A7 /* archiver_zip.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = archiver_zip.c; path = ../src/archiver_zip.c; sourceTree = SOURCE_ROOT; };
- 610FB78316613776002FB2A7 /* physfs_byteorder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = physfs_byteorder.c; path = ../src/physfs_byteorder.c; sourceTree = SOURCE_ROOT; };
- 610FB78416613776002FB2A7 /* physfs_casefolding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = physfs_casefolding.h; path = ../src/physfs_casefolding.h; sourceTree = SOURCE_ROOT; };
- 610FB78516613776002FB2A7 /* physfs_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = physfs_internal.h; path = ../src/physfs_internal.h; sourceTree = SOURCE_ROOT; };
- 610FB78616613776002FB2A7 /* physfs_miniz.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = physfs_miniz.h; path = ../src/physfs_miniz.h; sourceTree = SOURCE_ROOT; };
- 610FB78716613776002FB2A7 /* physfs_platforms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = physfs_platforms.h; path = ../src/physfs_platforms.h; sourceTree = SOURCE_ROOT; };
- 610FB78816613776002FB2A7 /* physfs_unicode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = physfs_unicode.c; path = ../src/physfs_unicode.c; sourceTree = SOURCE_ROOT; };
- 610FB78916613776002FB2A7 /* physfs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = physfs.c; path = ../src/physfs.c; sourceTree = SOURCE_ROOT; };
- 610FB78A16613776002FB2A7 /* physfs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = physfs.h; path = ../src/physfs.h; sourceTree = SOURCE_ROOT; };
- 610FB78B16613776002FB2A7 /* platform_beos.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = platform_beos.cpp; path = ../src/platform_beos.cpp; sourceTree = SOURCE_ROOT; };
- 610FB78C16613776002FB2A7 /* platform_macosx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = platform_macosx.c; path = ../src/platform_macosx.c; sourceTree = SOURCE_ROOT; };
- 610FB78D16613776002FB2A7 /* platform_posix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = platform_posix.c; path = ../src/platform_posix.c; sourceTree = SOURCE_ROOT; };
- 610FB78E16613776002FB2A7 /* platform_unix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = platform_unix.c; path = ../src/platform_unix.c; sourceTree = SOURCE_ROOT; };
- 610FB78F16613776002FB2A7 /* platform_windows.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = platform_windows.c; path = ../src/platform_windows.c; sourceTree = SOURCE_ROOT; };
- 610FB7A916613813002FB2A7 /* hwpacksmounter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = hwpacksmounter.c; path = ../extras/hwpacksmounter.c; sourceTree = SOURCE_ROOT; };
- 610FB7AA16613813002FB2A7 /* hwpacksmounter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hwpacksmounter.h; path = ../extras/hwpacksmounter.h; sourceTree = SOURCE_ROOT; };
- 610FB7AB16613813002FB2A7 /* physfslualoader.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = physfslualoader.c; path = ../extras/physfslualoader.c; sourceTree = SOURCE_ROOT; };
- 610FB7AC16613813002FB2A7 /* physfsrwops.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = physfsrwops.c; path = ../extras/physfsrwops.c; sourceTree = SOURCE_ROOT; };
- 610FB7AD16613813002FB2A7 /* physfsrwops.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = physfsrwops.h; path = ../extras/physfsrwops.h; sourceTree = SOURCE_ROOT; };
- AA747D9E0F9514B9006C5449 /* Physfs_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Physfs_Prefix.pch; sourceTree = SOURCE_ROOT; };
- AACBBE490F95108600F1A2B1 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
- D2AAC07E0554694100DB518D /* libPhysfs.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPhysfs.a; sourceTree = BUILT_PRODUCTS_DIR; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
- D2AAC07C0554694100DB518D /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
- 034768DFFF38A50411DB9C8B /* Products */ = {
- isa = PBXGroup;
- children = (
- D2AAC07E0554694100DB518D /* libPhysfs.a */,
- );
- name = Products;
- sourceTree = "";
- };
- 0867D691FE84028FC02AAC07 /* Physfs */ = {
- isa = PBXGroup;
- children = (
- 08FB77AEFE84172EC02AAC07 /* Sources */,
- 610FB77116613730002FB2A7 /* Extras */,
- 32C88DFF0371C24200C91783 /* Other Sources */,
- 0867D69AFE84028FC02AAC07 /* Frameworks */,
- 034768DFFF38A50411DB9C8B /* Products */,
- );
- name = Physfs;
- sourceTree = "";
- };
- 0867D69AFE84028FC02AAC07 /* Frameworks */ = {
- isa = PBXGroup;
- children = (
- AACBBE490F95108600F1A2B1 /* Foundation.framework */,
- );
- name = Frameworks;
- sourceTree = "";
- };
- 08FB77AEFE84172EC02AAC07 /* Sources */ = {
- isa = PBXGroup;
- children = (
- 610FB77916613776002FB2A7 /* archiver_dir.c */,
- 610FB77A16613776002FB2A7 /* archiver_grp.c */,
- 610FB77B16613776002FB2A7 /* archiver_hog.c */,
- 610FB77C16613776002FB2A7 /* archiver_iso9660.c */,
- 610FB77D16613776002FB2A7 /* archiver_lzma.c */,
- 610FB77E16613776002FB2A7 /* archiver_mvl.c */,
- 610FB77F16613776002FB2A7 /* archiver_qpak.c */,
- 610FB78016613776002FB2A7 /* archiver_unpacked.c */,
- 610FB78116613776002FB2A7 /* archiver_wad.c */,
- 610FB78216613776002FB2A7 /* archiver_zip.c */,
- 610FB78316613776002FB2A7 /* physfs_byteorder.c */,
- 610FB78416613776002FB2A7 /* physfs_casefolding.h */,
- 610FB78516613776002FB2A7 /* physfs_internal.h */,
- 610FB78616613776002FB2A7 /* physfs_miniz.h */,
- 610FB78716613776002FB2A7 /* physfs_platforms.h */,
- 610FB78816613776002FB2A7 /* physfs_unicode.c */,
- 610FB78916613776002FB2A7 /* physfs.c */,
- 610FB78A16613776002FB2A7 /* physfs.h */,
- 610FB78B16613776002FB2A7 /* platform_beos.cpp */,
- 610FB78C16613776002FB2A7 /* platform_macosx.c */,
- 610FB78D16613776002FB2A7 /* platform_posix.c */,
- 610FB78E16613776002FB2A7 /* platform_unix.c */,
- 610FB78F16613776002FB2A7 /* platform_windows.c */,
- );
- name = Sources;
- sourceTree = "";
- };
- 32C88DFF0371C24200C91783 /* Other Sources */ = {
- isa = PBXGroup;
- children = (
- AA747D9E0F9514B9006C5449 /* Physfs_Prefix.pch */,
- );
- name = "Other Sources";
- sourceTree = "";
- };
- 610FB77116613730002FB2A7 /* Extras */ = {
- isa = PBXGroup;
- children = (
- 610FB7A916613813002FB2A7 /* hwpacksmounter.c */,
- 610FB7AA16613813002FB2A7 /* hwpacksmounter.h */,
- 610FB7AB16613813002FB2A7 /* physfslualoader.c */,
- 610FB7AC16613813002FB2A7 /* physfsrwops.c */,
- 610FB7AD16613813002FB2A7 /* physfsrwops.h */,
- );
- name = Extras;
- sourceTree = "";
- };
-/* End PBXGroup section */
-
-/* Begin PBXHeadersBuildPhase section */
- D2AAC07A0554694100DB518D /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- AA747D9F0F9514B9006C5449 /* Physfs_Prefix.pch in Headers */,
- 610FB79B16613776002FB2A7 /* physfs_casefolding.h in Headers */,
- 610FB79C16613776002FB2A7 /* physfs_internal.h in Headers */,
- 610FB79D16613776002FB2A7 /* physfs_miniz.h in Headers */,
- 610FB79E16613776002FB2A7 /* physfs_platforms.h in Headers */,
- 610FB7A116613776002FB2A7 /* physfs.h in Headers */,
- 610FB7AF16613813002FB2A7 /* hwpacksmounter.h in Headers */,
- 610FB7B216613813002FB2A7 /* physfsrwops.h in Headers */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXHeadersBuildPhase section */
-
-/* Begin PBXNativeTarget section */
- D2AAC07D0554694100DB518D /* Physfs */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "Physfs" */;
- buildPhases = (
- D2AAC07A0554694100DB518D /* Headers */,
- D2AAC07B0554694100DB518D /* Sources */,
- D2AAC07C0554694100DB518D /* Frameworks */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = Physfs;
- productName = Physfs;
- productReference = D2AAC07E0554694100DB518D /* libPhysfs.a */;
- productType = "com.apple.product-type.library.static";
- };
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
- 0867D690FE84028FC02AAC07 /* Project object */ = {
- isa = PBXProject;
- buildConfigurationList = 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "Physfs" */;
- compatibilityVersion = "Xcode 3.1";
- developmentRegion = English;
- hasScannedForEncodings = 1;
- knownRegions = (
- English,
- Japanese,
- French,
- German,
- );
- mainGroup = 0867D691FE84028FC02AAC07 /* Physfs */;
- productRefGroup = 034768DFFF38A50411DB9C8B /* Products */;
- projectDirPath = "";
- projectRoot = "";
- targets = (
- D2AAC07D0554694100DB518D /* Physfs */,
- );
- };
-/* End PBXProject section */
-
-/* Begin PBXSourcesBuildPhase section */
- D2AAC07B0554694100DB518D /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 610FB79016613776002FB2A7 /* archiver_dir.c in Sources */,
- 610FB79116613776002FB2A7 /* archiver_grp.c in Sources */,
- 610FB79216613776002FB2A7 /* archiver_hog.c in Sources */,
- 610FB79316613776002FB2A7 /* archiver_iso9660.c in Sources */,
- 610FB79416613776002FB2A7 /* archiver_lzma.c in Sources */,
- 610FB79516613776002FB2A7 /* archiver_mvl.c in Sources */,
- 610FB79616613776002FB2A7 /* archiver_qpak.c in Sources */,
- 610FB79716613776002FB2A7 /* archiver_unpacked.c in Sources */,
- 610FB79816613776002FB2A7 /* archiver_wad.c in Sources */,
- 610FB79916613776002FB2A7 /* archiver_zip.c in Sources */,
- 610FB79A16613776002FB2A7 /* physfs_byteorder.c in Sources */,
- 610FB79F16613776002FB2A7 /* physfs_unicode.c in Sources */,
- 610FB7A016613776002FB2A7 /* physfs.c in Sources */,
- 610FB7A216613776002FB2A7 /* platform_beos.cpp in Sources */,
- 610FB7A316613776002FB2A7 /* platform_macosx.c in Sources */,
- 610FB7A416613776002FB2A7 /* platform_posix.c in Sources */,
- 610FB7A516613776002FB2A7 /* platform_unix.c in Sources */,
- 610FB7A616613776002FB2A7 /* platform_windows.c in Sources */,
- 610FB7AE16613813002FB2A7 /* hwpacksmounter.c in Sources */,
- 610FB7B016613813002FB2A7 /* physfslualoader.c in Sources */,
- 610FB7B116613813002FB2A7 /* physfsrwops.c in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXSourcesBuildPhase section */
-
-/* Begin XCBuildConfiguration section */
- 1DEB921F08733DC00010E9CD /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- ARCHS = "$(ARCHS_STANDARD_32_BIT)";
- COPY_PHASE_STRIP = NO;
- DSTROOT = /tmp/Physfs.dst;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_ENABLE_FIX_AND_CONTINUE = YES;
- GCC_MODEL_TUNING = G5;
- GCC_OPTIMIZATION_LEVEL = 0;
- GCC_PRECOMPILE_PREFIX_HEADER = YES;
- GCC_PREFIX_HEADER = Physfs_Prefix.pch;
- INSTALL_PATH = /usr/local/lib;
- PRODUCT_NAME = Physfs;
- };
- name = Debug;
- };
- 1DEB922008733DC00010E9CD /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- ARCHS = "$(ARCHS_STANDARD_32_BIT)";
- DSTROOT = /tmp/Physfs.dst;
- GCC_MODEL_TUNING = G5;
- GCC_PRECOMPILE_PREFIX_HEADER = YES;
- GCC_PREFIX_HEADER = Physfs_Prefix.pch;
- INSTALL_PATH = /usr/local/lib;
- PRODUCT_NAME = Physfs;
- };
- name = Release;
- };
- 1DEB922308733DC00010E9CD /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- ARCHS = "$(ARCHS_STANDARD_32_BIT)";
- GCC_C_LANGUAGE_STANDARD = c99;
- GCC_OPTIMIZATION_LEVEL = 0;
- GCC_WARN_ABOUT_RETURN_TYPE = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- HEADER_SEARCH_PATHS = (
- "\"$(SRCROOT)/../../liblua\"",
- "\"$(SRCROOT)/../../../../Library/SDL/include\"",
- );
- OTHER_LDFLAGS = "-ObjC";
- PREBINDING = NO;
- SDKROOT = iphoneos;
- };
- name = Debug;
- };
- 1DEB922408733DC00010E9CD /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- ARCHS = "$(ARCHS_STANDARD_32_BIT)";
- GCC_C_LANGUAGE_STANDARD = c99;
- GCC_WARN_ABOUT_RETURN_TYPE = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- HEADER_SEARCH_PATHS = (
- "\"$(SRCROOT)/../../liblua\"",
- "\"$(SRCROOT)/../../../../Library/SDL/include\"",
- );
- OTHER_LDFLAGS = "-ObjC";
- PREBINDING = NO;
- SDKROOT = iphoneos;
- };
- name = Release;
- };
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
- 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "Physfs" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 1DEB921F08733DC00010E9CD /* Debug */,
- 1DEB922008733DC00010E9CD /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "Physfs" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 1DEB922308733DC00010E9CD /* Debug */,
- 1DEB922408733DC00010E9CD /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
-/* End XCConfigurationList section */
- };
- rootObject = 0867D690FE84028FC02AAC07 /* Project object */;
-}
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/Xcode/Physfs_Prefix.pch
--- a/misc/physfs/Xcode/Physfs_Prefix.pch Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-//
-// Prefix header for all source files of the 'CocoaTouchStaticLibrary' target in the 'CocoaTouchStaticLibrary' project.
-//
-
-#ifdef __OBJC__
- #import
-#endif
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/extras/hwpacksmounter.c
--- a/misc/physfs/extras/hwpacksmounter.c Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-#include
-#include
-#include
-
-#include "hwpacksmounter.h"
-
-PHYSFS_DECL void hedgewarsMountPackages()
-{
- char ** filesList = PHYSFS_enumerateFiles("/");
- char **i;
-
- for (i = filesList; *i != NULL; i++)
- {
- char * fileName = *i;
- int fileNameLength = strlen(fileName);
- if (fileNameLength > 4)
- if (strcmp(fileName + fileNameLength - 4, ".hwp") == 0)
- {
- const char * dir = PHYSFS_getRealDir(fileName);
- if(dir)
- {
- char * fullPath = (char *)malloc(strlen(dir) + fileNameLength + 2);
- strcpy(fullPath, dir);
- strcat(fullPath, "/");
- strcat(fullPath, fileName);
-
- PHYSFS_mount(fullPath, NULL, 1);
-
- free(fullPath);
- }
- }
- }
-
- PHYSFS_freeList(filesList);
-}
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/extras/hwpacksmounter.h
--- a/misc/physfs/extras/hwpacksmounter.h Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-#ifndef HEDGEWARS_PACKAGES_MOUNTER_H
-#define HEDGEWARS_PACKAGES_MOUNTER_H
-
-#include "physfs.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-PHYSFS_DECL void hedgewarsMountPackages();
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/extras/physfslualoader.c
--- a/misc/physfs/extras/physfslualoader.c Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-#include "lua.h"
-#include "physfs.h"
-
-#define BUFSIZE 1024
-
-void *physfsReaderBuffer;
-
-PHYSFS_DECL const char * physfsReader(lua_State *L, PHYSFS_File *f, size_t *size)
-{
-
- if(PHYSFS_eof(f))
- {
- return NULL;
- }
- else
- {
- *size = PHYSFS_readBytes(f, physfsReaderBuffer, BUFSIZE);
-
- if(*size == 0)
- return NULL;
- else
- return physfsReaderBuffer;
- }
-}
-
-PHYSFS_DECL void physfsReaderSetBuffer(void *buffer)
-{
- physfsReaderBuffer = buffer;
-}
-
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/extras/physfsrwops.c
--- a/misc/physfs/extras/physfsrwops.c Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,219 +0,0 @@
-/*
- * This code provides a glue layer between PhysicsFS and Simple Directmedia
- * Layer's (SDL) RWops i/o abstraction.
- *
- * License: this code is public domain. I make no warranty that it is useful,
- * correct, harmless, or environmentally safe.
- *
- * This particular file may be used however you like, including copying it
- * verbatim into a closed-source project, exploiting it commercially, and
- * removing any trace of my name from the source (although I hope you won't
- * do that). I welcome enhancements and corrections to this file, but I do
- * not require you to send me patches if you make changes. This code has
- * NO WARRANTY.
- *
- * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
- * Please see LICENSE.txt in the root of the source tree.
- *
- * SDL 1.2 falls under the LGPL license. SDL 1.3+ is zlib, like PhysicsFS.
- * You can get SDL at http://www.libsdl.org/
- *
- * This file was written by Ryan C. Gordon. (icculus@icculus.org).
- */
-
-#include /* used for SEEK_SET, SEEK_CUR, SEEK_END ... */
-#include "physfsrwops.h"
-
-/* SDL's RWOPS interface changed a little in SDL 1.3... */
-#if defined(SDL_VERSION_ATLEAST)
-#if SDL_VERSION_ATLEAST(1, 3, 0)
-#define TARGET_SDL13 1
-#endif
-#endif
-
-#if TARGET_SDL13
-static long SDLCALL physfsrwops_seek(struct SDL_RWops *rw, long offset, int whence)
-#else
-static int physfsrwops_seek(SDL_RWops *rw, int offset, int whence)
-#endif
-{
- PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
- PHYSFS_sint64 pos = 0;
-
- if (whence == SEEK_SET)
- pos = (PHYSFS_sint64) offset;
-
- else if (whence == SEEK_CUR)
- {
- const PHYSFS_sint64 current = PHYSFS_tell(handle);
- if (current == -1)
- {
- SDL_SetError("Can't find position in file: %s",
- PHYSFS_getLastError());
- return -1;
- } /* if */
-
- if (offset == 0) /* this is a "tell" call. We're done. */
- {
- #if TARGET_SDL13
- return (long) current;
- #else
- return (int) current;
- #endif
- } /* if */
-
- pos = current + ((PHYSFS_sint64) offset);
- } /* else if */
-
- else if (whence == SEEK_END)
- {
- const PHYSFS_sint64 len = PHYSFS_fileLength(handle);
- if (len == -1)
- {
- SDL_SetError("Can't find end of file: %s", PHYSFS_getLastError());
- return -1;
- } /* if */
-
- pos = len + ((PHYSFS_sint64) offset);
- } /* else if */
-
- else
- {
- SDL_SetError("Invalid 'whence' parameter.");
- return -1;
- } /* else */
-
- if ( pos < 0 )
- {
- SDL_SetError("Attempt to seek past start of file.");
- return -1;
- } /* if */
-
- if (!PHYSFS_seek(handle, (PHYSFS_uint64) pos))
- {
- SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
- return -1;
- } /* if */
-
- #if TARGET_SDL13
- return (long) pos;
- #else
- return (int) pos;
- #endif
-} /* physfsrwops_seek */
-
-
-#if TARGET_SDL13
-static size_t SDLCALL physfsrwops_read(struct SDL_RWops *rw, void *ptr,
- size_t size, size_t maxnum)
-#else
-static int physfsrwops_read(SDL_RWops *rw, void *ptr, int size, int maxnum)
-#endif
-{
- PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
- const PHYSFS_uint64 readlen = (PHYSFS_uint64) (maxnum * size);
- const PHYSFS_sint64 rc = PHYSFS_readBytes(handle, ptr, readlen);
- if (rc != ((PHYSFS_sint64) readlen))
- {
- if (!PHYSFS_eof(handle)) /* not EOF? Must be an error. */
- SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
- } /* if */
-
- #if TARGET_SDL13
- return (size_t) rc;
- #else
- return (int) rc;
- #endif
-} /* physfsrwops_read */
-
-
-#if TARGET_SDL13
-static size_t SDLCALL physfsrwops_write(struct SDL_RWops *rw, const void *ptr,
- size_t size, size_t num)
-#else
-static int physfsrwops_write(SDL_RWops *rw, const void *ptr, int size, int num)
-#endif
-{
- PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
- const PHYSFS_uint64 writelen = (PHYSFS_uint64) (num * size);
- const PHYSFS_sint64 rc = PHYSFS_writeBytes(handle, ptr, writelen);
- if (rc != ((PHYSFS_sint64) writelen))
- SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
-
- #if TARGET_SDL13
- return (size_t) rc;
- #else
- return (int) rc;
- #endif
-} /* physfsrwops_write */
-
-
-static int physfsrwops_close(SDL_RWops *rw)
-{
- PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
- if (!PHYSFS_close(handle))
- {
- SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
- return -1;
- } /* if */
-
- SDL_FreeRW(rw);
- return 0;
-} /* physfsrwops_close */
-
-
-static SDL_RWops *create_rwops(PHYSFS_File *handle)
-{
- SDL_RWops *retval = NULL;
-
- if (handle == NULL)
- SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
- else
- {
- retval = SDL_AllocRW();
- if (retval != NULL)
- {
- retval->seek = physfsrwops_seek;
- retval->read = physfsrwops_read;
- retval->write = physfsrwops_write;
- retval->close = physfsrwops_close;
- retval->hidden.unknown.data1 = handle;
- } /* if */
- } /* else */
-
- return retval;
-} /* create_rwops */
-
-
-SDL_RWops *PHYSFSRWOPS_makeRWops(PHYSFS_File *handle)
-{
- SDL_RWops *retval = NULL;
- if (handle == NULL)
- SDL_SetError("NULL pointer passed to PHYSFSRWOPS_makeRWops().");
- else
- retval = create_rwops(handle);
-
- return retval;
-} /* PHYSFSRWOPS_makeRWops */
-
-
-SDL_RWops *PHYSFSRWOPS_openRead(const char *fname)
-{
- return create_rwops(PHYSFS_openRead(fname));
-} /* PHYSFSRWOPS_openRead */
-
-
-SDL_RWops *PHYSFSRWOPS_openWrite(const char *fname)
-{
- return create_rwops(PHYSFS_openWrite(fname));
-} /* PHYSFSRWOPS_openWrite */
-
-
-SDL_RWops *PHYSFSRWOPS_openAppend(const char *fname)
-{
- return create_rwops(PHYSFS_openAppend(fname));
-} /* PHYSFSRWOPS_openAppend */
-
-
-/* end of physfsrwops.c ... */
-
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/extras/physfsrwops.h
--- a/misc/physfs/extras/physfsrwops.h Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +0,0 @@
-/*
- * This code provides a glue layer between PhysicsFS and Simple Directmedia
- * Layer's (SDL) RWops i/o abstraction.
- *
- * License: this code is public domain. I make no warranty that it is useful,
- * correct, harmless, or environmentally safe.
- *
- * This particular file may be used however you like, including copying it
- * verbatim into a closed-source project, exploiting it commercially, and
- * removing any trace of my name from the source (although I hope you won't
- * do that). I welcome enhancements and corrections to this file, but I do
- * not require you to send me patches if you make changes. This code has
- * NO WARRANTY.
- *
- * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
- * Please see LICENSE.txt in the root of the source tree.
- *
- * SDL falls under the LGPL license. You can get SDL at http://www.libsdl.org/
- *
- * This file was written by Ryan C. Gordon. (icculus@icculus.org).
- */
-
-#ifndef _INCLUDE_PHYSFSRWOPS_H_
-#define _INCLUDE_PHYSFSRWOPS_H_
-
-#include "physfs.h"
-#include "SDL.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Open a platform-independent filename for reading, and make it accessible
- * via an SDL_RWops structure. The file will be closed in PhysicsFS when the
- * RWops is closed. PhysicsFS should be configured to your liking before
- * opening files through this method.
- *
- * @param filename File to open in platform-independent notation.
- * @return A valid SDL_RWops structure on success, NULL on error. Specifics
- * of the error can be gleaned from PHYSFS_getLastError().
- */
-PHYSFS_DECL SDL_RWops *PHYSFSRWOPS_openRead(const char *fname);
-
-/**
- * Open a platform-independent filename for writing, and make it accessible
- * via an SDL_RWops structure. The file will be closed in PhysicsFS when the
- * RWops is closed. PhysicsFS should be configured to your liking before
- * opening files through this method.
- *
- * @param filename File to open in platform-independent notation.
- * @return A valid SDL_RWops structure on success, NULL on error. Specifics
- * of the error can be gleaned from PHYSFS_getLastError().
- */
-PHYSFS_DECL SDL_RWops *PHYSFSRWOPS_openWrite(const char *fname);
-
-/**
- * Open a platform-independent filename for appending, and make it accessible
- * via an SDL_RWops structure. The file will be closed in PhysicsFS when the
- * RWops is closed. PhysicsFS should be configured to your liking before
- * opening files through this method.
- *
- * @param filename File to open in platform-independent notation.
- * @return A valid SDL_RWops structure on success, NULL on error. Specifics
- * of the error can be gleaned from PHYSFS_getLastError().
- */
-PHYSFS_DECL SDL_RWops *PHYSFSRWOPS_openAppend(const char *fname);
-
-/**
- * Make a SDL_RWops from an existing PhysicsFS file handle. You should
- * dispose of any references to the handle after successful creation of
- * the RWops. The actual PhysicsFS handle will be destroyed when the
- * RWops is closed.
- *
- * @param handle a valid PhysicsFS file handle.
- * @return A valid SDL_RWops structure on success, NULL on error. Specifics
- * of the error can be gleaned from PHYSFS_getLastError().
- */
-PHYSFS_DECL SDL_RWops *PHYSFSRWOPS_makeRWops(PHYSFS_File *handle);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* include-once blocker */
-
-/* end of physfsrwops.h ... */
-
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/src/Android.mk
--- a/misc/physfs/src/Android.mk Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := physfs
-
-LOCAL_CFLAGS := -O2 -DPHYSFS_NO_CDROM_SUPPORT
-
-LOCAL_C_INCLUDES := $(LOCAL_PATH)
-
-LOCAL_SRC_FILES := physfs.c \
- physfs_byteorder.c \
- physfs_unicode.c \
- platform_posix.c \
- platform_unix.c \
- platform_macosx.c \
- platform_windows.c \
- archiver_dir.c \
- archiver_grp.c \
- archiver_hog.c \
- archiver_lzma.c \
- archiver_mvl.c \
- archiver_qpak.c \
- archiver_wad.c \
- archiver_zip.c \
- ../extras/hwpacksmounter.c \
- ../extras/physfslualoader.c \
- ../extras/physfsrwops.c \
-
-include $(BUILD_SHARED_LIBRARY)
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/src/archiver_dir.c
--- a/misc/physfs/src/archiver_dir.c Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,201 +0,0 @@
-/*
- * Standard directory I/O support routines for PhysicsFS.
- *
- * Please see the file LICENSE.txt in the source's root directory.
- *
- * This file written by Ryan C. Gordon.
- */
-
-#define __PHYSICSFS_INTERNAL__
-#include "physfs_internal.h"
-
-/* There's no PHYSFS_Io interface here. Use __PHYSFS_createNativeIo(). */
-
-
-
-static char *cvtToDependent(const char *prepend, const char *path, char *buf)
-{
- BAIL_IF_MACRO(buf == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
- sprintf(buf, "%s%s", prepend ? prepend : "", path);
-
- if (__PHYSFS_platformDirSeparator != '/')
- {
- char *p;
- for (p = strchr(buf, '/'); p != NULL; p = strchr(p + 1, '/'))
- *p = __PHYSFS_platformDirSeparator;
- } /* if */
-
- return buf;
-} /* cvtToDependent */
-
-
-#define CVT_TO_DEPENDENT(buf, pre, dir) { \
- const size_t len = ((pre) ? strlen((char *) pre) : 0) + strlen(dir) + 1; \
- buf = cvtToDependent((char*)pre,dir,(char*)__PHYSFS_smallAlloc(len)); \
-}
-
-
-
-static void *DIR_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
-{
- PHYSFS_Stat st;
- const char dirsep = __PHYSFS_platformDirSeparator;
- char *retval = NULL;
- const size_t namelen = strlen(name);
- const size_t seplen = 1;
- int exists = 0;
-
- assert(io == NULL); /* shouldn't create an Io for these. */
- BAIL_IF_MACRO(!__PHYSFS_platformStat(name, &exists, &st), ERRPASS, NULL);
- if (st.filetype != PHYSFS_FILETYPE_DIRECTORY)
- BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL);
-
- retval = allocator.Malloc(namelen + seplen + 1);
- BAIL_IF_MACRO(retval == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
-
- strcpy(retval, name);
-
- /* make sure there's a dir separator at the end of the string */
- if (retval[namelen - 1] != dirsep)
- {
- retval[namelen] = dirsep;
- retval[namelen + 1] = '\0';
- } /* if */
-
- return retval;
-} /* DIR_openArchive */
-
-
-static void DIR_enumerateFiles(PHYSFS_Dir *opaque, const char *dname,
- int omitSymLinks, PHYSFS_EnumFilesCallback cb,
- const char *origdir, void *callbackdata)
-{
- char *d;
-
- CVT_TO_DEPENDENT(d, opaque, dname);
- if (d != NULL)
- {
- __PHYSFS_platformEnumerateFiles(d, omitSymLinks, cb,
- origdir, callbackdata);
- __PHYSFS_smallFree(d);
- } /* if */
-} /* DIR_enumerateFiles */
-
-
-static PHYSFS_Io *doOpen(PHYSFS_Dir *opaque, const char *name,
- const int mode, int *fileExists)
-{
- char *f;
- PHYSFS_Io *io = NULL;
- int existtmp = 0;
-
- CVT_TO_DEPENDENT(f, opaque, name);
- BAIL_IF_MACRO(!f, ERRPASS, NULL);
-
- if (fileExists == NULL)
- fileExists = &existtmp;
-
- io = __PHYSFS_createNativeIo(f, mode);
- if (io == NULL)
- {
- const PHYSFS_ErrorCode err = PHYSFS_getLastErrorCode();
- PHYSFS_Stat statbuf;
- __PHYSFS_platformStat(f, fileExists, &statbuf);
- __PHYSFS_setError(err);
- } /* if */
- else
- {
- *fileExists = 1;
- } /* else */
-
- __PHYSFS_smallFree(f);
-
- return io;
-} /* doOpen */
-
-
-static PHYSFS_Io *DIR_openRead(PHYSFS_Dir *opaque, const char *fnm, int *exist)
-{
- return doOpen(opaque, fnm, 'r', exist);
-} /* DIR_openRead */
-
-
-static PHYSFS_Io *DIR_openWrite(PHYSFS_Dir *opaque, const char *filename)
-{
- return doOpen(opaque, filename, 'w', NULL);
-} /* DIR_openWrite */
-
-
-static PHYSFS_Io *DIR_openAppend(PHYSFS_Dir *opaque, const char *filename)
-{
- return doOpen(opaque, filename, 'a', NULL);
-} /* DIR_openAppend */
-
-
-static int DIR_remove(PHYSFS_Dir *opaque, const char *name)
-{
- int retval;
- char *f;
-
- CVT_TO_DEPENDENT(f, opaque, name);
- BAIL_IF_MACRO(!f, ERRPASS, 0);
- retval = __PHYSFS_platformDelete(f);
- __PHYSFS_smallFree(f);
- return retval;
-} /* DIR_remove */
-
-
-static int DIR_mkdir(PHYSFS_Dir *opaque, const char *name)
-{
- int retval;
- char *f;
-
- CVT_TO_DEPENDENT(f, opaque, name);
- BAIL_IF_MACRO(!f, ERRPASS, 0);
- retval = __PHYSFS_platformMkDir(f);
- __PHYSFS_smallFree(f);
- return retval;
-} /* DIR_mkdir */
-
-
-static void DIR_closeArchive(PHYSFS_Dir *opaque)
-{
- allocator.Free(opaque);
-} /* DIR_closeArchive */
-
-
-static int DIR_stat(PHYSFS_Dir *opaque, const char *name,
- int *exists, PHYSFS_Stat *stat)
-{
- int retval = 0;
- char *d;
-
- CVT_TO_DEPENDENT(d, opaque, name);
- BAIL_IF_MACRO(!d, ERRPASS, 0);
- retval = __PHYSFS_platformStat(d, exists, stat);
- __PHYSFS_smallFree(d);
- return retval;
-} /* DIR_stat */
-
-
-const PHYSFS_Archiver __PHYSFS_Archiver_DIR =
-{
- {
- "",
- "Non-archive, direct filesystem I/O",
- "Ryan C. Gordon ",
- "http://icculus.org/physfs/",
- },
- DIR_openArchive, /* openArchive() method */
- DIR_enumerateFiles, /* enumerateFiles() method */
- DIR_openRead, /* openRead() method */
- DIR_openWrite, /* openWrite() method */
- DIR_openAppend, /* openAppend() method */
- DIR_remove, /* remove() method */
- DIR_mkdir, /* mkdir() method */
- DIR_closeArchive, /* closeArchive() method */
- DIR_stat /* stat() method */
-};
-
-/* end of dir.c ... */
-
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/src/archiver_grp.c
--- a/misc/physfs/src/archiver_grp.c Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,110 +0,0 @@
-/*
- * GRP support routines for PhysicsFS.
- *
- * This driver handles BUILD engine archives ("groupfiles"). This format
- * (but not this driver) was put together by Ken Silverman.
- *
- * The format is simple enough. In Ken's words:
- *
- * What's the .GRP file format?
- *
- * The ".grp" file format is just a collection of a lot of files stored
- * into 1 big one. I tried to make the format as simple as possible: The
- * first 12 bytes contains my name, "KenSilverman". The next 4 bytes is
- * the number of files that were compacted into the group file. Then for
- * each file, there is a 16 byte structure, where the first 12 bytes are
- * the filename, and the last 4 bytes are the file's size. The rest of
- * the group file is just the raw data packed one after the other in the
- * same order as the list of files.
- *
- * (That info is from http://www.advsys.net/ken/build.htm ...)
- *
- * Please see the file LICENSE.txt in the source's root directory.
- *
- * This file written by Ryan C. Gordon.
- */
-
-#define __PHYSICSFS_INTERNAL__
-#include "physfs_internal.h"
-
-#if PHYSFS_SUPPORTS_GRP
-
-static UNPKentry *grpLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 fileCount)
-{
- PHYSFS_uint32 location = 16; /* sizeof sig. */
- UNPKentry *entries = NULL;
- UNPKentry *entry = NULL;
- char *ptr = NULL;
-
- entries = (UNPKentry *) allocator.Malloc(sizeof (UNPKentry) * fileCount);
- BAIL_IF_MACRO(entries == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
-
- location += (16 * fileCount);
-
- for (entry = entries; fileCount > 0; fileCount--, entry++)
- {
- GOTO_IF_MACRO(!__PHYSFS_readAll(io, &entry->name, 12), ERRPASS, failed);
- GOTO_IF_MACRO(!__PHYSFS_readAll(io, &entry->size, 4), ERRPASS, failed);
- entry->name[12] = '\0'; /* name isn't null-terminated in file. */
- if ((ptr = strchr(entry->name, ' ')) != NULL)
- *ptr = '\0'; /* trim extra spaces. */
-
- entry->size = PHYSFS_swapULE32(entry->size);
- entry->startPos = location;
- location += entry->size;
- } /* for */
-
- return entries;
-
-failed:
- allocator.Free(entries);
- return NULL;
-} /* grpLoadEntries */
-
-
-static void *GRP_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
-{
- PHYSFS_uint8 buf[12];
- PHYSFS_uint32 count = 0;
- UNPKentry *entries = NULL;
-
- assert(io != NULL); /* shouldn't ever happen. */
-
- BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
-
- BAIL_IF_MACRO(!__PHYSFS_readAll(io, buf, sizeof (buf)), ERRPASS, NULL);
- if (memcmp(buf, "KenSilverman", sizeof (buf)) != 0)
- BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL);
-
- BAIL_IF_MACRO(!__PHYSFS_readAll(io, &count, sizeof(count)), ERRPASS, NULL);
- count = PHYSFS_swapULE32(count);
-
- entries = grpLoadEntries(io, count);
- BAIL_IF_MACRO(!entries, ERRPASS, NULL);
- return UNPK_openArchive(io, entries, count);
-} /* GRP_openArchive */
-
-
-const PHYSFS_Archiver __PHYSFS_Archiver_GRP =
-{
- {
- "GRP",
- "Build engine Groupfile format",
- "Ryan C. Gordon ",
- "http://icculus.org/physfs/",
- },
- GRP_openArchive, /* openArchive() method */
- UNPK_enumerateFiles, /* enumerateFiles() method */
- UNPK_openRead, /* openRead() method */
- UNPK_openWrite, /* openWrite() method */
- UNPK_openAppend, /* openAppend() method */
- UNPK_remove, /* remove() method */
- UNPK_mkdir, /* mkdir() method */
- UNPK_closeArchive, /* closeArchive() method */
- UNPK_stat /* stat() method */
-};
-
-#endif /* defined PHYSFS_SUPPORTS_GRP */
-
-/* end of grp.c ... */
-
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/src/archiver_hog.c
--- a/misc/physfs/src/archiver_hog.c Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,116 +0,0 @@
-/*
- * HOG support routines for PhysicsFS.
- *
- * This driver handles Descent I/II HOG archives.
- *
- * The format is very simple:
- *
- * The file always starts with the 3-byte signature "DHF" (Descent
- * HOG file). After that the files of a HOG are just attached after
- * another, divided by a 17 bytes header, which specifies the name
- * and length (in bytes) of the forthcoming file! So you just read
- * the header with its information of how big the following file is,
- * and then skip exact that number of bytes to get to the next file
- * in that HOG.
- *
- * char sig[3] = {'D', 'H', 'F'}; // "DHF"=Descent HOG File
- *
- * struct {
- * char file_name[13]; // Filename, padded to 13 bytes with 0s
- * int file_size; // filesize in bytes
- * char data[file_size]; // The file data
- * } FILE_STRUCT; // Repeated until the end of the file.
- *
- * (That info is from http://www.descent2.com/ddn/specs/hog/)
- *
- * Please see the file LICENSE.txt in the source's root directory.
- *
- * This file written by Bradley Bell.
- * Based on grp.c by Ryan C. Gordon.
- */
-
-#define __PHYSICSFS_INTERNAL__
-#include "physfs_internal.h"
-
-#if PHYSFS_SUPPORTS_HOG
-
-static UNPKentry *hogLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 *_entCount)
-{
- const PHYSFS_uint64 iolen = io->length(io);
- PHYSFS_uint32 entCount = 0;
- void *ptr = NULL;
- UNPKentry *entries = NULL;
- UNPKentry *entry = NULL;
- PHYSFS_uint32 size = 0;
- PHYSFS_uint32 pos = 3;
-
- while (pos < iolen)
- {
- entCount++;
- ptr = allocator.Realloc(ptr, sizeof (UNPKentry) * entCount);
- GOTO_IF_MACRO(ptr == NULL, PHYSFS_ERR_OUT_OF_MEMORY, failed);
- entries = (UNPKentry *) ptr;
- entry = &entries[entCount-1];
-
- GOTO_IF_MACRO(!__PHYSFS_readAll(io, &entry->name, 13), ERRPASS, failed);
- pos += 13;
- GOTO_IF_MACRO(!__PHYSFS_readAll(io, &size, 4), ERRPASS, failed);
- pos += 4;
-
- entry->size = PHYSFS_swapULE32(size);
- entry->startPos = pos;
- pos += size;
-
- /* skip over entry */
- GOTO_IF_MACRO(!io->seek(io, pos), ERRPASS, failed);
- } /* while */
-
- *_entCount = entCount;
- return entries;
-
-failed:
- allocator.Free(entries);
- return NULL;
-} /* hogLoadEntries */
-
-
-static void *HOG_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
-{
- PHYSFS_uint8 buf[3];
- PHYSFS_uint32 count = 0;
- UNPKentry *entries = NULL;
-
- assert(io != NULL); /* shouldn't ever happen. */
- BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
- BAIL_IF_MACRO(!__PHYSFS_readAll(io, buf, 3), ERRPASS, NULL);
- BAIL_IF_MACRO(memcmp(buf, "DHF", 3) != 0, PHYSFS_ERR_UNSUPPORTED, NULL);
-
- entries = hogLoadEntries(io, &count);
- BAIL_IF_MACRO(!entries, ERRPASS, NULL);
- return UNPK_openArchive(io, entries, count);
-} /* HOG_openArchive */
-
-
-const PHYSFS_Archiver __PHYSFS_Archiver_HOG =
-{
- {
- "HOG",
- "Descent I/II HOG file format",
- "Bradley Bell ",
- "http://icculus.org/physfs/",
- },
- HOG_openArchive, /* openArchive() method */
- UNPK_enumerateFiles, /* enumerateFiles() method */
- UNPK_openRead, /* openRead() method */
- UNPK_openWrite, /* openWrite() method */
- UNPK_openAppend, /* openAppend() method */
- UNPK_remove, /* remove() method */
- UNPK_mkdir, /* mkdir() method */
- UNPK_closeArchive, /* closeArchive() method */
- UNPK_stat /* stat() method */
-};
-
-#endif /* defined PHYSFS_SUPPORTS_HOG */
-
-/* end of hog.c ... */
-
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/src/archiver_iso9660.c
--- a/misc/physfs/src/archiver_iso9660.c Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,969 +0,0 @@
-/*
- * ISO9660 support routines for PhysicsFS.
- *
- * Please see the file LICENSE.txt in the source's root directory.
- *
- * This file written by Christoph Nelles.
- */
-
-/* !!! FIXME: this file needs Ryanification. */
-
-/*
- * Handles CD-ROM disk images (and raw CD-ROM devices).
- *
- * Not supported:
- * - RockRidge
- * - Non 2048 Sectors
- * - UDF
- *
- * Deviations from the standard
- * - Ignores mandatory sort order
- * - Allows various invalid file names
- *
- * Problems
- * - Ambiguities in the standard
- */
-
-#define __PHYSICSFS_INTERNAL__
-#include "physfs_internal.h"
-
-#if PHYSFS_SUPPORTS_ISO9660
-
-#include
-
-/* cache files smaller than this completely in memory */
-#define ISO9660_FULLCACHEMAXSIZE 2048
-
-/* !!! FIXME: this is going to cause trouble. */
-#pragma pack(push) /* push current alignment to stack */
-#pragma pack(1) /* set alignment to 1 byte boundary */
-
-/* This is the format as defined by the standard
-typedef struct
-{
- PHYSFS_uint32 lsb;
- PHYSFS_uint32 msb;
-} ISOBB32bit; // 32byte Both Byte type, means the value first in LSB then in MSB
-
-typedef struct
-{
- PHYSFS_uint16 lsb;
- PHYSFS_uint16 msb;
-} ISOBB16bit; // 16byte Both Byte type, means the value first in LSB then in MSB
-*/
-
-/* define better ones to simplify coding (less if's) */
-#if PHYSFS_BYTEORDER == PHYSFS_LIL_ENDIAN
-#define ISOBB32bit(name) PHYSFS_uint32 name; PHYSFS_uint32 __dummy_##name;
-#define ISOBB16bit(name) PHYSFS_uint16 name; PHYSFS_uint16 __dummy_##name;
-#else
-#define ISOBB32bit(name) PHYSFS_uint32 __dummy_##name; PHYSFS_uint32 name;
-#define ISOBB16bit(name) PHYSFS_uint16 __dummy_##name; PHYSFS_uint16 name;
-#endif
-
-typedef struct
-{
- char year[4];
- char month[2];
- char day[2];
- char hour[2];
- char minute[2];
- char second[2];
- char centisec[2];
- PHYSFS_sint8 offset; /* in 15min from GMT */
-} ISO9660VolumeTimestamp;
-
-typedef struct
-{
- PHYSFS_uint8 year;
- PHYSFS_uint8 month;
- PHYSFS_uint8 day;
- PHYSFS_uint8 hour;
- PHYSFS_uint8 minute;
- PHYSFS_uint8 second;
- PHYSFS_sint8 offset;
-} ISO9660FileTimestamp;
-
-typedef struct
-{
- unsigned existence:1;
- unsigned directory:1;
- unsigned associated_file:1;
- unsigned record:1;
- unsigned protection:1;
- unsigned reserved:2;
- unsigned multiextent:1;
-} ISO9660FileFlags;
-
-typedef struct
-{
- PHYSFS_uint8 length;
- PHYSFS_uint8 attribute_length;
- ISOBB32bit(extent_location)
- ISOBB32bit(data_length)
- ISO9660FileTimestamp timestamp;
- ISO9660FileFlags file_flags;
- PHYSFS_uint8 file_unit_size;
- PHYSFS_uint8 gap_size;
- ISOBB16bit(vol_seq_no)
- PHYSFS_uint8 len_fi;
- char unused;
-} ISO9660RootDirectoryRecord;
-
-/* this structure is combined for all Volume descriptor types */
-typedef struct
-{
- PHYSFS_uint8 type;
- char identifier[5];
- PHYSFS_uint8 version;
- PHYSFS_uint8 flags;
- char system_identifier[32];
- char volume_identifier[32];
- char unused2[8];
- ISOBB32bit(space_size)
- PHYSFS_uint8 escape_sequences[32];
- ISOBB16bit(vol_set_size)
- ISOBB16bit(vol_seq_no)
- ISOBB16bit(block_size)
- ISOBB32bit(path_table_size)
-/* PHYSFS_uint32 path_table_start_lsb; // why didn't they use both byte type?
- PHYSFS_uint32 opt_path_table_start_lsb;
- PHYSFS_uint32 path_table_start_msb;
- PHYSFS_uint32 opt_path_table_start_msb;*/
-#if PHYSFS_BYTEORDER == PHYSFS_LIL_ENDIAN
- PHYSFS_uint32 path_table_start;
- PHYSFS_uint32 opt_path_table_start;
- PHYSFS_uint32 unused6;
- PHYSFS_uint32 unused7;
-#else
- PHYSFS_uint32 unused6;
- PHYSFS_uint32 unused7;
- PHYSFS_uint32 path_table_start;
- PHYSFS_uint32 opt_path_table_start;
-#endif
- ISO9660RootDirectoryRecord rootdirectory;
- char set_identifier[128];
- char publisher_identifier[128];
- char preparer_identifer[128];
- char application_identifier[128];
- char copyright_file_identifier[37];
- char abstract_file_identifier[37];
- char bibliographic_file_identifier[37];
- ISO9660VolumeTimestamp creation_timestamp;
- ISO9660VolumeTimestamp modification_timestamp;
- ISO9660VolumeTimestamp expiration_timestamp;
- ISO9660VolumeTimestamp effective_timestamp;
- PHYSFS_uint8 file_structure_version;
- char unused4;
- char application_use[512];
- char unused5[653];
-} ISO9660VolumeDescriptor;
-
-typedef struct
-{
- PHYSFS_uint8 recordlen;
- PHYSFS_uint8 extattributelen;
- ISOBB32bit(extentpos)
- ISOBB32bit(datalen)
- ISO9660FileTimestamp recordtime;
- ISO9660FileFlags flags;
- PHYSFS_uint8 file_unit_size;
- PHYSFS_uint8 interleave_gap;
- ISOBB16bit(volseqno)
- PHYSFS_uint8 filenamelen;
- char filename[222]; /* This is not exact, but makes reading easier */
-} ISO9660FileDescriptor;
-
-typedef struct
-{
- ISOBB16bit(owner)
- ISOBB16bit(group)
- PHYSFS_uint16 flags; /* not implemented*/
- ISO9660VolumeTimestamp create_time; /* yes, not file timestamp */
- ISO9660VolumeTimestamp mod_time;
- ISO9660VolumeTimestamp expire_time;
- ISO9660VolumeTimestamp effective_time;
- PHYSFS_uint8 record_format;
- PHYSFS_uint8 record_attributes;
- ISOBB16bit(record_len)
- char system_identifier[32];
- char system_use[64];
- PHYSFS_uint8 version;
- ISOBB16bit(escape_len)
- char reserved[64];
- /** further fields not implemented */
-} ISO9660ExtAttributeRec;
-
-#pragma pack(pop) /* restore original alignment from stack */
-
-typedef struct
-{
- PHYSFS_Io *io;
- PHYSFS_uint32 rootdirstart;
- PHYSFS_uint32 rootdirsize;
- PHYSFS_uint64 currpos;
- int isjoliet;
- char *path;
- void *mutex;
-} ISO9660Handle;
-
-
-typedef struct __ISO9660FileHandle
-{
- PHYSFS_sint64 filesize;
- PHYSFS_uint64 currpos;
- PHYSFS_uint64 startblock;
- ISO9660Handle *isohandle;
- PHYSFS_uint32 (*read) (struct __ISO9660FileHandle *filehandle, void *buffer,
- PHYSFS_uint64 len);
- int (*seek)(struct __ISO9660FileHandle *filehandle, PHYSFS_sint64 offset);
- void (*close)(struct __ISO9660FileHandle *filehandle);
- /* !!! FIXME: anonymouse union is going to cause problems. */
- union
- {
- /* !!! FIXME: just use a memory PHYSFS_Io here, unify all this code. */
- char *cacheddata; /* data of file when cached */
- PHYSFS_Io *io; /* handle to separate opened file */
- };
-} ISO9660FileHandle;
-
-/*******************************************************************************
- * Time conversion functions
- ******************************************************************************/
-
-static PHYSFS_sint64 iso_mktime(ISO9660FileTimestamp *timestamp)
-{
- struct tm tm;
- tm.tm_year = timestamp->year;
- tm.tm_mon = timestamp->month - 1;
- tm.tm_mday = timestamp->day;
- tm.tm_hour = timestamp->hour;
- tm.tm_min = timestamp->minute;
- tm.tm_sec = timestamp->second;
- /* Ignore GMT offset for now... */
- return mktime(&tm);
-} /* iso_mktime */
-
-static int iso_atoi2(char *text)
-{
- return ((text[0] - 40) * 10) + (text[1] - 40);
-} /* iso_atoi2 */
-
-static int iso_atoi4(char *text)
-{
- return ((text[0] - 40) * 1000) + ((text[1] - 40) * 100) +
- ((text[2] - 40) * 10) + (text[3] - 40);
-} /* iso_atoi4 */
-
-static PHYSFS_sint64 iso_volume_mktime(ISO9660VolumeTimestamp *timestamp)
-{
- struct tm tm;
- tm.tm_year = iso_atoi4(timestamp->year);
- tm.tm_mon = iso_atoi2(timestamp->month) - 1;
- tm.tm_mday = iso_atoi2(timestamp->day);
- tm.tm_hour = iso_atoi2(timestamp->hour);
- tm.tm_min = iso_atoi2(timestamp->minute);
- tm.tm_sec = iso_atoi2(timestamp->second);
- /* this allows values outside the range of a unix timestamp... sanitize them */
- PHYSFS_sint64 value = mktime(&tm);
- return value == -1 ? 0 : value;
-} /* iso_volume_mktime */
-
-/*******************************************************************************
- * Filename extraction
- ******************************************************************************/
-
-static int iso_extractfilenameISO(ISO9660FileDescriptor *descriptor,
- char *filename, int *version)
-{
- *filename = '\0';
- if (descriptor->flags.directory)
- {
- strncpy(filename, descriptor->filename, descriptor->filenamelen);
- filename[descriptor->filenamelen] = '\0';
- *version = 0;
- } /* if */
- else
- {
- /* find last SEPARATOR2 */
- int pos = 0;
- int lastfound = -1;
- for(;pos < descriptor->filenamelen; pos++)
- if (descriptor->filename[pos] == ';')
- lastfound = pos;
- BAIL_IF_MACRO(lastfound < 1, PHYSFS_ERR_NO_SUCH_PATH /* !!! FIXME: PHYSFS_ERR_BAD_FILENAME */, -1);
- BAIL_IF_MACRO(lastfound == (descriptor->filenamelen -1), PHYSFS_ERR_NO_SUCH_PATH /* !!! PHYSFS_ERR_BAD_FILENAME */, -1);
- strncpy(filename, descriptor->filename, lastfound);
- if (filename[lastfound - 1] == '.')
- filename[lastfound - 1] = '\0'; /* consume trailing ., as done in all implementations */
- else
- filename[lastfound] = '\0';
- *version = atoi(descriptor->filename + lastfound);
- } /* else */
-
- return 0;
-} /* iso_extractfilenameISO */
-
-
-static int iso_extractfilenameUCS2(ISO9660FileDescriptor *descriptor,
- char *filename, int *version)
-{
- PHYSFS_uint16 tmp[128];
- PHYSFS_uint16 *src;
- int len;
-
- *filename = '\0';
- *version = 1; /* Joliet does not have versions.. at least not on my images */
-
- src = (PHYSFS_uint16*) descriptor->filename;
- len = descriptor->filenamelen / 2;
- tmp[len] = 0;
-
- while(len--)
- tmp[len] = PHYSFS_swapUBE16(src[len]);
-
- PHYSFS_utf8FromUcs2(tmp, filename, 255);
-
- return 0;
-} /* iso_extractfilenameUCS2 */
-
-
-static int iso_extractfilename(ISO9660Handle *handle,
- ISO9660FileDescriptor *descriptor, char *filename,int *version)
-{
- if (handle->isjoliet)
- return iso_extractfilenameUCS2(descriptor, filename, version);
- else
- return iso_extractfilenameISO(descriptor, filename, version);
-} /* iso_extractfilename */
-
-/*******************************************************************************
- * Basic image read functions
- ******************************************************************************/
-
-static int iso_readimage(ISO9660Handle *handle, PHYSFS_uint64 where,
- void *buffer, PHYSFS_uint64 len)
-{
- BAIL_IF_MACRO(!__PHYSFS_platformGrabMutex(handle->mutex), ERRPASS, -1);
- int rc = -1;
- if (where != handle->currpos)
- GOTO_IF_MACRO(!handle->io->seek(handle->io,where), ERRPASS, unlockme);
- rc = handle->io->read(handle->io, buffer, len);
- if (rc == -1)
- {
- handle->currpos = (PHYSFS_uint64) -1;
- goto unlockme;
- } /* if */
- handle->currpos += rc;
-
- unlockme:
- __PHYSFS_platformReleaseMutex(handle->mutex);
- return rc;
-} /* iso_readimage */
-
-
-static PHYSFS_sint64 iso_readfiledescriptor(ISO9660Handle *handle,
- PHYSFS_uint64 where,
- ISO9660FileDescriptor *descriptor)
-{
- PHYSFS_sint64 rc = iso_readimage(handle, where, descriptor,
- sizeof (descriptor->recordlen));
- BAIL_IF_MACRO(rc == -1, ERRPASS, -1);
- BAIL_IF_MACRO(rc != 1, PHYSFS_ERR_CORRUPT, -1);
-
- if (descriptor->recordlen == 0)
- return 0; /* fill bytes at the end of a sector */
-
- rc = iso_readimage(handle, where + 1, &descriptor->extattributelen,
- descriptor->recordlen - sizeof(descriptor->recordlen));
- BAIL_IF_MACRO(rc == -1, ERRPASS, -1);
- BAIL_IF_MACRO(rc != 1, PHYSFS_ERR_CORRUPT, -1);
-
- return 0;
-} /* iso_readfiledescriptor */
-
-static void iso_extractsubpath(char *path, char **subpath)
-{
- *subpath = strchr(path,'/');
- if (*subpath != 0)
- {
- **subpath = 0;
- *subpath +=1;
- } /* if */
-} /* iso_extractsubpath */
-
-/*
- * Don't use path tables, they are not necessarily faster, but more complicated
- * to implement as they store only directories and not files, so searching for
- * a file needs to branch to the directory extent sooner or later.
- */
-static int iso_find_dir_entry(ISO9660Handle *handle,const char *path,
- ISO9660FileDescriptor *descriptor, int *exists)
-{
- char *subpath = 0;
- PHYSFS_uint64 readpos, end_of_dir;
- char filename[255];
- char pathcopy[256];
- char *mypath;
- int version = 0;
-
- strcpy(pathcopy, path);
- mypath = pathcopy;
- *exists = 0;
-
- readpos = handle->rootdirstart;
- end_of_dir = handle->rootdirstart + handle->rootdirsize;
- iso_extractsubpath(mypath, &subpath);
- while (1)
- {
- BAIL_IF_MACRO(iso_readfiledescriptor(handle, readpos, descriptor), ERRPASS, -1);
-
- /* recordlen = 0 -> no more entries or fill entry */
- if (!descriptor->recordlen)
- {
- /* if we are in the last sector of the directory & it's 0 -> end */
- if ((end_of_dir - 2048) <= (readpos -1))
- break; /* finished */
-
- /* else skip to the next sector & continue; */
- readpos = (((readpos - 1) / 2048) + 1) * 2048;
- continue;
- } /* if */
-
- readpos += descriptor->recordlen;
- if (descriptor->filenamelen == 1 && (descriptor->filename[0] == 0
- || descriptor->filename[0] == 1))
- continue; /* special ones, ignore */
-
- BAIL_IF_MACRO(
- iso_extractfilename(handle, descriptor, filename, &version),
- ERRPASS, -1);
-
- if (strcmp(filename, mypath) == 0)
- {
- if ( (subpath == 0) || (subpath[0] == 0) )
- {
- *exists = 1;
- return 0; /* no subpaths left and we found the entry */
- } /* if */
-
- if (descriptor->flags.directory)
- {
- /* shorten the path to the subpath */
- mypath = subpath;
- iso_extractsubpath(mypath, &subpath);
- /* gosub to the new directory extent */
- readpos = descriptor->extentpos * 2048;
- end_of_dir = readpos + descriptor->datalen;
- } /* if */
- else
- {
- /* we're at a file but have a remaining subpath -> no match */
- return 0;
- } /* else */
- } /* if */
- } /* while */
-
- return 0;
-} /* iso_find_dir_entry */
-
-
-static int iso_read_ext_attributes(ISO9660Handle *handle, int block,
- ISO9660ExtAttributeRec *attributes)
-{
- return iso_readimage(handle, block * 2048, attributes,
- sizeof(ISO9660ExtAttributeRec));
-} /* iso_read_ext_attributes */
-
-
-static int ISO9660_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
-
-static PHYSFS_Io *ISO9660_duplicate(PHYSFS_Io *_io)
-{
- BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL); /* !!! FIXME: write me. */
-} /* ISO9660_duplicate */
-
-
-static void ISO9660_destroy(PHYSFS_Io *io)
-{
- ISO9660FileHandle *fhandle = (ISO9660FileHandle*) io->opaque;
- fhandle->close(fhandle);
- allocator.Free(io);
-} /* ISO9660_destroy */
-
-
-static PHYSFS_sint64 ISO9660_read(PHYSFS_Io *io, void *buf, PHYSFS_uint64 len)
-{
- ISO9660FileHandle *fhandle = (ISO9660FileHandle*) io->opaque;
- return fhandle->read(fhandle, buf, len);
-} /* ISO9660_read */
-
-
-static PHYSFS_sint64 ISO9660_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 l)
-{
- BAIL_MACRO(PHYSFS_ERR_READ_ONLY, -1);
-} /* ISO9660_write */
-
-
-static PHYSFS_sint64 ISO9660_tell(PHYSFS_Io *io)
-{
- return ((ISO9660FileHandle*) io->opaque)->currpos;
-} /* ISO9660_tell */
-
-
-static int ISO9660_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
-{
- ISO9660FileHandle *fhandle = (ISO9660FileHandle*) io->opaque;
- return fhandle->seek(fhandle, offset);
-} /* ISO9660_seek */
-
-
-static PHYSFS_sint64 ISO9660_length(PHYSFS_Io *io)
-{
- return ((ISO9660FileHandle*) io->opaque)->filesize;
-} /* ISO9660_length */
-
-
-static const PHYSFS_Io ISO9660_Io =
-{
- CURRENT_PHYSFS_IO_API_VERSION, NULL,
- ISO9660_read,
- ISO9660_write,
- ISO9660_seek,
- ISO9660_tell,
- ISO9660_length,
- ISO9660_duplicate,
- ISO9660_flush,
- ISO9660_destroy
-};
-
-
-/*******************************************************************************
- * Archive management functions
- ******************************************************************************/
-
-static void *ISO9660_openArchive(PHYSFS_Io *io, const char *filename, int forWriting)
-{
- char magicnumber[6];
- ISO9660Handle *handle;
- int founddescriptor = 0;
- int foundjoliet = 0;
-
- assert(io != NULL); /* shouldn't ever happen. */
-
- BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
-
- /* Skip system area to magic number in Volume descriptor */
- BAIL_IF_MACRO(!io->seek(io, 32769), ERRPASS, NULL);
- BAIL_IF_MACRO(!io->read(io, magicnumber, 5) != 5, ERRPASS, NULL);
- if (memcmp(magicnumber, "CD001", 6) != 0)
- BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL);
-
- handle = allocator.Malloc(sizeof(ISO9660Handle));
- GOTO_IF_MACRO(!handle, PHYSFS_ERR_OUT_OF_MEMORY, errorcleanup);
- handle->path = 0;
- handle->mutex= 0;
- handle->io = NULL;
-
- handle->path = allocator.Malloc(strlen(filename) + 1);
- GOTO_IF_MACRO(!handle->path, PHYSFS_ERR_OUT_OF_MEMORY, errorcleanup);
- strcpy(handle->path, filename);
-
- handle->mutex = __PHYSFS_platformCreateMutex();
- GOTO_IF_MACRO(!handle->mutex, ERRPASS, errorcleanup);
-
- handle->io = io;
-
- /* seek Primary Volume Descriptor */
- GOTO_IF_MACRO(!io->seek(io, 32768), PHYSFS_ERR_IO, errorcleanup);
-
- while (1)
- {
- ISO9660VolumeDescriptor descriptor;
- GOTO_IF_MACRO(io->read(io, &descriptor, sizeof(ISO9660VolumeDescriptor)) != sizeof(ISO9660VolumeDescriptor), PHYSFS_ERR_IO, errorcleanup);
- GOTO_IF_MACRO(strncmp(descriptor.identifier, "CD001", 5) != 0, PHYSFS_ERR_UNSUPPORTED, errorcleanup);
-
- if (descriptor.type == 255)
- {
- /* type 255 terminates the volume descriptor list */
- if (founddescriptor)
- return handle; /* ok, we've found one volume descriptor */
- else
- GOTO_MACRO(PHYSFS_ERR_CORRUPT, errorcleanup);
- } /* if */
- if (descriptor.type == 1 && !founddescriptor)
- {
- handle->currpos = io->tell(io);
- handle->rootdirstart =
- descriptor.rootdirectory.extent_location * 2048;
- handle->rootdirsize =
- descriptor.rootdirectory.data_length;
- handle->isjoliet = 0;
- founddescriptor = 1; /* continue search for joliet */
- } /* if */
- if (descriptor.type == 2 && !foundjoliet)
- {
- /* check if is joliet */
- PHYSFS_uint8 *s = descriptor.escape_sequences;
- int joliet = !(descriptor.flags & 1)
- && (s[0] == 0x25)
- && (s[1] == 0x2F)
- && ((s[2] == 0x40) || (s[2] == 0x43) || (s[2] == 0x45));
- if (!joliet)
- continue;
-
- handle->currpos = io->tell(io);
- handle->rootdirstart =
- descriptor.rootdirectory.extent_location * 2048;
- handle->rootdirsize =
- descriptor.rootdirectory.data_length;
- handle->isjoliet = 1;
- founddescriptor = 1;
- foundjoliet = 1;
- } /* if */
- } /* while */
-
- GOTO_MACRO(PHYSFS_ERR_CORRUPT, errorcleanup); /* not found. */
-
-errorcleanup:
- if (handle)
- {
- if (handle->path)
- allocator.Free(handle->path);
- if (handle->mutex)
- __PHYSFS_platformDestroyMutex(handle->mutex);
- allocator.Free(handle);
- } /* if */
- return NULL;
-} /* ISO9660_openArchive */
-
-
-static void ISO9660_closeArchive(PHYSFS_Dir *opaque)
-{
- ISO9660Handle *handle = (ISO9660Handle*) opaque;
- handle->io->destroy(handle->io);
- __PHYSFS_platformDestroyMutex(handle->mutex);
- allocator.Free(handle->path);
- allocator.Free(handle);
-} /* ISO9660_closeArchive */
-
-
-/*******************************************************************************
- * Read functions
- ******************************************************************************/
-
-
-static PHYSFS_uint32 iso_file_read_mem(ISO9660FileHandle *filehandle,
- void *buffer, PHYSFS_uint64 len)
-{
- /* check remaining bytes & max obj which can be fetched */
- const PHYSFS_sint64 bytesleft = filehandle->filesize - filehandle->currpos;
- if (bytesleft < len)
- len = bytesleft;
-
- if (len == 0)
- return 0;
-
- memcpy(buffer, filehandle->cacheddata + filehandle->currpos, (size_t) len);
-
- filehandle->currpos += len;
- return (PHYSFS_uint32) len;
-} /* iso_file_read_mem */
-
-
-static int iso_file_seek_mem(ISO9660FileHandle *fhandle, PHYSFS_sint64 offset)
-{
- BAIL_IF_MACRO(offset < 0, PHYSFS_ERR_INVALID_ARGUMENT, 0);
- BAIL_IF_MACRO(offset >= fhandle->filesize, PHYSFS_ERR_PAST_EOF, 0);
-
- fhandle->currpos = offset;
- return 0;
-} /* iso_file_seek_mem */
-
-
-static void iso_file_close_mem(ISO9660FileHandle *fhandle)
-{
- allocator.Free(fhandle->cacheddata);
- allocator.Free(fhandle);
-} /* iso_file_close_mem */
-
-
-static PHYSFS_uint32 iso_file_read_foreign(ISO9660FileHandle *filehandle,
- void *buffer, PHYSFS_uint64 len)
-{
- /* check remaining bytes & max obj which can be fetched */
- const PHYSFS_sint64 bytesleft = filehandle->filesize - filehandle->currpos;
- if (bytesleft < len)
- len = bytesleft;
-
- const PHYSFS_sint64 rc = filehandle->io->read(filehandle->io, buffer, len);
- BAIL_IF_MACRO(rc == -1, ERRPASS, -1);
-
- filehandle->currpos += rc; /* i trust my internal book keeping */
- BAIL_IF_MACRO(rc < len, PHYSFS_ERR_CORRUPT, -1);
- return rc;
-} /* iso_file_read_foreign */
-
-
-static int iso_file_seek_foreign(ISO9660FileHandle *fhandle,
- PHYSFS_sint64 offset)
-{
- BAIL_IF_MACRO(offset < 0, PHYSFS_ERR_INVALID_ARGUMENT, 0);
- BAIL_IF_MACRO(offset >= fhandle->filesize, PHYSFS_ERR_PAST_EOF, 0);
-
- PHYSFS_sint64 pos = fhandle->startblock * 2048 + offset;
- BAIL_IF_MACRO(!fhandle->io->seek(fhandle->io, pos), ERRPASS, -1);
-
- fhandle->currpos = offset;
- return 0;
-} /* iso_file_seek_foreign */
-
-
-static void iso_file_close_foreign(ISO9660FileHandle *fhandle)
-{
- fhandle->io->destroy(fhandle->io);
- allocator.Free(fhandle);
-} /* iso_file_close_foreign */
-
-
-static int iso_file_open_mem(ISO9660Handle *handle, ISO9660FileHandle *fhandle)
-{
- fhandle->cacheddata = allocator.Malloc(fhandle->filesize);
- BAIL_IF_MACRO(!fhandle->cacheddata, PHYSFS_ERR_OUT_OF_MEMORY, -1);
- int rc = iso_readimage(handle, fhandle->startblock * 2048,
- fhandle->cacheddata, fhandle->filesize);
- GOTO_IF_MACRO(rc < 0, ERRPASS, freemem);
- GOTO_IF_MACRO(rc == 0, PHYSFS_ERR_CORRUPT, freemem);
-
- fhandle->read = iso_file_read_mem;
- fhandle->seek = iso_file_seek_mem;
- fhandle->close = iso_file_close_mem;
- return 0;
-
-freemem:
- allocator.Free(fhandle->cacheddata);
- return -1;
-} /* iso_file_open_mem */
-
-
-static int iso_file_open_foreign(ISO9660Handle *handle,
- ISO9660FileHandle *fhandle)
-{
- int rc;
- fhandle->io = __PHYSFS_createNativeIo(handle->path, 'r');
- BAIL_IF_MACRO(!fhandle->io, ERRPASS, -1);
- rc = fhandle->io->seek(fhandle->io, fhandle->startblock * 2048);
- GOTO_IF_MACRO(!rc, ERRPASS, closefile);
-
- fhandle->read = iso_file_read_foreign;
- fhandle->seek = iso_file_seek_foreign;
- fhandle->close = iso_file_close_foreign;
- return 0;
-
-closefile:
- fhandle->io->destroy(fhandle->io);
- return -1;
-} /* iso_file_open_foreign */
-
-
-static PHYSFS_Io *ISO9660_openRead(PHYSFS_Dir *opaque, const char *filename,
- int *exists)
-{
- PHYSFS_Io *retval = NULL;
- ISO9660Handle *handle = (ISO9660Handle*) opaque;
- ISO9660FileHandle *fhandle;
- ISO9660FileDescriptor descriptor;
- int rc;
-
- fhandle = allocator.Malloc(sizeof(ISO9660FileHandle));
- BAIL_IF_MACRO(fhandle == 0, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
- fhandle->cacheddata = 0;
-
- retval = allocator.Malloc(sizeof(PHYSFS_Io));
- GOTO_IF_MACRO(retval == 0, PHYSFS_ERR_OUT_OF_MEMORY, errorhandling);
-
- /* find file descriptor */
- rc = iso_find_dir_entry(handle, filename, &descriptor, exists);
- GOTO_IF_MACRO(rc, ERRPASS, errorhandling);
- GOTO_IF_MACRO(!*exists, PHYSFS_ERR_NO_SUCH_PATH, errorhandling);
-
- fhandle->startblock = descriptor.extentpos + descriptor.extattributelen;
- fhandle->filesize = descriptor.datalen;
- fhandle->currpos = 0;
- fhandle->isohandle = handle;
- fhandle->cacheddata = NULL;
- fhandle->io = NULL;
-
- if (descriptor.datalen <= ISO9660_FULLCACHEMAXSIZE)
- rc = iso_file_open_mem(handle, fhandle);
- else
- rc = iso_file_open_foreign(handle, fhandle);
- GOTO_IF_MACRO(rc, ERRPASS, errorhandling);
-
- memcpy(retval, &ISO9660_Io, sizeof (PHYSFS_Io));
- retval->opaque = fhandle;
- return retval;
-
-errorhandling:
- if (retval) allocator.Free(retval);
- if (fhandle) allocator.Free(fhandle);
- return NULL;
-} /* ISO9660_openRead */
-
-
-
-/*******************************************************************************
- * Information gathering functions
- ******************************************************************************/
-
-static void ISO9660_enumerateFiles(PHYSFS_Dir *opaque, const char *dname,
- int omitSymLinks,
- PHYSFS_EnumFilesCallback cb,
- const char *origdir, void *callbackdata)
-{
- ISO9660Handle *handle = (ISO9660Handle*) opaque;
- ISO9660FileDescriptor descriptor;
- PHYSFS_uint64 readpos;
- PHYSFS_uint64 end_of_dir;
- char filename[130]; /* ISO allows 31, Joliet 128 -> 128 + 2 eol bytes */
- int version = 0;
-
- if (*dname == '\0')
- {
- readpos = handle->rootdirstart;
- end_of_dir = readpos + handle->rootdirsize;
- } /* if */
- else
- {
- printf("pfad %s\n",dname);
- int exists = 0;
- BAIL_IF_MACRO(iso_find_dir_entry(handle,dname, &descriptor, &exists), ERRPASS,);
- BAIL_IF_MACRO(!exists, ERRPASS, );
- BAIL_IF_MACRO(!descriptor.flags.directory, ERRPASS,);
-
- readpos = descriptor.extentpos * 2048;
- end_of_dir = readpos + descriptor.datalen;
- } /* else */
-
- while (1)
- {
- BAIL_IF_MACRO(iso_readfiledescriptor(handle, readpos, &descriptor), ERRPASS, );
-
- /* recordlen = 0 -> no more entries or fill entry */
- if (!descriptor.recordlen)
- {
- /* if we are in the last sector of the directory & it's 0 -> end */
- if ((end_of_dir - 2048) <= (readpos -1))
- break; /* finished */
-
- /* else skip to the next sector & continue; */
- readpos = (((readpos - 1) / 2048) + 1) * 2048;
- continue;
- } /* if */
-
- readpos += descriptor.recordlen;
- if (descriptor.filenamelen == 1 && (descriptor.filename[0] == 0
- || descriptor.filename[0] == 1))
- continue; /* special ones, ignore */
-
- strncpy(filename,descriptor.filename,descriptor.filenamelen);
- iso_extractfilename(handle, &descriptor, filename, &version);
- cb(callbackdata, origdir,filename);
- } /* while */
-} /* ISO9660_enumerateFiles */
-
-
-static int ISO9660_stat(PHYSFS_Dir *opaque, const char *name, int *exists,
- PHYSFS_Stat *stat)
-{
- ISO9660Handle *handle = (ISO9660Handle*) opaque;
- ISO9660FileDescriptor descriptor;
- ISO9660ExtAttributeRec extattr;
- BAIL_IF_MACRO(iso_find_dir_entry(handle, name, &descriptor, exists), ERRPASS, -1);
- if (!*exists)
- return 0;
-
- stat->readonly = 1;
-
- /* try to get extended info */
- if (descriptor.extattributelen)
- {
- BAIL_IF_MACRO(iso_read_ext_attributes(handle,
- descriptor.extentpos, &extattr), ERRPASS, -1);
- stat->createtime = iso_volume_mktime(&extattr.create_time);
- stat->modtime = iso_volume_mktime(&extattr.mod_time);
- stat->accesstime = iso_volume_mktime(&extattr.mod_time);
- } /* if */
- else
- {
- stat->createtime = iso_mktime(&descriptor.recordtime);
- stat->modtime = iso_mktime(&descriptor.recordtime);
- stat->accesstime = iso_mktime(&descriptor.recordtime);
- } /* else */
-
- if (descriptor.flags.directory)
- {
- stat->filesize = 0;
- stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
- } /* if */
- else
- {
- stat->filesize = descriptor.datalen;
- stat->filetype = PHYSFS_FILETYPE_REGULAR;
- } /* else */
-
- return 1;
-} /* ISO9660_stat */
-
-
-/*******************************************************************************
- * Not supported functions
- ******************************************************************************/
-
-static PHYSFS_Io *ISO9660_openWrite(PHYSFS_Dir *opaque, const char *name)
-{
- BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
-} /* ISO9660_openWrite */
-
-
-static PHYSFS_Io *ISO9660_openAppend(PHYSFS_Dir *opaque, const char *name)
-{
- BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
-} /* ISO9660_openAppend */
-
-
-static int ISO9660_remove(PHYSFS_Dir *opaque, const char *name)
-{
- BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
-} /* ISO9660_remove */
-
-
-static int ISO9660_mkdir(PHYSFS_Dir *opaque, const char *name)
-{
- BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
-} /* ISO9660_mkdir */
-
-
-const PHYSFS_Archiver __PHYSFS_Archiver_ISO9660 =
-{
- {
- "ISO",
- "ISO9660 image file",
- "Christoph Nelles ",
- "http://www.evilazrael.de/",
- },
- ISO9660_openArchive, /* openArchive() method */
- ISO9660_enumerateFiles, /* enumerateFiles() method */
- ISO9660_openRead, /* openRead() method */
- ISO9660_openWrite, /* openWrite() method */
- ISO9660_openAppend, /* openAppend() method */
- ISO9660_remove, /* remove() method */
- ISO9660_mkdir, /* mkdir() method */
- ISO9660_closeArchive, /* closeArchive() method */
- ISO9660_stat /* stat() method */
-};
-
-#endif /* defined PHYSFS_SUPPORTS_ISO9660 */
-
-/* end of archiver_iso9660.c ... */
-
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/src/archiver_lzma.c
--- a/misc/physfs/src/archiver_lzma.c Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,701 +0,0 @@
-/*
- * LZMA support routines for PhysicsFS.
- *
- * Please see the file lzma.txt in the lzma/ directory.
- *
- * This file was written by Dennis Schridde, with some peeking at "7zMain.c"
- * by Igor Pavlov.
- */
-
-#define __PHYSICSFS_INTERNAL__
-#include "physfs_internal.h"
-
-#if PHYSFS_SUPPORTS_7Z
-
-#include "lzma/C/7zCrc.h"
-#include "lzma/C/Archive/7z/7zIn.h"
-#include "lzma/C/Archive/7z/7zExtract.h"
-
-
-/* 7z internal from 7zIn.c */
-extern int TestSignatureCandidate(Byte *testBytes);
-
-
-#ifdef _LZMA_IN_CB
-# define BUFFER_SIZE (1 << 12)
-#endif /* _LZMA_IN_CB */
-
-
-/*
- * Carries filestream metadata through 7z
- */
-typedef struct _FileInputStream
-{
- ISzAlloc allocImp; /* Allocation implementation, used by 7z */
- ISzAlloc allocTempImp; /* Temporary allocation implementation, used by 7z */
- ISzInStream inStream; /* Input stream with read callbacks, used by 7z */
- PHYSFS_Io *io; /* Filehandle, used by read implementation */
-#ifdef _LZMA_IN_CB
- Byte buffer[BUFFER_SIZE]; /* Buffer, used by read implementation */
-#endif /* _LZMA_IN_CB */
-} FileInputStream;
-
-/*
- * In the 7z format archives are splited into blocks, those are called folders
- * Set by LZMA_read()
-*/
-typedef struct _LZMAfolder
-{
- PHYSFS_uint32 index; /* Index of folder in archive */
- PHYSFS_uint32 references; /* Number of files using this block */
- PHYSFS_uint8 *cache; /* Cached folder */
- size_t size; /* Size of folder */
-} LZMAfolder;
-
-/*
- * Set by LZMA_openArchive(), except folder which gets it's values
- * in LZMA_read()
- */
-typedef struct _LZMAarchive
-{
- struct _LZMAfile *files; /* Array of files, size == archive->db.Database.NumFiles */
- LZMAfolder *folders; /* Array of folders, size == archive->db.Database.NumFolders */
- CArchiveDatabaseEx db; /* For 7z: Database */
- FileInputStream stream; /* For 7z: Input file incl. read and seek callbacks */
-} LZMAarchive;
-
-/* Set by LZMA_openArchive(), except offset which is set by LZMA_read() */
-typedef struct _LZMAfile
-{
- PHYSFS_uint32 index; /* Index of file in archive */
- LZMAarchive *archive; /* Link to corresponding archive */
- LZMAfolder *folder; /* Link to corresponding folder */
- CFileItem *item; /* For 7z: File info, eg. name, size */
- size_t offset; /* Offset in folder */
- size_t position; /* Current "virtual" position in file */
-} LZMAfile;
-
-
-/* Memory management implementations to be passed to 7z */
-
-static void *SzAllocPhysicsFS(size_t size)
-{
- return ((size == 0) ? NULL : allocator.Malloc(size));
-} /* SzAllocPhysicsFS */
-
-
-static void SzFreePhysicsFS(void *address)
-{
- if (address != NULL)
- allocator.Free(address);
-} /* SzFreePhysicsFS */
-
-
-/* Filesystem implementations to be passed to 7z */
-
-#ifdef _LZMA_IN_CB
-
-/*
- * Read implementation, to be passed to 7z
- * WARNING: If the ISzInStream in 'object' is not contained in a valid FileInputStream this _will_ break horribly!
- */
-SZ_RESULT SzFileReadImp(void *object, void **buffer, size_t maxReqSize,
- size_t *processedSize)
-{
- FileInputStream *s = (FileInputStream *)(object - offsetof(FileInputStream, inStream)); /* HACK! */
- PHYSFS_sint64 processedSizeLoc = 0;
-
- if (maxReqSize > BUFFER_SIZE)
- maxReqSize = BUFFER_SIZE;
- processedSizeLoc = s->io->read(s->io, s->buffer, maxReqSize);
- *buffer = s->buffer;
- if (processedSize != NULL)
- *processedSize = (size_t) processedSizeLoc;
-
- return SZ_OK;
-} /* SzFileReadImp */
-
-#else
-
-/*
- * Read implementation, to be passed to 7z
- * WARNING: If the ISzInStream in 'object' is not contained in a valid FileInputStream this _will_ break horribly!
- */
-SZ_RESULT SzFileReadImp(void *object, void *buffer, size_t size,
- size_t *processedSize)
-{
- FileInputStream *s = (FileInputStream *)((unsigned long)object - offsetof(FileInputStream, inStream)); /* HACK! */
- const size_t processedSizeLoc = s->io->read(s->io, buffer, size);
- if (processedSize != NULL)
- *processedSize = processedSizeLoc;
- return SZ_OK;
-} /* SzFileReadImp */
-
-#endif
-
-/*
- * Seek implementation, to be passed to 7z
- * WARNING: If the ISzInStream in 'object' is not contained in a valid FileInputStream this _will_ break horribly!
- */
-SZ_RESULT SzFileSeekImp(void *object, CFileSize pos)
-{
- FileInputStream *s = (FileInputStream *)((unsigned long)object - offsetof(FileInputStream, inStream)); /* HACK! */
- if (s->io->seek(s->io, (PHYSFS_uint64) pos))
- return SZ_OK;
- return SZE_FAIL;
-} /* SzFileSeekImp */
-
-
-/*
- * Translate Microsoft FILETIME (used by 7zip) into UNIX timestamp
- */
-static PHYSFS_sint64 lzma_filetime_to_unix_timestamp(CArchiveFileTime *ft)
-{
- /* MS counts in nanoseconds ... */
- const PHYSFS_uint64 FILETIME_NANOTICKS_PER_SECOND = __PHYSFS_UI64(10000000);
- /* MS likes to count seconds since 01.01.1601 ... */
- const PHYSFS_uint64 FILETIME_UNIX_DIFF = __PHYSFS_UI64(11644473600);
-
- PHYSFS_uint64 filetime = ft->Low | ((PHYSFS_uint64)ft->High << 32);
- return filetime/FILETIME_NANOTICKS_PER_SECOND - FILETIME_UNIX_DIFF;
-} /* lzma_filetime_to_unix_timestamp */
-
-
-/*
- * Compare a file with a given name, C89 stdlib variant
- * Used for sorting
- */
-static int lzma_file_cmp_stdlib(const void *key, const void *object)
-{
- const char *name = (const char *) key;
- LZMAfile *file = (LZMAfile *) object;
- return strcmp(name, file->item->Name);
-} /* lzma_file_cmp_posix */
-
-
-/*
- * Compare two files with each other based on the name
- * Used for sorting
- */
-static int lzma_file_cmp(void *_a, size_t one, size_t two)
-{
- LZMAfile *files = (LZMAfile *) _a;
- return strcmp(files[one].item->Name, files[two].item->Name);
-} /* lzma_file_cmp */
-
-
-/*
- * Swap two entries in the file array
- */
-static void lzma_file_swap(void *_a, size_t one, size_t two)
-{
- LZMAfile tmp;
- LZMAfile *first = &(((LZMAfile *) _a)[one]);
- LZMAfile *second = &(((LZMAfile *) _a)[two]);
- memcpy(&tmp, first, sizeof (LZMAfile));
- memcpy(first, second, sizeof (LZMAfile));
- memcpy(second, &tmp, sizeof (LZMAfile));
-} /* lzma_file_swap */
-
-
-/*
- * Find entry 'name' in 'archive'
- */
-static LZMAfile * lzma_find_file(const LZMAarchive *archive, const char *name)
-{
- LZMAfile *file = bsearch(name, archive->files, archive->db.Database.NumFiles, sizeof(*archive->files), lzma_file_cmp_stdlib); /* FIXME: Should become __PHYSFS_search!!! */
-
- BAIL_IF_MACRO(file == NULL, PHYSFS_ERR_NO_SUCH_PATH, NULL);
-
- return file;
-} /* lzma_find_file */
-
-
-/*
- * Load metadata for the file at given index
- */
-static int lzma_file_init(LZMAarchive *archive, PHYSFS_uint32 fileIndex)
-{
- LZMAfile *file = &archive->files[fileIndex];
- PHYSFS_uint32 folderIndex = archive->db.FileIndexToFolderIndexMap[fileIndex];
-
- file->index = fileIndex; /* Store index into 7z array, since we sort our own. */
- file->archive = archive;
- file->folder = (folderIndex != (PHYSFS_uint32)-1 ? &archive->folders[folderIndex] : NULL); /* Directories don't have a folder (they contain no own data...) */
- file->item = &archive->db.Database.Files[fileIndex]; /* Holds crucial data and is often referenced -> Store link */
- file->position = 0;
- file->offset = 0; /* Offset will be set by LZMA_read() */
-
- return 1;
-} /* lzma_load_file */
-
-
-/*
- * Load metadata for all files
- */
-static int lzma_files_init(LZMAarchive *archive)
-{
- PHYSFS_uint32 fileIndex = 0, numFiles = archive->db.Database.NumFiles;
-
- for (fileIndex = 0; fileIndex < numFiles; fileIndex++ )
- {
- if (!lzma_file_init(archive, fileIndex))
- {
- return 0; /* FALSE on failure */
- }
- } /* for */
-
- __PHYSFS_sort(archive->files, (size_t) numFiles, lzma_file_cmp, lzma_file_swap);
-
- return 1;
-} /* lzma_load_files */
-
-
-/*
- * Initialise specified archive
- */
-static void lzma_archive_init(LZMAarchive *archive)
-{
- memset(archive, 0, sizeof(*archive));
-
- /* Prepare callbacks for 7z */
- archive->stream.inStream.Read = SzFileReadImp;
- archive->stream.inStream.Seek = SzFileSeekImp;
-
- archive->stream.allocImp.Alloc = SzAllocPhysicsFS;
- archive->stream.allocImp.Free = SzFreePhysicsFS;
-
- archive->stream.allocTempImp.Alloc = SzAllocPhysicsFS;
- archive->stream.allocTempImp.Free = SzFreePhysicsFS;
-}
-
-
-/*
- * Deinitialise archive
- */
-static void lzma_archive_exit(LZMAarchive *archive)
-{
- /* Free arrays */
- allocator.Free(archive->folders);
- allocator.Free(archive->files);
- allocator.Free(archive);
-}
-
-/*
- * Wrap all 7z calls in this, so the physfs error state is set appropriately.
- */
-static int lzma_err(SZ_RESULT rc)
-{
- switch (rc)
- {
- case SZ_OK: /* Same as LZMA_RESULT_OK */
- break;
- case SZE_DATA_ERROR: /* Same as LZMA_RESULT_DATA_ERROR */
- __PHYSFS_setError(PHYSFS_ERR_CORRUPT); /*!!!FIXME: was "PHYSFS_ERR_DATA_ERROR" */
- break;
- case SZE_OUTOFMEMORY:
- __PHYSFS_setError(PHYSFS_ERR_OUT_OF_MEMORY);
- break;
- case SZE_CRC_ERROR:
- __PHYSFS_setError(PHYSFS_ERR_CORRUPT);
- break;
- case SZE_NOTIMPL:
- __PHYSFS_setError(PHYSFS_ERR_UNSUPPORTED);
- break;
- case SZE_FAIL:
- __PHYSFS_setError(PHYSFS_ERR_OTHER_ERROR); /* !!! FIXME: right? */
- break;
- case SZE_ARCHIVE_ERROR:
- __PHYSFS_setError(PHYSFS_ERR_CORRUPT); /* !!! FIXME: right? */
- break;
- default:
- __PHYSFS_setError(PHYSFS_ERR_OTHER_ERROR);
- } /* switch */
-
- return rc;
-} /* lzma_err */
-
-
-static PHYSFS_sint64 LZMA_read(PHYSFS_Io *io, void *outBuf, PHYSFS_uint64 len)
-{
- LZMAfile *file = (LZMAfile *) io->opaque;
-
- size_t wantedSize = (size_t) len;
- const size_t remainingSize = file->item->Size - file->position;
- size_t fileSize = 0;
-
- BAIL_IF_MACRO(wantedSize == 0, ERRPASS, 0); /* quick rejection. */
- BAIL_IF_MACRO(remainingSize == 0, PHYSFS_ERR_PAST_EOF, 0);
-
- if (wantedSize > remainingSize)
- wantedSize = remainingSize;
-
- /* Only decompress the folder if it is not already cached */
- if (file->folder->cache == NULL)
- {
- const int rc = lzma_err(SzExtract(
- &file->archive->stream.inStream, /* compressed data */
- &file->archive->db, /* 7z's database, containing everything */
- file->index, /* Index into database arrays */
- /* Index of cached folder, will be changed by SzExtract */
- &file->folder->index,
- /* Cache for decompressed folder, allocated/freed by SzExtract */
- &file->folder->cache,
- /* Size of cache, will be changed by SzExtract */
- &file->folder->size,
- /* Offset of this file inside the cache, set by SzExtract */
- &file->offset,
- &fileSize, /* Size of this file */
- &file->archive->stream.allocImp,
- &file->archive->stream.allocTempImp));
-
- if (rc != SZ_OK)
- return -1;
- } /* if */
-
- /* Copy wanted bytes over from cache to outBuf */
- memcpy(outBuf, (file->folder->cache + file->offset + file->position),
- wantedSize);
- file->position += wantedSize; /* Increase virtual position */
-
- return wantedSize;
-} /* LZMA_read */
-
-
-static PHYSFS_sint64 LZMA_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
-{
- BAIL_MACRO(PHYSFS_ERR_READ_ONLY, -1);
-} /* LZMA_write */
-
-
-static PHYSFS_sint64 LZMA_tell(PHYSFS_Io *io)
-{
- LZMAfile *file = (LZMAfile *) io->opaque;
- return file->position;
-} /* LZMA_tell */
-
-
-static int LZMA_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
-{
- LZMAfile *file = (LZMAfile *) io->opaque;
-
- BAIL_IF_MACRO(offset > file->item->Size, PHYSFS_ERR_PAST_EOF, 0);
-
- file->position = offset; /* We only use a virtual position... */
-
- return 1;
-} /* LZMA_seek */
-
-
-static PHYSFS_sint64 LZMA_length(PHYSFS_Io *io)
-{
- const LZMAfile *file = (LZMAfile *) io->opaque;
- return (file->item->Size);
-} /* LZMA_length */
-
-
-static PHYSFS_Io *LZMA_duplicate(PHYSFS_Io *_io)
-{
- /* !!! FIXME: this archiver needs to be reworked to allow multiple
- * !!! FIXME: opens before we worry about duplication. */
- BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL);
-} /* LZMA_duplicate */
-
-
-static int LZMA_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
-
-
-static void LZMA_destroy(PHYSFS_Io *io)
-{
- LZMAfile *file = (LZMAfile *) io->opaque;
-
- if (file->folder != NULL)
- {
- /* Only decrease refcount if someone actually requested this file... Prevents from overflows and close-on-open... */
- if (file->folder->references > 0)
- file->folder->references--;
- if (file->folder->references == 0)
- {
- /* Free the cache which might have been allocated by LZMA_read() */
- allocator.Free(file->folder->cache);
- file->folder->cache = NULL;
- }
- /* !!! FIXME: we don't free (file) or (file->folder)?! */
- } /* if */
-} /* LZMA_destroy */
-
-
-static const PHYSFS_Io LZMA_Io =
-{
- CURRENT_PHYSFS_IO_API_VERSION, NULL,
- LZMA_read,
- LZMA_write,
- LZMA_seek,
- LZMA_tell,
- LZMA_length,
- LZMA_duplicate,
- LZMA_flush,
- LZMA_destroy
-};
-
-
-static void *LZMA_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
-{
- PHYSFS_uint8 sig[k7zSignatureSize];
- size_t len = 0;
- LZMAarchive *archive = NULL;
-
- assert(io != NULL); /* shouldn't ever happen. */
-
- BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
-
- if (io->read(io, sig, k7zSignatureSize) != k7zSignatureSize)
- return 0;
- BAIL_IF_MACRO(!TestSignatureCandidate(sig), PHYSFS_ERR_UNSUPPORTED, NULL);
- BAIL_IF_MACRO(!io->seek(io, 0), ERRPASS, NULL);
-
- archive = (LZMAarchive *) allocator.Malloc(sizeof (LZMAarchive));
- BAIL_IF_MACRO(archive == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
-
- lzma_archive_init(archive);
- archive->stream.io = io;
-
- CrcGenerateTable();
- SzArDbExInit(&archive->db);
- if (lzma_err(SzArchiveOpen(&archive->stream.inStream,
- &archive->db,
- &archive->stream.allocImp,
- &archive->stream.allocTempImp)) != SZ_OK)
- {
- SzArDbExFree(&archive->db, SzFreePhysicsFS);
- lzma_archive_exit(archive);
- return NULL; /* Error is set by lzma_err! */
- } /* if */
-
- len = archive->db.Database.NumFiles * sizeof (LZMAfile);
- archive->files = (LZMAfile *) allocator.Malloc(len);
- if (archive->files == NULL)
- {
- SzArDbExFree(&archive->db, SzFreePhysicsFS);
- lzma_archive_exit(archive);
- BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
- }
-
- /*
- * Init with 0 so we know when a folder is already cached
- * Values will be set by LZMA_openRead()
- */
- memset(archive->files, 0, len);
-
- len = archive->db.Database.NumFolders * sizeof (LZMAfolder);
- archive->folders = (LZMAfolder *) allocator.Malloc(len);
- if (archive->folders == NULL)
- {
- SzArDbExFree(&archive->db, SzFreePhysicsFS);
- lzma_archive_exit(archive);
- BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
- }
-
- /*
- * Init with 0 so we know when a folder is already cached
- * Values will be set by LZMA_read()
- */
- memset(archive->folders, 0, len);
-
- if(!lzma_files_init(archive))
- {
- SzArDbExFree(&archive->db, SzFreePhysicsFS);
- lzma_archive_exit(archive);
- BAIL_MACRO(PHYSFS_ERR_OTHER_ERROR, NULL);
- }
-
- return archive;
-} /* LZMA_openArchive */
-
-
-/*
- * Moved to seperate function so we can use alloca then immediately throw
- * away the allocated stack space...
- */
-static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata,
- const char *odir, const char *str, size_t flen)
-{
- char *newstr = __PHYSFS_smallAlloc(flen + 1);
- if (newstr == NULL)
- return;
-
- memcpy(newstr, str, flen);
- newstr[flen] = '\0';
- cb(callbackdata, odir, newstr);
- __PHYSFS_smallFree(newstr);
-} /* doEnumCallback */
-
-
-static void LZMA_enumerateFiles(PHYSFS_Dir *opaque, const char *dname,
- int omitSymLinks, PHYSFS_EnumFilesCallback cb,
- const char *origdir, void *callbackdata)
-{
- size_t dlen = strlen(dname),
- dlen_inc = dlen + ((dlen > 0) ? 1 : 0);
- LZMAarchive *archive = (LZMAarchive *) opaque;
- LZMAfile *file = NULL,
- *lastFile = &archive->files[archive->db.Database.NumFiles];
- if (dlen)
- {
- file = lzma_find_file(archive, dname);
- if (file != NULL) /* if 'file' is NULL it should stay so, otherwise errors will not be handled */
- file += 1;
- }
- else
- {
- file = archive->files;
- }
-
- BAIL_IF_MACRO(file == NULL, PHYSFS_ERR_NO_SUCH_PATH, );
-
- while (file < lastFile)
- {
- const char * fname = file->item->Name;
- const char * dirNameEnd = fname + dlen_inc;
-
- if (strncmp(dname, fname, dlen) != 0) /* Stop after mismatch, archive->files is sorted */
- break;
-
- if (strchr(dirNameEnd, '/')) /* Skip subdirs */
- {
- file++;
- continue;
- }
-
- /* Do the actual callback... */
- doEnumCallback(cb, callbackdata, origdir, dirNameEnd, strlen(dirNameEnd));
-
- file++;
- }
-} /* LZMA_enumerateFiles */
-
-
-static PHYSFS_Io *LZMA_openRead(PHYSFS_Dir *opaque, const char *name,
- int *fileExists)
-{
- LZMAarchive *archive = (LZMAarchive *) opaque;
- LZMAfile *file = lzma_find_file(archive, name);
- PHYSFS_Io *io = NULL;
-
- *fileExists = (file != NULL);
- BAIL_IF_MACRO(file == NULL, PHYSFS_ERR_NO_SUCH_PATH, NULL);
- BAIL_IF_MACRO(file->folder == NULL, PHYSFS_ERR_NOT_A_FILE, NULL);
-
- file->position = 0;
- file->folder->references++; /* Increase refcount for automatic cleanup... */
-
- io = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
- BAIL_IF_MACRO(io == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
- memcpy(io, &LZMA_Io, sizeof (*io));
- io->opaque = file;
-
- return io;
-} /* LZMA_openRead */
-
-
-static PHYSFS_Io *LZMA_openWrite(PHYSFS_Dir *opaque, const char *filename)
-{
- BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
-} /* LZMA_openWrite */
-
-
-static PHYSFS_Io *LZMA_openAppend(PHYSFS_Dir *opaque, const char *filename)
-{
- BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
-} /* LZMA_openAppend */
-
-
-static void LZMA_closeArchive(PHYSFS_Dir *opaque)
-{
- LZMAarchive *archive = (LZMAarchive *) opaque;
-
-#if 0 /* !!! FIXME: you shouldn't have to do this. */
- PHYSFS_uint32 fileIndex = 0, numFiles = archive->db.Database.NumFiles;
- for (fileIndex = 0; fileIndex < numFiles; fileIndex++)
- {
- LZMA_fileClose(&archive->files[fileIndex]);
- } /* for */
-#endif
-
- SzArDbExFree(&archive->db, SzFreePhysicsFS);
- archive->stream.io->destroy(archive->stream.io);
- lzma_archive_exit(archive);
-} /* LZMA_closeArchive */
-
-
-static int LZMA_remove(PHYSFS_Dir *opaque, const char *name)
-{
- BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
-} /* LZMA_remove */
-
-
-static int LZMA_mkdir(PHYSFS_Dir *opaque, const char *name)
-{
- BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
-} /* LZMA_mkdir */
-
-static int LZMA_stat(PHYSFS_Dir *opaque, const char *filename,
- int *exists, PHYSFS_Stat *stat)
-{
- const LZMAarchive *archive = (const LZMAarchive *) opaque;
- const LZMAfile *file = lzma_find_file(archive, filename);
-
- *exists = (file != 0);
- if (!file)
- return 0;
-
- if(file->item->IsDirectory)
- {
- stat->filesize = 0;
- stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
- } /* if */
- else
- {
- stat->filesize = (PHYSFS_sint64) file->item->Size;
- stat->filetype = PHYSFS_FILETYPE_REGULAR;
- } /* else */
-
- /* !!! FIXME: the 0's should be -1's? */
- if (file->item->IsLastWriteTimeDefined)
- stat->modtime = lzma_filetime_to_unix_timestamp(&file->item->LastWriteTime);
- else
- stat->modtime = 0;
-
- /* real create and accesstype are currently not in the lzma SDK */
- stat->createtime = stat->modtime;
- stat->accesstime = 0;
-
- stat->readonly = 1; /* 7zips are always read only */
-
- return 1;
-} /* LZMA_stat */
-
-
-const PHYSFS_Archiver __PHYSFS_Archiver_LZMA =
-{
- {
- "7Z",
- "LZMA (7zip) format",
- "Dennis Schridde ",
- "http://icculus.org/physfs/",
- },
- LZMA_openArchive, /* openArchive() method */
- LZMA_enumerateFiles, /* enumerateFiles() method */
- LZMA_openRead, /* openRead() method */
- LZMA_openWrite, /* openWrite() method */
- LZMA_openAppend, /* openAppend() method */
- LZMA_remove, /* remove() method */
- LZMA_mkdir, /* mkdir() method */
- LZMA_closeArchive, /* closeArchive() method */
- LZMA_stat /* stat() method */
-};
-
-#endif /* defined PHYSFS_SUPPORTS_7Z */
-
-/* end of lzma.c ... */
-
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/src/archiver_mvl.c
--- a/misc/physfs/src/archiver_mvl.c Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/*
- * MVL support routines for PhysicsFS.
- *
- * This driver handles Descent II Movielib archives.
- *
- * The file format of MVL is quite easy...
- *
- * //MVL File format - Written by Heiko Herrmann
- * char sig[4] = {'D','M', 'V', 'L'}; // "DMVL"=Descent MoVie Library
- *
- * int num_files; // the number of files in this MVL
- *
- * struct {
- * char file_name[13]; // Filename, padded to 13 bytes with 0s
- * int file_size; // filesize in bytes
- * }DIR_STRUCT[num_files];
- *
- * struct {
- * char data[file_size]; // The file data
- * }FILE_STRUCT[num_files];
- *
- * (That info is from http://www.descent2.com/ddn/specs/mvl/)
- *
- * Please see the file LICENSE.txt in the source's root directory.
- *
- * This file written by Bradley Bell.
- * Based on grp.c by Ryan C. Gordon.
- */
-
-#define __PHYSICSFS_INTERNAL__
-#include "physfs_internal.h"
-
-#if PHYSFS_SUPPORTS_MVL
-
-static UNPKentry *mvlLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 fileCount)
-{
- PHYSFS_uint32 location = 8; /* sizeof sig. */
- UNPKentry *entries = NULL;
- UNPKentry *entry = NULL;
-
- entries = (UNPKentry *) allocator.Malloc(sizeof (UNPKentry) * fileCount);
- BAIL_IF_MACRO(entries == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
-
- location += (17 * fileCount);
-
- for (entry = entries; fileCount > 0; fileCount--, entry++)
- {
- if (!__PHYSFS_readAll(io, &entry->name, 13)) goto failed;
- if (!__PHYSFS_readAll(io, &entry->size, 4)) goto failed;
- entry->size = PHYSFS_swapULE32(entry->size);
- entry->startPos = location;
- location += entry->size;
- } /* for */
-
- return entries;
-
-failed:
- allocator.Free(entries);
- return NULL;
-} /* mvlLoadEntries */
-
-
-static void *MVL_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
-{
- PHYSFS_uint8 buf[4];
- PHYSFS_uint32 count = 0;
- UNPKentry *entries = NULL;
-
- assert(io != NULL); /* shouldn't ever happen. */
- BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
- BAIL_IF_MACRO(!__PHYSFS_readAll(io, buf, 4), ERRPASS, NULL);
- BAIL_IF_MACRO(memcmp(buf, "DMVL", 4) != 0, PHYSFS_ERR_UNSUPPORTED, NULL);
- BAIL_IF_MACRO(!__PHYSFS_readAll(io, &count, sizeof(count)), ERRPASS, NULL);
-
- count = PHYSFS_swapULE32(count);
- entries = mvlLoadEntries(io, count);
- return (!entries) ? NULL : UNPK_openArchive(io, entries, count);
-} /* MVL_openArchive */
-
-
-const PHYSFS_Archiver __PHYSFS_Archiver_MVL =
-{
- {
- "MVL",
- "Descent II Movielib format",
- "Bradley Bell ",
- "http://icculus.org/physfs/",
- },
- MVL_openArchive, /* openArchive() method */
- UNPK_enumerateFiles, /* enumerateFiles() method */
- UNPK_openRead, /* openRead() method */
- UNPK_openWrite, /* openWrite() method */
- UNPK_openAppend, /* openAppend() method */
- UNPK_remove, /* remove() method */
- UNPK_mkdir, /* mkdir() method */
- UNPK_closeArchive, /* closeArchive() method */
- UNPK_stat /* stat() method */
-};
-
-#endif /* defined PHYSFS_SUPPORTS_MVL */
-
-/* end of mvl.c ... */
-
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/src/archiver_qpak.c
--- a/misc/physfs/src/archiver_qpak.c Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,119 +0,0 @@
-/*
- * QPAK support routines for PhysicsFS.
- *
- * This archiver handles the archive format utilized by Quake 1 and 2.
- * Quake3-based games use the PkZip/Info-Zip format (which our zip.c
- * archiver handles).
- *
- * ========================================================================
- *
- * This format info (in more detail) comes from:
- * http://debian.fmi.uni-sofia.bg/~sergei/cgsr/docs/pak.txt
- *
- * Quake PAK Format
- *
- * Header
- * (4 bytes) signature = 'PACK'
- * (4 bytes) directory offset
- * (4 bytes) directory length
- *
- * Directory
- * (56 bytes) file name
- * (4 bytes) file position
- * (4 bytes) file length
- *
- * ========================================================================
- *
- * Please see the file LICENSE.txt in the source's root directory.
- *
- * This file written by Ryan C. Gordon.
- */
-
-#define __PHYSICSFS_INTERNAL__
-#include "physfs_internal.h"
-
-#if PHYSFS_SUPPORTS_QPAK
-
-#define QPAK_SIG 0x4B434150 /* "PACK" in ASCII. */
-
-static UNPKentry *qpakLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 fileCount)
-{
- UNPKentry *entries = NULL;
- UNPKentry *entry = NULL;
-
- entries = (UNPKentry *) allocator.Malloc(sizeof (UNPKentry) * fileCount);
- BAIL_IF_MACRO(entries == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
-
- for (entry = entries; fileCount > 0; fileCount--, entry++)
- {
- if (!__PHYSFS_readAll(io, &entry->name, 56)) goto failed;
- if (!__PHYSFS_readAll(io, &entry->startPos, 4)) goto failed;
- if (!__PHYSFS_readAll(io, &entry->size, 4)) goto failed;
- entry->size = PHYSFS_swapULE32(entry->size);
- entry->startPos = PHYSFS_swapULE32(entry->startPos);
- } /* for */
-
- return entries;
-
-failed:
- allocator.Free(entries);
- return NULL;
-} /* qpakLoadEntries */
-
-
-static void *QPAK_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
-{
- UNPKentry *entries = NULL;
- PHYSFS_uint32 val = 0;
- PHYSFS_uint32 pos = 0;
- PHYSFS_uint32 count = 0;
-
- assert(io != NULL); /* shouldn't ever happen. */
-
- BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
-
- BAIL_IF_MACRO(!__PHYSFS_readAll(io, &val, 4), ERRPASS, NULL);
- if (PHYSFS_swapULE32(val) != QPAK_SIG)
- BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL);
-
- BAIL_IF_MACRO(!__PHYSFS_readAll(io, &val, 4), ERRPASS, NULL);
- pos = PHYSFS_swapULE32(val); /* directory table offset. */
-
- BAIL_IF_MACRO(!__PHYSFS_readAll(io, &val, 4), ERRPASS, NULL);
- count = PHYSFS_swapULE32(val);
-
- /* corrupted archive? */
- BAIL_IF_MACRO((count % 64) != 0, PHYSFS_ERR_CORRUPT, NULL);
- count /= 64;
-
- BAIL_IF_MACRO(!io->seek(io, pos), ERRPASS, NULL);
-
- entries = qpakLoadEntries(io, count);
- BAIL_IF_MACRO(!entries, ERRPASS, NULL);
- return UNPK_openArchive(io, entries, count);
-} /* QPAK_openArchive */
-
-
-const PHYSFS_Archiver __PHYSFS_Archiver_QPAK =
-{
- {
- "PAK",
- "Quake I/II format",
- "Ryan C. Gordon ",
- "http://icculus.org/physfs/",
- },
- QPAK_openArchive, /* openArchive() method */
- UNPK_enumerateFiles, /* enumerateFiles() method */
- UNPK_openRead, /* openRead() method */
- UNPK_openWrite, /* openWrite() method */
- UNPK_openAppend, /* openAppend() method */
- UNPK_remove, /* remove() method */
- UNPK_mkdir, /* mkdir() method */
- UNPK_closeArchive, /* closeArchive() method */
- UNPK_stat /* stat() method */
-};
-
-#endif /* defined PHYSFS_SUPPORTS_QPAK */
-
-/* end of qpak.c ... */
-
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/src/archiver_unpacked.c
--- a/misc/physfs/src/archiver_unpacked.c Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,470 +0,0 @@
-/*
- * High-level PhysicsFS archiver for simple unpacked file formats.
- *
- * This is a framework that basic archivers build on top of. It's for simple
- * formats that can just hand back a list of files and the offsets of their
- * uncompressed data. There are an alarming number of formats like this.
- *
- * RULES: Archive entries must be uncompressed, must not have separate subdir
- * entries (but can have subdirs), must be case insensitive LOW ASCII
- * filenames <= 56 bytes. No symlinks, etc. We can relax some of these rules
- * as necessary.
- *
- * Please see the file LICENSE.txt in the source's root directory.
- *
- * This file written by Ryan C. Gordon.
- */
-
-#define __PHYSICSFS_INTERNAL__
-#include "physfs_internal.h"
-
-typedef struct
-{
- PHYSFS_Io *io;
- PHYSFS_uint32 entryCount;
- UNPKentry *entries;
-} UNPKinfo;
-
-
-typedef struct
-{
- PHYSFS_Io *io;
- UNPKentry *entry;
- PHYSFS_uint32 curPos;
-} UNPKfileinfo;
-
-
-void UNPK_closeArchive(PHYSFS_Dir *opaque)
-{
- UNPKinfo *info = ((UNPKinfo *) opaque);
- info->io->destroy(info->io);
- allocator.Free(info->entries);
- allocator.Free(info);
-} /* UNPK_closeArchive */
-
-
-static PHYSFS_sint64 UNPK_read(PHYSFS_Io *io, void *buffer, PHYSFS_uint64 len)
-{
- UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque;
- const UNPKentry *entry = finfo->entry;
- const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos);
- PHYSFS_sint64 rc;
-
- if (bytesLeft < len)
- len = bytesLeft;
-
- rc = finfo->io->read(finfo->io, buffer, len);
- if (rc > 0)
- finfo->curPos += (PHYSFS_uint32) rc;
-
- return rc;
-} /* UNPK_read */
-
-
-static PHYSFS_sint64 UNPK_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
-{
- BAIL_MACRO(PHYSFS_ERR_READ_ONLY, -1);
-} /* UNPK_write */
-
-
-static PHYSFS_sint64 UNPK_tell(PHYSFS_Io *io)
-{
- return ((UNPKfileinfo *) io->opaque)->curPos;
-} /* UNPK_tell */
-
-
-static int UNPK_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
-{
- UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque;
- const UNPKentry *entry = finfo->entry;
- int rc;
-
- BAIL_IF_MACRO(offset >= entry->size, PHYSFS_ERR_PAST_EOF, 0);
- rc = finfo->io->seek(finfo->io, entry->startPos + offset);
- if (rc)
- finfo->curPos = (PHYSFS_uint32) offset;
-
- return rc;
-} /* UNPK_seek */
-
-
-static PHYSFS_sint64 UNPK_length(PHYSFS_Io *io)
-{
- const UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque;
- return ((PHYSFS_sint64) finfo->entry->size);
-} /* UNPK_length */
-
-
-static PHYSFS_Io *UNPK_duplicate(PHYSFS_Io *_io)
-{
- UNPKfileinfo *origfinfo = (UNPKfileinfo *) _io->opaque;
- PHYSFS_Io *io = NULL;
- PHYSFS_Io *retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
- UNPKfileinfo *finfo = (UNPKfileinfo *) allocator.Malloc(sizeof (UNPKfileinfo));
- GOTO_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, UNPK_duplicate_failed);
- GOTO_IF_MACRO(!finfo, PHYSFS_ERR_OUT_OF_MEMORY, UNPK_duplicate_failed);
-
- io = origfinfo->io->duplicate(origfinfo->io);
- if (!io) goto UNPK_duplicate_failed;
- finfo->io = io;
- finfo->entry = origfinfo->entry;
- finfo->curPos = 0;
- memcpy(retval, _io, sizeof (PHYSFS_Io));
- retval->opaque = finfo;
- return retval;
-
-UNPK_duplicate_failed:
- if (finfo != NULL) allocator.Free(finfo);
- if (retval != NULL) allocator.Free(retval);
- if (io != NULL) io->destroy(io);
- return NULL;
-} /* UNPK_duplicate */
-
-static int UNPK_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
-
-static void UNPK_destroy(PHYSFS_Io *io)
-{
- UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque;
- finfo->io->destroy(finfo->io);
- allocator.Free(finfo);
- allocator.Free(io);
-} /* UNPK_destroy */
-
-
-static const PHYSFS_Io UNPK_Io =
-{
- CURRENT_PHYSFS_IO_API_VERSION, NULL,
- UNPK_read,
- UNPK_write,
- UNPK_seek,
- UNPK_tell,
- UNPK_length,
- UNPK_duplicate,
- UNPK_flush,
- UNPK_destroy
-};
-
-
-static int entryCmp(void *_a, size_t one, size_t two)
-{
- if (one != two)
- {
- const UNPKentry *a = (const UNPKentry *) _a;
- return __PHYSFS_stricmpASCII(a[one].name, a[two].name);
- } /* if */
-
- return 0;
-} /* entryCmp */
-
-
-static void entrySwap(void *_a, size_t one, size_t two)
-{
- if (one != two)
- {
- UNPKentry tmp;
- UNPKentry *first = &(((UNPKentry *) _a)[one]);
- UNPKentry *second = &(((UNPKentry *) _a)[two]);
- memcpy(&tmp, first, sizeof (UNPKentry));
- memcpy(first, second, sizeof (UNPKentry));
- memcpy(second, &tmp, sizeof (UNPKentry));
- } /* if */
-} /* entrySwap */
-
-
-static PHYSFS_sint32 findStartOfDir(UNPKinfo *info, const char *path,
- int stop_on_first_find)
-{
- PHYSFS_sint32 lo = 0;
- PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
- PHYSFS_sint32 middle;
- PHYSFS_uint32 dlen = (PHYSFS_uint32) strlen(path);
- PHYSFS_sint32 retval = -1;
- const char *name;
- int rc;
-
- if (*path == '\0') /* root dir? */
- return 0;
-
- if ((dlen > 0) && (path[dlen - 1] == '/')) /* ignore trailing slash. */
- dlen--;
-
- while (lo <= hi)
- {
- middle = lo + ((hi - lo) / 2);
- name = info->entries[middle].name;
- rc = __PHYSFS_strnicmpASCII(path, name, dlen);
- if (rc == 0)
- {
- char ch = name[dlen];
- if (ch < '/') /* make sure this isn't just a substr match. */
- rc = -1;
- else if (ch > '/')
- rc = 1;
- else
- {
- if (stop_on_first_find) /* Just checking dir's existance? */
- return middle;
-
- if (name[dlen + 1] == '\0') /* Skip initial dir entry. */
- return (middle + 1);
-
- /* there might be more entries earlier in the list. */
- retval = middle;
- hi = middle - 1;
- } /* else */
- } /* if */
-
- if (rc > 0)
- lo = middle + 1;
- else
- hi = middle - 1;
- } /* while */
-
- return retval;
-} /* findStartOfDir */
-
-
-/*
- * Moved to seperate function so we can use alloca then immediately throw
- * away the allocated stack space...
- */
-static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata,
- const char *odir, const char *str, PHYSFS_sint32 ln)
-{
- char *newstr = __PHYSFS_smallAlloc(ln + 1);
- if (newstr == NULL)
- return;
-
- memcpy(newstr, str, ln);
- newstr[ln] = '\0';
- cb(callbackdata, odir, newstr);
- __PHYSFS_smallFree(newstr);
-} /* doEnumCallback */
-
-
-void UNPK_enumerateFiles(PHYSFS_Dir *opaque, const char *dname,
- int omitSymLinks, PHYSFS_EnumFilesCallback cb,
- const char *origdir, void *callbackdata)
-{
- UNPKinfo *info = ((UNPKinfo *) opaque);
- PHYSFS_sint32 dlen, dlen_inc, max, i;
-
- i = findStartOfDir(info, dname, 0);
- if (i == -1) /* no such directory. */
- return;
-
- dlen = (PHYSFS_sint32) strlen(dname);
- if ((dlen > 0) && (dname[dlen - 1] == '/')) /* ignore trailing slash. */
- dlen--;
-
- dlen_inc = ((dlen > 0) ? 1 : 0) + dlen;
- max = (PHYSFS_sint32) info->entryCount;
- while (i < max)
- {
- char *add;
- char *ptr;
- PHYSFS_sint32 ln;
- char *e = info->entries[i].name;
- if ((dlen) &&
- ((__PHYSFS_strnicmpASCII(e, dname, dlen)) || (e[dlen] != '/')))
- {
- break; /* past end of this dir; we're done. */
- } /* if */
-
- add = e + dlen_inc;
- ptr = strchr(add, '/');
- ln = (PHYSFS_sint32) ((ptr) ? ptr-add : strlen(add));
- doEnumCallback(cb, callbackdata, origdir, add, ln);
- ln += dlen_inc; /* point past entry to children... */
-
- /* increment counter and skip children of subdirs... */
- while ((++i < max) && (ptr != NULL))
- {
- char *e_new = info->entries[i].name;
- if ((__PHYSFS_strnicmpASCII(e, e_new, ln) != 0) ||
- (e_new[ln] != '/'))
- {
- break;
- } /* if */
- } /* while */
- } /* while */
-} /* UNPK_enumerateFiles */
-
-
-/*
- * This will find the UNPKentry associated with a path in platform-independent
- * notation. Directories don't have UNPKentries associated with them, but
- * (*isDir) will be set to non-zero if a dir was hit.
- */
-static UNPKentry *findEntry(const UNPKinfo *info, const char *path, int *isDir)
-{
- UNPKentry *a = info->entries;
- PHYSFS_sint32 pathlen = (PHYSFS_sint32) strlen(path);
- PHYSFS_sint32 lo = 0;
- PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
- PHYSFS_sint32 middle;
- const char *thispath = NULL;
- int rc;
-
- while (lo <= hi)
- {
- middle = lo + ((hi - lo) / 2);
- thispath = a[middle].name;
- rc = __PHYSFS_strnicmpASCII(path, thispath, pathlen);
-
- if (rc > 0)
- lo = middle + 1;
-
- else if (rc < 0)
- hi = middle - 1;
-
- else /* substring match...might be dir or entry or nothing. */
- {
- if (isDir != NULL)
- {
- *isDir = (thispath[pathlen] == '/');
- if (*isDir)
- return NULL;
- } /* if */
-
- if (thispath[pathlen] == '\0') /* found entry? */
- return &a[middle];
- /* adjust search params, try again. */
- else if (thispath[pathlen] > '/')
- hi = middle - 1;
- else
- lo = middle + 1;
- } /* if */
- } /* while */
-
- if (isDir != NULL)
- *isDir = 0;
-
- BAIL_MACRO(PHYSFS_ERR_NO_SUCH_PATH, NULL);
-} /* findEntry */
-
-
-PHYSFS_Io *UNPK_openRead(PHYSFS_Dir *opaque, const char *fnm, int *fileExists)
-{
- PHYSFS_Io *retval = NULL;
- UNPKinfo *info = (UNPKinfo *) opaque;
- UNPKfileinfo *finfo = NULL;
- int isdir = 0;
- UNPKentry *entry = findEntry(info, fnm, &isdir);
-
- *fileExists = (entry != NULL);
- GOTO_IF_MACRO(isdir, PHYSFS_ERR_NOT_A_FILE, UNPK_openRead_failed);
- GOTO_IF_MACRO(!entry, ERRPASS, UNPK_openRead_failed);
-
- retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
- GOTO_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, UNPK_openRead_failed);
-
- finfo = (UNPKfileinfo *) allocator.Malloc(sizeof (UNPKfileinfo));
- GOTO_IF_MACRO(!finfo, PHYSFS_ERR_OUT_OF_MEMORY, UNPK_openRead_failed);
-
- finfo->io = info->io->duplicate(info->io);
- GOTO_IF_MACRO(!finfo->io, ERRPASS, UNPK_openRead_failed);
-
- if (!finfo->io->seek(finfo->io, entry->startPos))
- goto UNPK_openRead_failed;
-
- finfo->curPos = 0;
- finfo->entry = entry;
-
- memcpy(retval, &UNPK_Io, sizeof (*retval));
- retval->opaque = finfo;
- return retval;
-
-UNPK_openRead_failed:
- if (finfo != NULL)
- {
- if (finfo->io != NULL)
- finfo->io->destroy(finfo->io);
- allocator.Free(finfo);
- } /* if */
-
- if (retval != NULL)
- allocator.Free(retval);
-
- return NULL;
-} /* UNPK_openRead */
-
-
-PHYSFS_Io *UNPK_openWrite(PHYSFS_Dir *opaque, const char *name)
-{
- BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
-} /* UNPK_openWrite */
-
-
-PHYSFS_Io *UNPK_openAppend(PHYSFS_Dir *opaque, const char *name)
-{
- BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
-} /* UNPK_openAppend */
-
-
-int UNPK_remove(PHYSFS_Dir *opaque, const char *name)
-{
- BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
-} /* UNPK_remove */
-
-
-int UNPK_mkdir(PHYSFS_Dir *opaque, const char *name)
-{
- BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
-} /* UNPK_mkdir */
-
-
-int UNPK_stat(PHYSFS_Dir *opaque, const char *filename,
- int *exists, PHYSFS_Stat *stat)
-{
- int isDir = 0;
- const UNPKinfo *info = (const UNPKinfo *) opaque;
- const UNPKentry *entry = findEntry(info, filename, &isDir);
-
- if (isDir)
- {
- *exists = 1;
- stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
- stat->filesize = 0;
- } /* if */
- else if (entry != NULL)
- {
- *exists = 1;
- stat->filetype = PHYSFS_FILETYPE_REGULAR;
- stat->filesize = entry->size;
- } /* else if */
- else
- {
- *exists = 0;
- return 0;
- } /* else */
-
- stat->modtime = -1;
- stat->createtime = -1;
- stat->accesstime = -1;
- stat->readonly = 1;
-
- return 1;
-} /* UNPK_stat */
-
-
-PHYSFS_Dir *UNPK_openArchive(PHYSFS_Io *io, UNPKentry *e,
- const PHYSFS_uint32 num)
-{
- UNPKinfo *info = (UNPKinfo *) allocator.Malloc(sizeof (UNPKinfo));
- if (info == NULL)
- {
- allocator.Free(e);
- BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
- } /* if */
-
- __PHYSFS_sort(e, (size_t) num, entryCmp, entrySwap);
- info->io = io;
- info->entryCount = num;
- info->entries = e;
-
- return info;
-} /* UNPK_openArchive */
-
-/* end of archiver_unpacked.c ... */
-
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/src/archiver_wad.c
--- a/misc/physfs/src/archiver_wad.c Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,127 +0,0 @@
-/*
- * WAD support routines for PhysicsFS.
- *
- * This driver handles DOOM engine archives ("wads").
- * This format (but not this driver) was designed by id Software for use
- * with the DOOM engine.
- * The specs of the format are from the unofficial doom specs v1.666
- * found here: http://www.gamers.org/dhs/helpdocs/dmsp1666.html
- * The format of the archive: (from the specs)
- *
- * A WAD file has three parts:
- * (1) a twelve-byte header
- * (2) one or more "lumps"
- * (3) a directory or "info table" that contains the names, offsets, and
- * sizes of all the lumps in the WAD
- *
- * The header consists of three four-byte parts:
- * (a) an ASCII string which must be either "IWAD" or "PWAD"
- * (b) a 4-byte (long) integer which is the number of lumps in the wad
- * (c) a long integer which is the file offset to the start of
- * the directory
- *
- * The directory has one 16-byte entry for every lump. Each entry consists
- * of three parts:
- *
- * (a) a long integer, the file offset to the start of the lump
- * (b) a long integer, the size of the lump in bytes
- * (c) an 8-byte ASCII string, the name of the lump, padded with zeros.
- * For example, the "DEMO1" entry in hexadecimal would be
- * (44 45 4D 4F 31 00 00 00)
- *
- * Note that there is no way to tell if an opened WAD archive is a
- * IWAD or PWAD with this archiver.
- * I couldn't think of a way to provide that information, without being too
- * hacky.
- * I don't think it's really that important though.
- *
- *
- * Please see the file LICENSE.txt in the source's root directory.
- *
- * This file written by Travis Wells, based on the GRP archiver by
- * Ryan C. Gordon.
- */
-
-#define __PHYSICSFS_INTERNAL__
-#include "physfs_internal.h"
-
-#if PHYSFS_SUPPORTS_WAD
-
-static UNPKentry *wadLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 fileCount)
-{
- PHYSFS_uint32 directoryOffset;
- UNPKentry *entries = NULL;
- UNPKentry *entry = NULL;
-
- BAIL_IF_MACRO(!__PHYSFS_readAll(io, &directoryOffset, 4), ERRPASS, 0);
- directoryOffset = PHYSFS_swapULE32(directoryOffset);
-
- BAIL_IF_MACRO(!io->seek(io, directoryOffset), ERRPASS, 0);
-
- entries = (UNPKentry *) allocator.Malloc(sizeof (UNPKentry) * fileCount);
- BAIL_IF_MACRO(!entries, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
-
- for (entry = entries; fileCount > 0; fileCount--, entry++)
- {
- if (!__PHYSFS_readAll(io, &entry->startPos, 4)) goto failed;
- if (!__PHYSFS_readAll(io, &entry->size, 4)) goto failed;
- if (!__PHYSFS_readAll(io, &entry->name, 8)) goto failed;
-
- entry->name[8] = '\0'; /* name might not be null-terminated in file. */
- entry->size = PHYSFS_swapULE32(entry->size);
- entry->startPos = PHYSFS_swapULE32(entry->startPos);
- } /* for */
-
- return entries;
-
-failed:
- allocator.Free(entries);
- return NULL;
-} /* wadLoadEntries */
-
-
-static void *WAD_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
-{
- PHYSFS_uint8 buf[4];
- UNPKentry *entries = NULL;
- PHYSFS_uint32 count = 0;
-
- assert(io != NULL); /* shouldn't ever happen. */
-
- BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
- BAIL_IF_MACRO(!__PHYSFS_readAll(io, buf, sizeof (buf)), ERRPASS, NULL);
- if ((memcmp(buf, "IWAD", 4) != 0) && (memcmp(buf, "PWAD", 4) != 0))
- BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL);
-
- BAIL_IF_MACRO(!__PHYSFS_readAll(io, &count, sizeof (count)), ERRPASS, NULL);
- count = PHYSFS_swapULE32(count);
-
- entries = wadLoadEntries(io, count);
- BAIL_IF_MACRO(!entries, ERRPASS, NULL);
- return UNPK_openArchive(io, entries, count);
-} /* WAD_openArchive */
-
-
-const PHYSFS_Archiver __PHYSFS_Archiver_WAD =
-{
- {
- "WAD",
- "DOOM engine format",
- "Travis Wells ",
- "http://www.3dmm2.com/doom/",
- },
- WAD_openArchive, /* openArchive() method */
- UNPK_enumerateFiles, /* enumerateFiles() method */
- UNPK_openRead, /* openRead() method */
- UNPK_openWrite, /* openWrite() method */
- UNPK_openAppend, /* openAppend() method */
- UNPK_remove, /* remove() method */
- UNPK_mkdir, /* mkdir() method */
- UNPK_closeArchive, /* closeArchive() method */
- UNPK_stat /* stat() method */
-};
-
-#endif /* defined PHYSFS_SUPPORTS_WAD */
-
-/* end of wad.c ... */
-
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/src/archiver_zip.c
--- a/misc/physfs/src/archiver_zip.c Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1717 +0,0 @@
-/*
- * ZIP support routines for PhysicsFS.
- *
- * Please see the file LICENSE.txt in the source's root directory.
- *
- * This file written by Ryan C. Gordon, with some peeking at "unzip.c"
- * by Gilles Vollant.
- */
-
-#define __PHYSICSFS_INTERNAL__
-#include "physfs_internal.h"
-
-#if PHYSFS_SUPPORTS_ZIP
-
-#include
-#include
-
-#define USE_MINIZ 1
-#if USE_MINIZ
-#include "physfs_miniz.h"
-#else
-#include
-#endif
-
-/*
- * A buffer of ZIP_READBUFSIZE is allocated for each compressed file opened,
- * and is freed when you close the file; compressed data is read into
- * this buffer, and then is decompressed into the buffer passed to
- * PHYSFS_read().
- *
- * Uncompressed entries in a zipfile do not allocate this buffer; they just
- * read data directly into the buffer passed to PHYSFS_read().
- *
- * Depending on your speed and memory requirements, you should tweak this
- * value.
- */
-#define ZIP_READBUFSIZE (16 * 1024)
-
-
-/*
- * Entries are "unresolved" until they are first opened. At that time,
- * local file headers parsed/validated, data offsets will be updated to look
- * at the actual file data instead of the header, and symlinks will be
- * followed and optimized. This means that we don't seek and read around the
- * archive until forced to do so, and after the first time, we had to do
- * less reading and parsing, which is very CD-ROM friendly.
- */
-typedef enum
-{
- ZIP_UNRESOLVED_FILE,
- ZIP_UNRESOLVED_SYMLINK,
- ZIP_RESOLVING,
- ZIP_RESOLVED,
- ZIP_BROKEN_FILE,
- ZIP_BROKEN_SYMLINK
-} ZipResolveType;
-
-
-/*
- * One ZIPentry is kept for each file in an open ZIP archive.
- */
-typedef struct _ZIPentry
-{
- char *name; /* Name of file in archive */
- struct _ZIPentry *symlink; /* NULL or file we symlink to */
- ZipResolveType resolved; /* Have we resolved file/symlink? */
- PHYSFS_uint64 offset; /* offset of data in archive */
- PHYSFS_uint16 version; /* version made by */
- PHYSFS_uint16 version_needed; /* version needed to extract */
- PHYSFS_uint16 compression_method; /* compression method */
- PHYSFS_uint32 crc; /* crc-32 */
- PHYSFS_uint64 compressed_size; /* compressed size */
- PHYSFS_uint64 uncompressed_size; /* uncompressed size */
- PHYSFS_sint64 last_mod_time; /* last file mod time */
-} ZIPentry;
-
-/*
- * One ZIPinfo is kept for each open ZIP archive.
- */
-typedef struct
-{
- PHYSFS_Io *io;
- int zip64; /* non-zero if this is a Zip64 archive. */
- PHYSFS_uint64 entryCount; /* Number of files in ZIP. */
- ZIPentry *entries; /* info on all files in ZIP. */
-} ZIPinfo;
-
-/*
- * One ZIPfileinfo is kept for each open file in a ZIP archive.
- */
-typedef struct
-{
- ZIPentry *entry; /* Info on file. */
- PHYSFS_Io *io; /* physical file handle. */
- PHYSFS_uint32 compressed_position; /* offset in compressed data. */
- PHYSFS_uint32 uncompressed_position; /* tell() position. */
- PHYSFS_uint8 *buffer; /* decompression buffer. */
- z_stream stream; /* zlib stream state. */
-} ZIPfileinfo;
-
-
-/* Magic numbers... */
-#define ZIP_LOCAL_FILE_SIG 0x04034b50
-#define ZIP_CENTRAL_DIR_SIG 0x02014b50
-#define ZIP_END_OF_CENTRAL_DIR_SIG 0x06054b50
-#define ZIP64_END_OF_CENTRAL_DIR_SIG 0x06064b50
-#define ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIG 0x07064b50
-#define ZIP64_EXTENDED_INFO_EXTRA_FIELD_SIG 0x0001
-
-/* compression methods... */
-#define COMPMETH_NONE 0
-/* ...and others... */
-
-
-#define UNIX_FILETYPE_MASK 0170000
-#define UNIX_FILETYPE_SYMLINK 0120000
-
-
-/*
- * Bridge physfs allocation functions to zlib's format...
- */
-static voidpf zlibPhysfsAlloc(voidpf opaque, uInt items, uInt size)
-{
- return ((PHYSFS_Allocator *) opaque)->Malloc(items * size);
-} /* zlibPhysfsAlloc */
-
-/*
- * Bridge physfs allocation functions to zlib's format...
- */
-static void zlibPhysfsFree(voidpf opaque, voidpf address)
-{
- ((PHYSFS_Allocator *) opaque)->Free(address);
-} /* zlibPhysfsFree */
-
-
-/*
- * Construct a new z_stream to a sane state.
- */
-static void initializeZStream(z_stream *pstr)
-{
- memset(pstr, '\0', sizeof (z_stream));
- pstr->zalloc = zlibPhysfsAlloc;
- pstr->zfree = zlibPhysfsFree;
- pstr->opaque = &allocator;
-} /* initializeZStream */
-
-
-static PHYSFS_ErrorCode zlib_error_code(int rc)
-{
- switch (rc)
- {
- case Z_OK: return PHYSFS_ERR_OK; /* not an error. */
- case Z_STREAM_END: return PHYSFS_ERR_OK; /* not an error. */
- case Z_ERRNO: return PHYSFS_ERR_IO;
- case Z_MEM_ERROR: return PHYSFS_ERR_OUT_OF_MEMORY;
- default: return PHYSFS_ERR_CORRUPT;
- } /* switch */
-} /* zlib_error_string */
-
-
-/*
- * Wrap all zlib calls in this, so the physfs error state is set appropriately.
- */
-static int zlib_err(const int rc)
-{
- __PHYSFS_setError(zlib_error_code(rc));
- return rc;
-} /* zlib_err */
-
-
-/*
- * Read an unsigned 64-bit int and swap to native byte order.
- */
-static int readui64(PHYSFS_Io *io, PHYSFS_uint64 *val)
-{
- PHYSFS_uint64 v;
- BAIL_IF_MACRO(!__PHYSFS_readAll(io, &v, sizeof (v)), ERRPASS, 0);
- *val = PHYSFS_swapULE64(v);
- return 1;
-} /* readui64 */
-
-/*
- * Read an unsigned 32-bit int and swap to native byte order.
- */
-static int readui32(PHYSFS_Io *io, PHYSFS_uint32 *val)
-{
- PHYSFS_uint32 v;
- BAIL_IF_MACRO(!__PHYSFS_readAll(io, &v, sizeof (v)), ERRPASS, 0);
- *val = PHYSFS_swapULE32(v);
- return 1;
-} /* readui32 */
-
-
-/*
- * Read an unsigned 16-bit int and swap to native byte order.
- */
-static int readui16(PHYSFS_Io *io, PHYSFS_uint16 *val)
-{
- PHYSFS_uint16 v;
- BAIL_IF_MACRO(!__PHYSFS_readAll(io, &v, sizeof (v)), ERRPASS, 0);
- *val = PHYSFS_swapULE16(v);
- return 1;
-} /* readui16 */
-
-
-static PHYSFS_sint64 ZIP_read(PHYSFS_Io *_io, void *buf, PHYSFS_uint64 len)
-{
- ZIPfileinfo *finfo = (ZIPfileinfo *) _io->opaque;
- PHYSFS_Io *io = finfo->io;
- ZIPentry *entry = finfo->entry;
- PHYSFS_sint64 retval = 0;
- PHYSFS_sint64 maxread = (PHYSFS_sint64) len;
- PHYSFS_sint64 avail = entry->uncompressed_size -
- finfo->uncompressed_position;
-
- if (avail < maxread)
- maxread = avail;
-
- BAIL_IF_MACRO(maxread == 0, ERRPASS, 0); /* quick rejection. */
-
- if (entry->compression_method == COMPMETH_NONE)
- retval = io->read(io, buf, maxread);
- else
- {
- finfo->stream.next_out = buf;
- finfo->stream.avail_out = (uInt) maxread;
-
- while (retval < maxread)
- {
- PHYSFS_uint32 before = finfo->stream.total_out;
- int rc;
-
- if (finfo->stream.avail_in == 0)
- {
- PHYSFS_sint64 br;
-
- br = entry->compressed_size - finfo->compressed_position;
- if (br > 0)
- {
- if (br > ZIP_READBUFSIZE)
- br = ZIP_READBUFSIZE;
-
- br = io->read(io, finfo->buffer, (PHYSFS_uint64) br);
- if (br <= 0)
- break;
-
- finfo->compressed_position += (PHYSFS_uint32) br;
- finfo->stream.next_in = finfo->buffer;
- finfo->stream.avail_in = (PHYSFS_uint32) br;
- } /* if */
- } /* if */
-
- rc = zlib_err(inflate(&finfo->stream, Z_SYNC_FLUSH));
- retval += (finfo->stream.total_out - before);
-
- if (rc != Z_OK)
- break;
- } /* while */
- } /* else */
-
- if (retval > 0)
- finfo->uncompressed_position += (PHYSFS_uint32) retval;
-
- return retval;
-} /* ZIP_read */
-
-
-static PHYSFS_sint64 ZIP_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
-{
- BAIL_MACRO(PHYSFS_ERR_READ_ONLY, -1);
-} /* ZIP_write */
-
-
-static PHYSFS_sint64 ZIP_tell(PHYSFS_Io *io)
-{
- return ((ZIPfileinfo *) io->opaque)->uncompressed_position;
-} /* ZIP_tell */
-
-
-static int ZIP_seek(PHYSFS_Io *_io, PHYSFS_uint64 offset)
-{
- ZIPfileinfo *finfo = (ZIPfileinfo *) _io->opaque;
- ZIPentry *entry = finfo->entry;
- PHYSFS_Io *io = finfo->io;
-
- BAIL_IF_MACRO(offset > entry->uncompressed_size, PHYSFS_ERR_PAST_EOF, 0);
-
- if (entry->compression_method == COMPMETH_NONE)
- {
- const PHYSFS_sint64 newpos = offset + entry->offset;
- BAIL_IF_MACRO(!io->seek(io, newpos), ERRPASS, 0);
- finfo->uncompressed_position = (PHYSFS_uint32) offset;
- } /* if */
-
- else
- {
- /*
- * If seeking backwards, we need to redecode the file
- * from the start and throw away the compressed bits until we hit
- * the offset we need. If seeking forward, we still need to
- * decode, but we don't rewind first.
- */
- if (offset < finfo->uncompressed_position)
- {
- /* we do a copy so state is sane if inflateInit2() fails. */
- z_stream str;
- initializeZStream(&str);
- if (zlib_err(inflateInit2(&str, -MAX_WBITS)) != Z_OK)
- return 0;
-
- if (!io->seek(io, entry->offset))
- return 0;
-
- inflateEnd(&finfo->stream);
- memcpy(&finfo->stream, &str, sizeof (z_stream));
- finfo->uncompressed_position = finfo->compressed_position = 0;
- } /* if */
-
- while (finfo->uncompressed_position != offset)
- {
- PHYSFS_uint8 buf[512];
- PHYSFS_uint32 maxread;
-
- maxread = (PHYSFS_uint32) (offset - finfo->uncompressed_position);
- if (maxread > sizeof (buf))
- maxread = sizeof (buf);
-
- if (ZIP_read(_io, buf, maxread) != maxread)
- return 0;
- } /* while */
- } /* else */
-
- return 1;
-} /* ZIP_seek */
-
-
-static PHYSFS_sint64 ZIP_length(PHYSFS_Io *io)
-{
- const ZIPfileinfo *finfo = (ZIPfileinfo *) io->opaque;
- return (PHYSFS_sint64) finfo->entry->uncompressed_size;
-} /* ZIP_length */
-
-
-static PHYSFS_Io *zip_get_io(PHYSFS_Io *io, ZIPinfo *inf, ZIPentry *entry);
-
-static PHYSFS_Io *ZIP_duplicate(PHYSFS_Io *io)
-{
- ZIPfileinfo *origfinfo = (ZIPfileinfo *) io->opaque;
- PHYSFS_Io *retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
- ZIPfileinfo *finfo = (ZIPfileinfo *) allocator.Malloc(sizeof (ZIPfileinfo));
- GOTO_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, failed);
- GOTO_IF_MACRO(!finfo, PHYSFS_ERR_OUT_OF_MEMORY, failed);
- memset(finfo, '\0', sizeof (*finfo));
-
- finfo->entry = origfinfo->entry;
- finfo->io = zip_get_io(origfinfo->io, NULL, finfo->entry);
- GOTO_IF_MACRO(!finfo->io, ERRPASS, failed);
-
- if (finfo->entry->compression_method != COMPMETH_NONE)
- {
- finfo->buffer = (PHYSFS_uint8 *) allocator.Malloc(ZIP_READBUFSIZE);
- GOTO_IF_MACRO(!finfo->buffer, PHYSFS_ERR_OUT_OF_MEMORY, failed);
- if (zlib_err(inflateInit2(&finfo->stream, -MAX_WBITS)) != Z_OK)
- goto failed;
- } /* if */
-
- memcpy(retval, io, sizeof (PHYSFS_Io));
- retval->opaque = finfo;
- return retval;
-
-failed:
- if (finfo != NULL)
- {
- if (finfo->io != NULL)
- finfo->io->destroy(finfo->io);
-
- if (finfo->buffer != NULL)
- {
- allocator.Free(finfo->buffer);
- inflateEnd(&finfo->stream);
- } /* if */
-
- allocator.Free(finfo);
- } /* if */
-
- if (retval != NULL)
- allocator.Free(retval);
-
- return NULL;
-} /* ZIP_duplicate */
-
-static int ZIP_flush(PHYSFS_Io *io) { return 1; /* no write support. */ }
-
-static void ZIP_destroy(PHYSFS_Io *io)
-{
- ZIPfileinfo *finfo = (ZIPfileinfo *) io->opaque;
- finfo->io->destroy(finfo->io);
-
- if (finfo->entry->compression_method != COMPMETH_NONE)
- inflateEnd(&finfo->stream);
-
- if (finfo->buffer != NULL)
- allocator.Free(finfo->buffer);
-
- allocator.Free(finfo);
- allocator.Free(io);
-} /* ZIP_destroy */
-
-
-static const PHYSFS_Io ZIP_Io =
-{
- CURRENT_PHYSFS_IO_API_VERSION, NULL,
- ZIP_read,
- ZIP_write,
- ZIP_seek,
- ZIP_tell,
- ZIP_length,
- ZIP_duplicate,
- ZIP_flush,
- ZIP_destroy
-};
-
-
-
-static PHYSFS_sint64 zip_find_end_of_central_dir(PHYSFS_Io *io, PHYSFS_sint64 *len)
-{
- PHYSFS_uint8 buf[256];
- PHYSFS_uint8 extra[4] = { 0, 0, 0, 0 };
- PHYSFS_sint32 i = 0;
- PHYSFS_sint64 filelen;
- PHYSFS_sint64 filepos;
- PHYSFS_sint32 maxread;
- PHYSFS_sint32 totalread = 0;
- int found = 0;
-
- filelen = io->length(io);
- BAIL_IF_MACRO(filelen == -1, ERRPASS, 0);
-
- /*
- * Jump to the end of the file and start reading backwards.
- * The last thing in the file is the zipfile comment, which is variable
- * length, and the field that specifies its size is before it in the
- * file (argh!)...this means that we need to scan backwards until we
- * hit the end-of-central-dir signature. We can then sanity check that
- * the comment was as big as it should be to make sure we're in the
- * right place. The comment length field is 16 bits, so we can stop
- * searching for that signature after a little more than 64k at most,
- * and call it a corrupted zipfile.
- */
-
- if (sizeof (buf) < filelen)
- {
- filepos = filelen - sizeof (buf);
- maxread = sizeof (buf);
- } /* if */
- else
- {
- filepos = 0;
- maxread = (PHYSFS_uint32) filelen;
- } /* else */
-
- while ((totalread < filelen) && (totalread < 65557))
- {
- BAIL_IF_MACRO(!io->seek(io, filepos), ERRPASS, -1);
-
- /* make sure we catch a signature between buffers. */
- if (totalread != 0)
- {
- if (!__PHYSFS_readAll(io, buf, maxread - 4))
- return -1;
- memcpy(&buf[maxread - 4], &extra, sizeof (extra));
- totalread += maxread - 4;
- } /* if */
- else
- {
- if (!__PHYSFS_readAll(io, buf, maxread))
- return -1;
- totalread += maxread;
- } /* else */
-
- memcpy(&extra, buf, sizeof (extra));
-
- for (i = maxread - 4; i > 0; i--)
- {
- if ((buf[i + 0] == 0x50) &&
- (buf[i + 1] == 0x4B) &&
- (buf[i + 2] == 0x05) &&
- (buf[i + 3] == 0x06) )
- {
- found = 1; /* that's the signature! */
- break;
- } /* if */
- } /* for */
-
- if (found)
- break;
-
- filepos -= (maxread - 4);
- if (filepos < 0)
- filepos = 0;
- } /* while */
-
- BAIL_IF_MACRO(!found, PHYSFS_ERR_UNSUPPORTED, -1);
-
- if (len != NULL)
- *len = filelen;
-
- return (filepos + i);
-} /* zip_find_end_of_central_dir */
-
-
-static int isZip(PHYSFS_Io *io)
-{
- PHYSFS_uint32 sig = 0;
- int retval = 0;
-
- /*
- * The first thing in a zip file might be the signature of the
- * first local file record, so it makes for a quick determination.
- */
- if (readui32(io, &sig))
- {
- retval = (sig == ZIP_LOCAL_FILE_SIG);
- if (!retval)
- {
- /*
- * No sig...might be a ZIP with data at the start
- * (a self-extracting executable, etc), so we'll have to do
- * it the hard way...
- */
- retval = (zip_find_end_of_central_dir(io, NULL) != -1);
- } /* if */
- } /* if */
-
- return retval;
-} /* isZip */
-
-
-static void zip_free_entries(ZIPentry *entries, PHYSFS_uint64 max)
-{
- PHYSFS_uint64 i;
- for (i = 0; i < max; i++)
- {
- ZIPentry *entry = &entries[i];
- if (entry->name != NULL)
- allocator.Free(entry->name);
- } /* for */
-
- allocator.Free(entries);
-} /* zip_free_entries */
-
-
-/*
- * This will find the ZIPentry associated with a path in platform-independent
- * notation. Directories don't have ZIPentries associated with them, but
- * (*isDir) will be set to non-zero if a dir was hit.
- */
-static ZIPentry *zip_find_entry(const ZIPinfo *info, const char *path,
- int *isDir)
-{
- ZIPentry *a = info->entries;
- PHYSFS_sint32 pathlen = (PHYSFS_sint32) strlen(path);
- PHYSFS_sint64 lo = 0;
- PHYSFS_sint64 hi = (PHYSFS_sint64) (info->entryCount - 1);
- PHYSFS_sint64 middle;
- const char *thispath = NULL;
- int rc;
-
- while (lo <= hi)
- {
- middle = lo + ((hi - lo) / 2);
- thispath = a[middle].name;
- rc = strncmp(path, thispath, pathlen);
-
- if (rc > 0)
- lo = middle + 1;
-
- else if (rc < 0)
- hi = middle - 1;
-
- else /* substring match...might be dir or entry or nothing. */
- {
- if (isDir != NULL)
- {
- *isDir = (thispath[pathlen] == '/');
- if (*isDir)
- return NULL;
- } /* if */
-
- if (thispath[pathlen] == '\0') /* found entry? */
- return &a[middle];
- /* adjust search params, try again. */
- else if (thispath[pathlen] > '/')
- hi = middle - 1;
- else
- lo = middle + 1;
- } /* if */
- } /* while */
-
- if (isDir != NULL)
- *isDir = 0;
-
- BAIL_MACRO(PHYSFS_ERR_NO_SUCH_PATH, NULL);
-} /* zip_find_entry */
-
-
-/* Convert paths from old, buggy DOS zippers... */
-static void zip_convert_dos_path(ZIPentry *entry, char *path)
-{
- PHYSFS_uint8 hosttype = (PHYSFS_uint8) ((entry->version >> 8) & 0xFF);
- if (hosttype == 0) /* FS_FAT_ */
- {
- while (*path)
- {
- if (*path == '\\')
- *path = '/';
- path++;
- } /* while */
- } /* if */
-} /* zip_convert_dos_path */
-
-
-static void zip_expand_symlink_path(char *path)
-{
- char *ptr = path;
- char *prevptr = path;
-
- while (1)
- {
- ptr = strchr(ptr, '/');
- if (ptr == NULL)
- break;
-
- if (*(ptr + 1) == '.')
- {
- if (*(ptr + 2) == '/')
- {
- /* current dir in middle of string: ditch it. */
- memmove(ptr, ptr + 2, strlen(ptr + 2) + 1);
- } /* else if */
-
- else if (*(ptr + 2) == '\0')
- {
- /* current dir at end of string: ditch it. */
- *ptr = '\0';
- } /* else if */
-
- else if (*(ptr + 2) == '.')
- {
- if (*(ptr + 3) == '/')
- {
- /* parent dir in middle: move back one, if possible. */
- memmove(prevptr, ptr + 4, strlen(ptr + 4) + 1);
- ptr = prevptr;
- while (prevptr != path)
- {
- prevptr--;
- if (*prevptr == '/')
- {
- prevptr++;
- break;
- } /* if */
- } /* while */
- } /* if */
-
- if (*(ptr + 3) == '\0')
- {
- /* parent dir at end: move back one, if possible. */
- *prevptr = '\0';
- } /* if */
- } /* if */
- } /* if */
- else
- {
- prevptr = ptr;
- ptr++;
- } /* else */
- } /* while */
-} /* zip_expand_symlink_path */
-
-/* (forward reference: zip_follow_symlink and zip_resolve call each other.) */
-static int zip_resolve(PHYSFS_Io *io, ZIPinfo *info, ZIPentry *entry);
-
-/*
- * Look for the entry named by (path). If it exists, resolve it, and return
- * a pointer to that entry. If it's another symlink, keep resolving until you
- * hit a real file and then return a pointer to the final non-symlink entry.
- * If there's a problem, return NULL.
- */
-static ZIPentry *zip_follow_symlink(PHYSFS_Io *io, ZIPinfo *info, char *path)
-{
- ZIPentry *entry;
-
- zip_expand_symlink_path(path);
- entry = zip_find_entry(info, path, NULL);
- if (entry != NULL)
- {
- if (!zip_resolve(io, info, entry)) /* recursive! */
- entry = NULL;
- else
- {
- if (entry->symlink != NULL)
- entry = entry->symlink;
- } /* else */
- } /* if */
-
- return entry;
-} /* zip_follow_symlink */
-
-
-static int zip_resolve_symlink(PHYSFS_Io *io, ZIPinfo *info, ZIPentry *entry)
-{
- const PHYSFS_uint64 size = entry->uncompressed_size;
- char *path = NULL;
- int rc = 0;
-
- /*
- * We've already parsed the local file header of the symlink at this
- * point. Now we need to read the actual link from the file data and
- * follow it.
- */
-
- BAIL_IF_MACRO(!io->seek(io, entry->offset), ERRPASS, 0);
-
- path = (char *) __PHYSFS_smallAlloc(size + 1);
- BAIL_IF_MACRO(!path, PHYSFS_ERR_OUT_OF_MEMORY, 0);
-
- if (entry->compression_method == COMPMETH_NONE)
- rc = __PHYSFS_readAll(io, path, size);
-
- else /* symlink target path is compressed... */
- {
- z_stream stream;
- const PHYSFS_uint64 complen = entry->compressed_size;
- PHYSFS_uint8 *compressed = (PHYSFS_uint8*) __PHYSFS_smallAlloc(complen);
- if (compressed != NULL)
- {
- if (__PHYSFS_readAll(io, compressed, complen))
- {
- initializeZStream(&stream);
- stream.next_in = compressed;
- stream.avail_in = complen;
- stream.next_out = (unsigned char *) path;
- stream.avail_out = size;
- if (zlib_err(inflateInit2(&stream, -MAX_WBITS)) == Z_OK)
- {
- rc = zlib_err(inflate(&stream, Z_FINISH));
- inflateEnd(&stream);
-
- /* both are acceptable outcomes... */
- rc = ((rc == Z_OK) || (rc == Z_STREAM_END));
- } /* if */
- } /* if */
- __PHYSFS_smallFree(compressed);
- } /* if */
- } /* else */
-
- if (rc)
- {
- path[entry->uncompressed_size] = '\0'; /* null-terminate it. */
- zip_convert_dos_path(entry, path);
- entry->symlink = zip_follow_symlink(io, info, path);
- } /* else */
-
- __PHYSFS_smallFree(path);
-
- return (entry->symlink != NULL);
-} /* zip_resolve_symlink */
-
-
-/*
- * Parse the local file header of an entry, and update entry->offset.
- */
-static int zip_parse_local(PHYSFS_Io *io, ZIPentry *entry)
-{
- PHYSFS_uint32 ui32;
- PHYSFS_uint16 ui16;
- PHYSFS_uint16 fnamelen;
- PHYSFS_uint16 extralen;
-
- /*
- * crc and (un)compressed_size are always zero if this is a "JAR"
- * archive created with Sun's Java tools, apparently. We only
- * consider this archive corrupted if those entries don't match and
- * aren't zero. That seems to work well.
- * We also ignore a mismatch if the value is 0xFFFFFFFF here, since it's
- * possible that's a Zip64 thing.
- */
-
- BAIL_IF_MACRO(!io->seek(io, entry->offset), ERRPASS, 0);
- BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
- BAIL_IF_MACRO(ui32 != ZIP_LOCAL_FILE_SIG, PHYSFS_ERR_CORRUPT, 0);
- BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
- BAIL_IF_MACRO(ui16 != entry->version_needed, PHYSFS_ERR_CORRUPT, 0);
- BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0); /* general bits. */
- BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
- BAIL_IF_MACRO(ui16 != entry->compression_method, PHYSFS_ERR_CORRUPT, 0);
- BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0); /* date/time */
- BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
- BAIL_IF_MACRO(ui32 && (ui32 != entry->crc), PHYSFS_ERR_CORRUPT, 0);
-
- BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
- BAIL_IF_MACRO(ui32 && (ui32 != 0xFFFFFFFF) &&
- (ui32 != entry->compressed_size), PHYSFS_ERR_CORRUPT, 0);
-
- BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
- BAIL_IF_MACRO(ui32 && (ui32 != 0xFFFFFFFF) &&
- (ui32 != entry->uncompressed_size), PHYSFS_ERR_CORRUPT, 0);
-
- BAIL_IF_MACRO(!readui16(io, &fnamelen), ERRPASS, 0);
- BAIL_IF_MACRO(!readui16(io, &extralen), ERRPASS, 0);
-
- entry->offset += fnamelen + extralen + 30;
- return 1;
-} /* zip_parse_local */
-
-
-static int zip_resolve(PHYSFS_Io *io, ZIPinfo *info, ZIPentry *entry)
-{
- int retval = 1;
- ZipResolveType resolve_type = entry->resolved;
-
- /* Don't bother if we've failed to resolve this entry before. */
- BAIL_IF_MACRO(resolve_type == ZIP_BROKEN_FILE, PHYSFS_ERR_CORRUPT, 0);
- BAIL_IF_MACRO(resolve_type == ZIP_BROKEN_SYMLINK, PHYSFS_ERR_CORRUPT, 0);
-
- /* uhoh...infinite symlink loop! */
- BAIL_IF_MACRO(resolve_type == ZIP_RESOLVING, PHYSFS_ERR_SYMLINK_LOOP, 0);
-
- /*
- * We fix up the offset to point to the actual data on the
- * first open, since we don't want to seek across the whole file on
- * archive open (can be SLOW on large, CD-stored files), but we
- * need to check the local file header...not just for corruption,
- * but since it stores offset info the central directory does not.
- */
- if (resolve_type != ZIP_RESOLVED)
- {
- entry->resolved = ZIP_RESOLVING;
-
- retval = zip_parse_local(io, entry);
- if (retval)
- {
- /*
- * If it's a symlink, find the original file. This will cause
- * resolution of other entries (other symlinks and, eventually,
- * the real file) if all goes well.
- */
- if (resolve_type == ZIP_UNRESOLVED_SYMLINK)
- retval = zip_resolve_symlink(io, info, entry);
- } /* if */
-
- if (resolve_type == ZIP_UNRESOLVED_SYMLINK)
- entry->resolved = ((retval) ? ZIP_RESOLVED : ZIP_BROKEN_SYMLINK);
- else if (resolve_type == ZIP_UNRESOLVED_FILE)
- entry->resolved = ((retval) ? ZIP_RESOLVED : ZIP_BROKEN_FILE);
- } /* if */
-
- return retval;
-} /* zip_resolve */
-
-
-static int zip_version_does_symlinks(PHYSFS_uint32 version)
-{
- int retval = 0;
- PHYSFS_uint8 hosttype = (PHYSFS_uint8) ((version >> 8) & 0xFF);
-
- switch (hosttype)
- {
- /*
- * These are the platforms that can NOT build an archive with
- * symlinks, according to the Info-ZIP project.
- */
- case 0: /* FS_FAT_ */
- case 1: /* AMIGA_ */
- case 2: /* VMS_ */
- case 4: /* VM_CSM_ */
- case 6: /* FS_HPFS_ */
- case 11: /* FS_NTFS_ */
- case 14: /* FS_VFAT_ */
- case 13: /* ACORN_ */
- case 15: /* MVS_ */
- case 18: /* THEOS_ */
- break; /* do nothing. */
-
- default: /* assume the rest to be unix-like. */
- retval = 1;
- break;
- } /* switch */
-
- return retval;
-} /* zip_version_does_symlinks */
-
-
-static int zip_entry_is_symlink(const ZIPentry *entry)
-{
- return ((entry->resolved == ZIP_UNRESOLVED_SYMLINK) ||
- (entry->resolved == ZIP_BROKEN_SYMLINK) ||
- (entry->symlink));
-} /* zip_entry_is_symlink */
-
-
-static int zip_has_symlink_attr(ZIPentry *entry, PHYSFS_uint32 extern_attr)
-{
- PHYSFS_uint16 xattr = ((extern_attr >> 16) & 0xFFFF);
- return ( (zip_version_does_symlinks(entry->version)) &&
- (entry->uncompressed_size > 0) &&
- ((xattr & UNIX_FILETYPE_MASK) == UNIX_FILETYPE_SYMLINK) );
-} /* zip_has_symlink_attr */
-
-
-static PHYSFS_sint64 zip_dos_time_to_physfs_time(PHYSFS_uint32 dostime)
-{
- PHYSFS_uint32 dosdate;
- struct tm unixtime;
- memset(&unixtime, '\0', sizeof (unixtime));
-
- dosdate = (PHYSFS_uint32) ((dostime >> 16) & 0xFFFF);
- dostime &= 0xFFFF;
-
- /* dissect date */
- unixtime.tm_year = ((dosdate >> 9) & 0x7F) + 80;
- unixtime.tm_mon = ((dosdate >> 5) & 0x0F) - 1;
- unixtime.tm_mday = ((dosdate ) & 0x1F);
-
- /* dissect time */
- unixtime.tm_hour = ((dostime >> 11) & 0x1F);
- unixtime.tm_min = ((dostime >> 5) & 0x3F);
- unixtime.tm_sec = ((dostime << 1) & 0x3E);
-
- /* let mktime calculate daylight savings time. */
- unixtime.tm_isdst = -1;
-
- return ((PHYSFS_sint64) mktime(&unixtime));
-} /* zip_dos_time_to_physfs_time */
-
-
-static int zip_load_entry(PHYSFS_Io *io, const int zip64, ZIPentry *entry,
- PHYSFS_uint64 ofs_fixup)
-{
- PHYSFS_uint16 fnamelen, extralen, commentlen;
- PHYSFS_uint32 external_attr;
- PHYSFS_uint32 starting_disk;
- PHYSFS_uint64 offset;
- PHYSFS_uint16 ui16;
- PHYSFS_uint32 ui32;
- PHYSFS_sint64 si64;
-
- /* sanity check with central directory signature... */
- BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
- BAIL_IF_MACRO(ui32 != ZIP_CENTRAL_DIR_SIG, PHYSFS_ERR_CORRUPT, 0);
-
- /* Get the pertinent parts of the record... */
- BAIL_IF_MACRO(!readui16(io, &entry->version), ERRPASS, 0);
- BAIL_IF_MACRO(!readui16(io, &entry->version_needed), ERRPASS, 0);
- BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0); /* general bits */
- BAIL_IF_MACRO(!readui16(io, &entry->compression_method), ERRPASS, 0);
- BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
- entry->last_mod_time = zip_dos_time_to_physfs_time(ui32);
- BAIL_IF_MACRO(!readui32(io, &entry->crc), ERRPASS, 0);
- BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
- entry->compressed_size = (PHYSFS_uint64) ui32;
- BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
- entry->uncompressed_size = (PHYSFS_uint64) ui32;
- BAIL_IF_MACRO(!readui16(io, &fnamelen), ERRPASS, 0);
- BAIL_IF_MACRO(!readui16(io, &extralen), ERRPASS, 0);
- BAIL_IF_MACRO(!readui16(io, &commentlen), ERRPASS, 0);
- BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
- starting_disk = (PHYSFS_uint32) ui16;
- BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0); /* internal file attribs */
- BAIL_IF_MACRO(!readui32(io, &external_attr), ERRPASS, 0);
- BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
- offset = (PHYSFS_uint64) ui32;
-
- entry->symlink = NULL; /* will be resolved later, if necessary. */
- entry->resolved = (zip_has_symlink_attr(entry, external_attr)) ?
- ZIP_UNRESOLVED_SYMLINK : ZIP_UNRESOLVED_FILE;
-
- entry->name = (char *) allocator.Malloc(fnamelen + 1);
- BAIL_IF_MACRO(entry->name == NULL, PHYSFS_ERR_OUT_OF_MEMORY, 0);
- if (!__PHYSFS_readAll(io, entry->name, fnamelen))
- goto zip_load_entry_puked;
-
- entry->name[fnamelen] = '\0'; /* null-terminate the filename. */
- zip_convert_dos_path(entry, entry->name);
-
- si64 = io->tell(io);
- if (si64 == -1)
- goto zip_load_entry_puked;
-
- /*
- * The actual sizes didn't fit in 32-bits; look for the Zip64
- * extended information extra field...
- */
- if ( (zip64) &&
- ((offset == 0xFFFFFFFF) ||
- (starting_disk == 0xFFFFFFFF) ||
- (entry->compressed_size == 0xFFFFFFFF) ||
- (entry->uncompressed_size == 0xFFFFFFFF)) )
- {
- int found = 0;
- PHYSFS_uint16 sig, len;
- while (extralen > 4)
- {
- if (!readui16(io, &sig))
- goto zip_load_entry_puked;
- else if (!readui16(io, &len))
- goto zip_load_entry_puked;
-
- si64 += 4 + len;
- extralen -= 4 + len;
- if (sig != ZIP64_EXTENDED_INFO_EXTRA_FIELD_SIG)
- {
- if (!io->seek(io, si64))
- goto zip_load_entry_puked;
- continue;
- } /* if */
-
- found = 1;
- break;
- } /* while */
-
- GOTO_IF_MACRO(!found, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
-
- if (entry->uncompressed_size == 0xFFFFFFFF)
- {
- GOTO_IF_MACRO(len < 8, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
- if (!readui64(io, &entry->uncompressed_size))
- goto zip_load_entry_puked;
- len -= 8;
- } /* if */
-
- if (entry->compressed_size == 0xFFFFFFFF)
- {
- GOTO_IF_MACRO(len < 8, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
- if (!readui64(io, &entry->compressed_size))
- goto zip_load_entry_puked;
- len -= 8;
- } /* if */
-
- if (offset == 0xFFFFFFFF)
- {
- GOTO_IF_MACRO(len < 8, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
- if (!readui64(io, &offset))
- goto zip_load_entry_puked;
- len -= 8;
- } /* if */
-
- if (starting_disk == 0xFFFFFFFF)
- {
- GOTO_IF_MACRO(len < 8, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
- if (!readui32(io, &starting_disk))
- goto zip_load_entry_puked;
- len -= 4;
- } /* if */
-
- GOTO_IF_MACRO(len != 0, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
- } /* if */
-
- GOTO_IF_MACRO(starting_disk != 0, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
-
- entry->offset = offset + ofs_fixup;
-
- /* seek to the start of the next entry in the central directory... */
- if (!io->seek(io, si64 + extralen + commentlen))
- goto zip_load_entry_puked;
-
- return 1; /* success. */
-
-zip_load_entry_puked:
- allocator.Free(entry->name);
- return 0; /* failure. */
-} /* zip_load_entry */
-
-
-static int zip_entry_cmp(void *_a, size_t one, size_t two)
-{
- if (one != two)
- {
- const ZIPentry *a = (const ZIPentry *) _a;
- return strcmp(a[one].name, a[two].name);
- } /* if */
-
- return 0;
-} /* zip_entry_cmp */
-
-
-static void zip_entry_swap(void *_a, size_t one, size_t two)
-{
- if (one != two)
- {
- ZIPentry tmp;
- ZIPentry *first = &(((ZIPentry *) _a)[one]);
- ZIPentry *second = &(((ZIPentry *) _a)[two]);
- memcpy(&tmp, first, sizeof (ZIPentry));
- memcpy(first, second, sizeof (ZIPentry));
- memcpy(second, &tmp, sizeof (ZIPentry));
- } /* if */
-} /* zip_entry_swap */
-
-
-static int zip_load_entries(PHYSFS_Io *io, ZIPinfo *info,
- const PHYSFS_uint64 data_ofs,
- const PHYSFS_uint64 central_ofs)
-{
- const PHYSFS_uint64 max = info->entryCount;
- const int zip64 = info->zip64;
- PHYSFS_uint64 i;
-
- BAIL_IF_MACRO(!io->seek(io, central_ofs), ERRPASS, 0);
-
- info->entries = (ZIPentry *) allocator.Malloc(sizeof (ZIPentry) * max);
- BAIL_IF_MACRO(!info->entries, PHYSFS_ERR_OUT_OF_MEMORY, 0);
-
- for (i = 0; i < max; i++)
- {
- if (!zip_load_entry(io, zip64, &info->entries[i], data_ofs))
- {
- zip_free_entries(info->entries, i);
- return 0;
- } /* if */
- } /* for */
-
- __PHYSFS_sort(info->entries, (size_t) max, zip_entry_cmp, zip_entry_swap);
- return 1;
-} /* zip_load_entries */
-
-
-static PHYSFS_sint64 zip64_find_end_of_central_dir(PHYSFS_Io *io,
- PHYSFS_sint64 _pos,
- PHYSFS_uint64 offset)
-{
- /*
- * Naturally, the offset is useless to us; it is the offset from the
- * start of file, which is meaningless if we've appended this .zip to
- * a self-extracting .exe. We need to find this on our own. It should
- * be directly before the locator record, but the record in question,
- * like the original end-of-central-directory record, ends with a
- * variable-length field. Unlike the original, which has to store the
- * size of that variable-length field in a 16-bit int and thus has to be
- * within 64k, the new one gets 64-bits.
- *
- * Fortunately, the only currently-specified record for that variable
- * length block is some weird proprietary thing that deals with EBCDIC
- * and tape backups or something. So we don't seek far.
- */
-
- PHYSFS_uint32 ui32;
- const PHYSFS_uint64 pos = (PHYSFS_uint64) _pos;
-
- assert(_pos > 0);
-
- /* Try offset specified in the Zip64 end of central directory locator. */
- /* This works if the entire PHYSFS_Io is the zip file. */
- BAIL_IF_MACRO(!io->seek(io, offset), ERRPASS, -1);
- BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, -1);
- if (ui32 == ZIP64_END_OF_CENTRAL_DIR_SIG)
- return offset;
-
- /* Try 56 bytes before the Zip64 end of central directory locator. */
- /* This works if the record isn't variable length and is version 1. */
- if (pos > 56)
- {
- BAIL_IF_MACRO(!io->seek(io, pos-56), ERRPASS, -1);
- BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, -1);
- if (ui32 == ZIP64_END_OF_CENTRAL_DIR_SIG)
- return pos-56;
- } /* if */
-
- /* Try 84 bytes before the Zip64 end of central directory locator. */
- /* This works if the record isn't variable length and is version 2. */
- if (pos > 84)
- {
- BAIL_IF_MACRO(!io->seek(io, pos-84), ERRPASS, -1);
- BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, -1);
- if (ui32 == ZIP64_END_OF_CENTRAL_DIR_SIG)
- return pos-84;
- } /* if */
-
- /* Ok, brute force: we know it's between (offset) and (pos) somewhere. */
- /* Just try moving back at most 256k. Oh well. */
- if ((offset < pos) && (pos > 4))
- {
- /* we assume you can eat this stack if you handle Zip64 files. */
- PHYSFS_uint8 buf[256 * 1024];
- PHYSFS_uint64 len = pos - offset;
- PHYSFS_sint32 i;
-
- if (len > sizeof (buf))
- len = sizeof (buf);
-
- BAIL_IF_MACRO(!io->seek(io, pos - len), ERRPASS, -1);
- BAIL_IF_MACRO(!__PHYSFS_readAll(io, buf, len), ERRPASS, -1);
- for (i = (PHYSFS_sint32) (len - 4); i >= 0; i--)
- {
- if (buf[i] != 0x50)
- continue;
- if ( (buf[i+1] == 0x4b) &&
- (buf[i+2] == 0x06) &&
- (buf[i+3] == 0x06) )
- return pos - (len - i);
- } /* for */
- } /* if */
-
- BAIL_MACRO(PHYSFS_ERR_CORRUPT, -1); /* didn't find it. */
-} /* zip64_find_end_of_central_dir */
-
-
-static int zip64_parse_end_of_central_dir(PHYSFS_Io *io, ZIPinfo *info,
- PHYSFS_uint64 *data_start,
- PHYSFS_uint64 *dir_ofs,
- PHYSFS_sint64 pos)
-{
- PHYSFS_uint64 ui64;
- PHYSFS_uint32 ui32;
- PHYSFS_uint16 ui16;
-
- /* We should be positioned right past the locator signature. */
-
- if ((pos < 0) || (!io->seek(io, pos)))
- return 0;
-
- BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
- if (ui32 != ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIG)
- return -1; /* it's not a Zip64 archive. Not an error, though! */
-
- info->zip64 = 1;
-
- /* number of the disk with the start of the central directory. */
- BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
- BAIL_IF_MACRO(ui32 != 0, PHYSFS_ERR_CORRUPT, 0);
-
- /* offset of Zip64 end of central directory record. */
- BAIL_IF_MACRO(!readui64(io, &ui64), ERRPASS, 0);
-
- /* total number of disks */
- BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
- BAIL_IF_MACRO(ui32 != 1, PHYSFS_ERR_CORRUPT, 0);
-
- pos = zip64_find_end_of_central_dir(io, pos, ui64);
- if (pos < 0)
- return 0; /* oh well. */
-
- /*
- * For self-extracting archives, etc, there's crapola in the file
- * before the zipfile records; we calculate how much data there is
- * prepended by determining how far the zip64-end-of-central-directory
- * offset is from where it is supposed to be...the difference in bytes
- * is how much arbitrary data is at the start of the physical file.
- */
- assert(((PHYSFS_uint64) pos) >= ui64);
- *data_start = ((PHYSFS_uint64) pos) - ui64;
-
- BAIL_IF_MACRO(!io->seek(io, pos), ERRPASS, 0);
-
- /* check signature again, just in case. */
- BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
- BAIL_IF_MACRO(ui32 != ZIP64_END_OF_CENTRAL_DIR_SIG, PHYSFS_ERR_CORRUPT, 0);
-
- /* size of Zip64 end of central directory record. */
- BAIL_IF_MACRO(!readui64(io, &ui64), ERRPASS, 0);
-
- /* version made by. */
- BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
-
- /* version needed to extract. */
- BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
-
- /* number of this disk. */
- BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
- BAIL_IF_MACRO(ui32 != 0, PHYSFS_ERR_CORRUPT, 0);
-
- /* number of disk with start of central directory record. */
- BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
- BAIL_IF_MACRO(ui32 != 0, PHYSFS_ERR_CORRUPT, 0);
-
- /* total number of entries in the central dir on this disk */
- BAIL_IF_MACRO(!readui64(io, &ui64), ERRPASS, 0);
-
- /* total number of entries in the central dir */
- BAIL_IF_MACRO(!readui64(io, &info->entryCount), ERRPASS, 0);
- BAIL_IF_MACRO(ui64 != info->entryCount, PHYSFS_ERR_CORRUPT, 0);
-
- /* size of the central directory */
- BAIL_IF_MACRO(!readui64(io, &ui64), ERRPASS, 0);
-
- /* offset of central directory */
- BAIL_IF_MACRO(!readui64(io, dir_ofs), ERRPASS, 0);
-
- /* Since we know the difference, fix up the central dir offset... */
- *dir_ofs += *data_start;
-
- /*
- * There are more fields here, for encryption and feature-specific things,
- * but we don't care about any of them at the moment.
- */
-
- return 1; /* made it. */
-} /* zip64_parse_end_of_central_dir */
-
-
-static int zip_parse_end_of_central_dir(PHYSFS_Io *io, ZIPinfo *info,
- PHYSFS_uint64 *data_start,
- PHYSFS_uint64 *dir_ofs)
-{
- PHYSFS_uint16 entryCount16;
- PHYSFS_uint32 offset32;
- PHYSFS_uint32 ui32;
- PHYSFS_uint16 ui16;
- PHYSFS_sint64 len;
- PHYSFS_sint64 pos;
- int rc;
-
- /* find the end-of-central-dir record, and seek to it. */
- pos = zip_find_end_of_central_dir(io, &len);
- BAIL_IF_MACRO(pos == -1, ERRPASS, 0);
- BAIL_IF_MACRO(!io->seek(io, pos), ERRPASS, 0);
-
- /* check signature again, just in case. */
- BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
- BAIL_IF_MACRO(ui32 != ZIP_END_OF_CENTRAL_DIR_SIG, PHYSFS_ERR_CORRUPT, 0);
-
- /* Seek back to see if "Zip64 end of central directory locator" exists. */
- /* this record is 20 bytes before end-of-central-dir */
- rc = zip64_parse_end_of_central_dir(io, info, data_start, dir_ofs, pos-20);
- BAIL_IF_MACRO(rc == 0, ERRPASS, 0);
- if (rc == 1)
- return 1; /* we're done here. */
-
- assert(rc == -1); /* no error, just not a Zip64 archive. */
-
- /* Not Zip64? Seek back to where we were and keep processing. */
- BAIL_IF_MACRO(!io->seek(io, pos + 4), ERRPASS, 0);
-
- /* number of this disk */
- BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
- BAIL_IF_MACRO(ui16 != 0, PHYSFS_ERR_CORRUPT, 0);
-
- /* number of the disk with the start of the central directory */
- BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
- BAIL_IF_MACRO(ui16 != 0, PHYSFS_ERR_CORRUPT, 0);
-
- /* total number of entries in the central dir on this disk */
- BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
-
- /* total number of entries in the central dir */
- BAIL_IF_MACRO(!readui16(io, &entryCount16), ERRPASS, 0);
- BAIL_IF_MACRO(ui16 != entryCount16, PHYSFS_ERR_CORRUPT, 0);
-
- info->entryCount = entryCount16;
-
- /* size of the central directory */
- BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
-
- /* offset of central directory */
- BAIL_IF_MACRO(!readui32(io, &offset32), ERRPASS, 0);
- *dir_ofs = (PHYSFS_uint64) offset32;
- BAIL_IF_MACRO(pos < (*dir_ofs + ui32), PHYSFS_ERR_CORRUPT, 0);
-
- /*
- * For self-extracting archives, etc, there's crapola in the file
- * before the zipfile records; we calculate how much data there is
- * prepended by determining how far the central directory offset is
- * from where it is supposed to be (start of end-of-central-dir minus
- * sizeof central dir)...the difference in bytes is how much arbitrary
- * data is at the start of the physical file.
- */
- *data_start = (PHYSFS_uint64) (pos - (*dir_ofs + ui32));
-
- /* Now that we know the difference, fix up the central dir offset... */
- *dir_ofs += *data_start;
-
- /* zipfile comment length */
- BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
-
- /*
- * Make sure that the comment length matches to the end of file...
- * If it doesn't, we're either in the wrong part of the file, or the
- * file is corrupted, but we give up either way.
- */
- BAIL_IF_MACRO((pos + 22 + ui16) != len, PHYSFS_ERR_CORRUPT, 0);
-
- return 1; /* made it. */
-} /* zip_parse_end_of_central_dir */
-
-
-static void *ZIP_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
-{
- ZIPinfo *info = NULL;
- PHYSFS_uint64 data_start;
- PHYSFS_uint64 cent_dir_ofs;
-
- assert(io != NULL); /* shouldn't ever happen. */
-
- BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
- BAIL_IF_MACRO(!isZip(io), ERRPASS, NULL);
-
- info = (ZIPinfo *) allocator.Malloc(sizeof (ZIPinfo));
- BAIL_IF_MACRO(!info, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
- memset(info, '\0', sizeof (ZIPinfo));
- info->io = io;
-
- if (!zip_parse_end_of_central_dir(io, info, &data_start, ¢_dir_ofs))
- goto ZIP_openarchive_failed;
-
- if (!zip_load_entries(io, info, data_start, cent_dir_ofs))
- goto ZIP_openarchive_failed;
-
- return info;
-
-ZIP_openarchive_failed:
- if (info != NULL)
- allocator.Free(info);
-
- return NULL;
-} /* ZIP_openArchive */
-
-
-static PHYSFS_sint64 zip_find_start_of_dir(ZIPinfo *info, const char *path,
- int stop_on_first_find)
-{
- PHYSFS_sint64 lo = 0;
- PHYSFS_sint64 hi = (PHYSFS_sint64) (info->entryCount - 1);
- PHYSFS_sint64 middle;
- PHYSFS_uint32 dlen = (PHYSFS_uint32) strlen(path);
- PHYSFS_sint64 retval = -1;
- const char *name;
- int rc;
-
- if (*path == '\0') /* root dir? */
- return 0;
-
- if ((dlen > 0) && (path[dlen - 1] == '/')) /* ignore trailing slash. */
- dlen--;
-
- while (lo <= hi)
- {
- middle = lo + ((hi - lo) / 2);
- name = info->entries[middle].name;
- rc = strncmp(path, name, dlen);
- if (rc == 0)
- {
- char ch = name[dlen];
- if ('/' < ch) /* make sure this isn't just a substr match. */
- rc = -1;
- else if ('/' > ch)
- rc = 1;
- else
- {
- if (stop_on_first_find) /* Just checking dir's existance? */
- return middle;
-
- if (name[dlen + 1] == '\0') /* Skip initial dir entry. */
- return (middle + 1);
-
- /* there might be more entries earlier in the list. */
- retval = middle;
- hi = middle - 1;
- } /* else */
- } /* if */
-
- if (rc > 0)
- lo = middle + 1;
- else
- hi = middle - 1;
- } /* while */
-
- return retval;
-} /* zip_find_start_of_dir */
-
-
-/*
- * Moved to seperate function so we can use alloca then immediately throw
- * away the allocated stack space...
- */
-static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata,
- const char *odir, const char *str, PHYSFS_sint32 ln)
-{
- char *newstr = __PHYSFS_smallAlloc(ln + 1);
- if (newstr == NULL)
- return;
-
- memcpy(newstr, str, ln);
- newstr[ln] = '\0';
- cb(callbackdata, odir, newstr);
- __PHYSFS_smallFree(newstr);
-} /* doEnumCallback */
-
-
-static void ZIP_enumerateFiles(PHYSFS_Dir *opaque, const char *dname,
- int omitSymLinks, PHYSFS_EnumFilesCallback cb,
- const char *origdir, void *callbackdata)
-{
- ZIPinfo *info = ((ZIPinfo *) opaque);
- PHYSFS_sint32 dlen, dlen_inc;
- PHYSFS_sint64 i, max;
-
- i = zip_find_start_of_dir(info, dname, 0);
- if (i == -1) /* no such directory. */
- return;
-
- dlen = (PHYSFS_sint32) strlen(dname);
- if ((dlen > 0) && (dname[dlen - 1] == '/')) /* ignore trailing slash. */
- dlen--;
-
- dlen_inc = ((dlen > 0) ? 1 : 0) + dlen;
- max = (PHYSFS_sint64) info->entryCount;
- while (i < max)
- {
- char *e = info->entries[i].name;
- if ((dlen) && ((strncmp(e, dname, dlen) != 0) || (e[dlen] != '/')))
- break; /* past end of this dir; we're done. */
-
- if ((omitSymLinks) && (zip_entry_is_symlink(&info->entries[i])))
- i++;
- else
- {
- char *add = e + dlen_inc;
- char *ptr = strchr(add, '/');
- PHYSFS_sint32 ln = (PHYSFS_sint32) ((ptr) ? ptr-add : strlen(add));
- doEnumCallback(cb, callbackdata, origdir, add, ln);
- ln += dlen_inc; /* point past entry to children... */
-
- /* increment counter and skip children of subdirs... */
- while ((++i < max) && (ptr != NULL))
- {
- char *e_new = info->entries[i].name;
- if ((strncmp(e, e_new, ln) != 0) || (e_new[ln] != '/'))
- break;
- } /* while */
- } /* else */
- } /* while */
-} /* ZIP_enumerateFiles */
-
-
-static PHYSFS_Io *zip_get_io(PHYSFS_Io *io, ZIPinfo *inf, ZIPentry *entry)
-{
- int success;
- PHYSFS_Io *retval = io->duplicate(io);
- BAIL_IF_MACRO(!retval, ERRPASS, NULL);
-
- /* !!! FIXME: if you open a dir here, it should bail ERR_NOT_A_FILE */
-
- /* (inf) can be NULL if we already resolved. */
- success = (inf == NULL) || zip_resolve(retval, inf, entry);
- if (success)
- {
- PHYSFS_sint64 offset;
- offset = ((entry->symlink) ? entry->symlink->offset : entry->offset);
- success = retval->seek(retval, offset);
- } /* if */
-
- if (!success)
- {
- retval->destroy(retval);
- retval = NULL;
- } /* if */
-
- return retval;
-} /* zip_get_io */
-
-
-static PHYSFS_Io *ZIP_openRead(PHYSFS_Dir *opaque, const char *fnm,
- int *fileExists)
-{
- PHYSFS_Io *retval = NULL;
- ZIPinfo *info = (ZIPinfo *) opaque;
- ZIPentry *entry = zip_find_entry(info, fnm, NULL);
- ZIPfileinfo *finfo = NULL;
-
- *fileExists = (entry != NULL);
- BAIL_IF_MACRO(!entry, ERRPASS, NULL);
-
- retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
- GOTO_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
-
- finfo = (ZIPfileinfo *) allocator.Malloc(sizeof (ZIPfileinfo));
- GOTO_IF_MACRO(!finfo, PHYSFS_ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
- memset(finfo, '\0', sizeof (ZIPfileinfo));
-
- finfo->io = zip_get_io(info->io, info, entry);
- GOTO_IF_MACRO(!finfo->io, ERRPASS, ZIP_openRead_failed);
- finfo->entry = ((entry->symlink != NULL) ? entry->symlink : entry);
- initializeZStream(&finfo->stream);
-
- if (finfo->entry->compression_method != COMPMETH_NONE)
- {
- finfo->buffer = (PHYSFS_uint8 *) allocator.Malloc(ZIP_READBUFSIZE);
- if (!finfo->buffer)
- GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
- else if (zlib_err(inflateInit2(&finfo->stream, -MAX_WBITS)) != Z_OK)
- goto ZIP_openRead_failed;
- } /* if */
-
- memcpy(retval, &ZIP_Io, sizeof (PHYSFS_Io));
- retval->opaque = finfo;
-
- return retval;
-
-ZIP_openRead_failed:
- if (finfo != NULL)
- {
- if (finfo->io != NULL)
- finfo->io->destroy(finfo->io);
-
- if (finfo->buffer != NULL)
- {
- allocator.Free(finfo->buffer);
- inflateEnd(&finfo->stream);
- } /* if */
-
- allocator.Free(finfo);
- } /* if */
-
- if (retval != NULL)
- allocator.Free(retval);
-
- return NULL;
-} /* ZIP_openRead */
-
-
-static PHYSFS_Io *ZIP_openWrite(PHYSFS_Dir *opaque, const char *filename)
-{
- BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
-} /* ZIP_openWrite */
-
-
-static PHYSFS_Io *ZIP_openAppend(PHYSFS_Dir *opaque, const char *filename)
-{
- BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
-} /* ZIP_openAppend */
-
-
-static void ZIP_closeArchive(PHYSFS_Dir *opaque)
-{
- ZIPinfo *zi = (ZIPinfo *) (opaque);
- zi->io->destroy(zi->io);
- zip_free_entries(zi->entries, zi->entryCount);
- allocator.Free(zi);
-} /* ZIP_closeArchive */
-
-
-static int ZIP_remove(PHYSFS_Dir *opaque, const char *name)
-{
- BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
-} /* ZIP_remove */
-
-
-static int ZIP_mkdir(PHYSFS_Dir *opaque, const char *name)
-{
- BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
-} /* ZIP_mkdir */
-
-
-static int ZIP_stat(PHYSFS_Dir *opaque, const char *filename, int *exists,
- PHYSFS_Stat *stat)
-{
- int isDir = 0;
- const ZIPinfo *info = (const ZIPinfo *) opaque;
- const ZIPentry *entry = zip_find_entry(info, filename, &isDir);
-
- /* !!! FIXME: does this need to resolve entries here? */
-
- *exists = isDir || (entry != 0);
- if (!*exists)
- return 0;
-
- if (isDir)
- {
- stat->filesize = 0;
- stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
- } /* if */
-
- else if (zip_entry_is_symlink(entry))
- {
- stat->filesize = 0;
- stat->filetype = PHYSFS_FILETYPE_SYMLINK;
- } /* else if */
-
- else
- {
- stat->filesize = (PHYSFS_sint64) entry->uncompressed_size;
- stat->filetype = PHYSFS_FILETYPE_REGULAR;
- } /* else */
-
- stat->modtime = ((entry) ? entry->last_mod_time : 0);
- stat->createtime = stat->modtime;
- stat->accesstime = 0;
- stat->readonly = 1; /* .zip files are always read only */
-
- return 1;
-} /* ZIP_stat */
-
-
-const PHYSFS_Archiver __PHYSFS_Archiver_ZIP =
-{
- {
- "ZIP",
- "PkZip/WinZip/Info-Zip compatible",
- "Ryan C. Gordon ",
- "http://icculus.org/physfs/",
- },
- ZIP_openArchive, /* openArchive() method */
- ZIP_enumerateFiles, /* enumerateFiles() method */
- ZIP_openRead, /* openRead() method */
- ZIP_openWrite, /* openWrite() method */
- ZIP_openAppend, /* openAppend() method */
- ZIP_remove, /* remove() method */
- ZIP_mkdir, /* mkdir() method */
- ZIP_closeArchive, /* closeArchive() method */
- ZIP_stat /* stat() method */
-};
-
-#endif /* defined PHYSFS_SUPPORTS_ZIP */
-
-/* end of zip.c ... */
-
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/src/physfs.c
--- a/misc/physfs/src/physfs.c Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2744 +0,0 @@
-/**
- * PhysicsFS; a portable, flexible file i/o abstraction.
- *
- * Documentation is in physfs.h. It's verbose, honest. :)
- *
- * Please see the file LICENSE.txt in the source's root directory.
- *
- * This file written by Ryan C. Gordon.
- */
-
-/* !!! FIXME: ERR_PAST_EOF shouldn't trigger for reads. Just return zero. */
-/* !!! FIXME: use snprintf(), not sprintf(). */
-
-#define __PHYSICSFS_INTERNAL__
-#include "physfs_internal.h"
-
-
-typedef struct __PHYSFS_DIRHANDLE__
-{
- void *opaque; /* Instance data unique to the archiver. */
- char *dirName; /* Path to archive in platform-dependent notation. */
- char *mountPoint; /* Mountpoint in virtual file tree. */
- const PHYSFS_Archiver *funcs; /* Ptr to archiver info for this handle. */
- struct __PHYSFS_DIRHANDLE__ *next; /* linked list stuff. */
-} DirHandle;
-
-
-typedef struct __PHYSFS_FILEHANDLE__
-{
- PHYSFS_Io *io; /* Instance data unique to the archiver for this file. */
- PHYSFS_uint8 forReading; /* Non-zero if reading, zero if write/append */
- const DirHandle *dirHandle; /* Archiver instance that created this */
- PHYSFS_uint8 *buffer; /* Buffer, if set (NULL otherwise). Don't touch! */
- PHYSFS_uint32 bufsize; /* Bufsize, if set (0 otherwise). Don't touch! */
- PHYSFS_uint32 buffill; /* Buffer fill size. Don't touch! */
- PHYSFS_uint32 bufpos; /* Buffer position. Don't touch! */
- struct __PHYSFS_FILEHANDLE__ *next; /* linked list stuff. */
-} FileHandle;
-
-
-typedef struct __PHYSFS_ERRSTATETYPE__
-{
- void *tid;
- PHYSFS_ErrorCode code;
- struct __PHYSFS_ERRSTATETYPE__ *next;
-} ErrState;
-
-
-/* The various i/o drivers...some of these may not be compiled in. */
-extern const PHYSFS_Archiver __PHYSFS_Archiver_ZIP;
-extern const PHYSFS_Archiver __PHYSFS_Archiver_LZMA;
-extern const PHYSFS_Archiver __PHYSFS_Archiver_GRP;
-extern const PHYSFS_Archiver __PHYSFS_Archiver_QPAK;
-extern const PHYSFS_Archiver __PHYSFS_Archiver_HOG;
-extern const PHYSFS_Archiver __PHYSFS_Archiver_MVL;
-extern const PHYSFS_Archiver __PHYSFS_Archiver_WAD;
-extern const PHYSFS_Archiver __PHYSFS_Archiver_DIR;
-extern const PHYSFS_Archiver __PHYSFS_Archiver_ISO9660;
-
-static const PHYSFS_Archiver *staticArchivers[] =
-{
-#if PHYSFS_SUPPORTS_ZIP
- &__PHYSFS_Archiver_ZIP,
-#endif
-#if PHYSFS_SUPPORTS_7Z
- &__PHYSFS_Archiver_LZMA,
-#endif
-#if PHYSFS_SUPPORTS_GRP
- &__PHYSFS_Archiver_GRP,
-#endif
-#if PHYSFS_SUPPORTS_QPAK
- &__PHYSFS_Archiver_QPAK,
-#endif
-#if PHYSFS_SUPPORTS_HOG
- &__PHYSFS_Archiver_HOG,
-#endif
-#if PHYSFS_SUPPORTS_MVL
- &__PHYSFS_Archiver_MVL,
-#endif
-#if PHYSFS_SUPPORTS_WAD
- &__PHYSFS_Archiver_WAD,
-#endif
-#if PHYSFS_SUPPORTS_ISO9660
- &__PHYSFS_Archiver_ISO9660,
-#endif
- NULL
-};
-
-
-
-/* General PhysicsFS state ... */
-static int initialized = 0;
-static ErrState *errorStates = NULL;
-static DirHandle *searchPath = NULL;
-static DirHandle *writeDir = NULL;
-static FileHandle *openWriteList = NULL;
-static FileHandle *openReadList = NULL;
-static char *baseDir = NULL;
-static char *userDir = NULL;
-static char *prefDir = NULL;
-static int allowSymLinks = 0;
-static const PHYSFS_Archiver **archivers = NULL;
-static const PHYSFS_ArchiveInfo **archiveInfo = NULL;
-
-/* mutexes ... */
-static void *errorLock = NULL; /* protects error message list. */
-static void *stateLock = NULL; /* protects other PhysFS static state. */
-
-/* allocator ... */
-static int externalAllocator = 0;
-PHYSFS_Allocator allocator;
-
-
-/* PHYSFS_Io implementation for i/o to physical filesystem... */
-
-/* !!! FIXME: maybe refcount the paths in a string pool? */
-typedef struct __PHYSFS_NativeIoInfo
-{
- void *handle;
- const char *path;
- int mode; /* 'r', 'w', or 'a' */
-} NativeIoInfo;
-
-static PHYSFS_sint64 nativeIo_read(PHYSFS_Io *io, void *buf, PHYSFS_uint64 len)
-{
- NativeIoInfo *info = (NativeIoInfo *) io->opaque;
- return __PHYSFS_platformRead(info->handle, buf, len);
-} /* nativeIo_read */
-
-static PHYSFS_sint64 nativeIo_write(PHYSFS_Io *io, const void *buffer,
- PHYSFS_uint64 len)
-{
- NativeIoInfo *info = (NativeIoInfo *) io->opaque;
- return __PHYSFS_platformWrite(info->handle, buffer, len);
-} /* nativeIo_write */
-
-static int nativeIo_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
-{
- NativeIoInfo *info = (NativeIoInfo *) io->opaque;
- return __PHYSFS_platformSeek(info->handle, offset);
-} /* nativeIo_seek */
-
-static PHYSFS_sint64 nativeIo_tell(PHYSFS_Io *io)
-{
- NativeIoInfo *info = (NativeIoInfo *) io->opaque;
- return __PHYSFS_platformTell(info->handle);
-} /* nativeIo_tell */
-
-static PHYSFS_sint64 nativeIo_length(PHYSFS_Io *io)
-{
- NativeIoInfo *info = (NativeIoInfo *) io->opaque;
- return __PHYSFS_platformFileLength(info->handle);
-} /* nativeIo_length */
-
-static PHYSFS_Io *nativeIo_duplicate(PHYSFS_Io *io)
-{
- NativeIoInfo *info = (NativeIoInfo *) io->opaque;
- return __PHYSFS_createNativeIo(info->path, info->mode);
-} /* nativeIo_duplicate */
-
-static int nativeIo_flush(PHYSFS_Io *io)
-{
- return __PHYSFS_platformFlush(io->opaque);
-} /* nativeIo_flush */
-
-static void nativeIo_destroy(PHYSFS_Io *io)
-{
- NativeIoInfo *info = (NativeIoInfo *) io->opaque;
- __PHYSFS_platformClose(info->handle);
- allocator.Free((void *) info->path);
- allocator.Free(info);
- allocator.Free(io);
-} /* nativeIo_destroy */
-
-static const PHYSFS_Io __PHYSFS_nativeIoInterface =
-{
- CURRENT_PHYSFS_IO_API_VERSION, NULL,
- nativeIo_read,
- nativeIo_write,
- nativeIo_seek,
- nativeIo_tell,
- nativeIo_length,
- nativeIo_duplicate,
- nativeIo_flush,
- nativeIo_destroy
-};
-
-PHYSFS_Io *__PHYSFS_createNativeIo(const char *path, const int mode)
-{
- PHYSFS_Io *io = NULL;
- NativeIoInfo *info = NULL;
- void *handle = NULL;
- char *pathdup = NULL;
-
- assert((mode == 'r') || (mode == 'w') || (mode == 'a'));
-
- io = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
- GOTO_IF_MACRO(!io, PHYSFS_ERR_OUT_OF_MEMORY, createNativeIo_failed);
- info = (NativeIoInfo *) allocator.Malloc(sizeof (NativeIoInfo));
- GOTO_IF_MACRO(!info, PHYSFS_ERR_OUT_OF_MEMORY, createNativeIo_failed);
- pathdup = (char *) allocator.Malloc(strlen(path) + 1);
- GOTO_IF_MACRO(!pathdup, PHYSFS_ERR_OUT_OF_MEMORY, createNativeIo_failed);
-
- if (mode == 'r')
- handle = __PHYSFS_platformOpenRead(path);
- else if (mode == 'w')
- handle = __PHYSFS_platformOpenWrite(path);
- else if (mode == 'a')
- handle = __PHYSFS_platformOpenAppend(path);
-
- GOTO_IF_MACRO(!handle, ERRPASS, createNativeIo_failed);
-
- strcpy(pathdup, path);
- info->handle = handle;
- info->path = pathdup;
- info->mode = mode;
- memcpy(io, &__PHYSFS_nativeIoInterface, sizeof (*io));
- io->opaque = info;
- return io;
-
-createNativeIo_failed:
- if (handle != NULL) __PHYSFS_platformClose(handle);
- if (pathdup != NULL) allocator.Free(pathdup);
- if (info != NULL) allocator.Free(info);
- if (io != NULL) allocator.Free(io);
- return NULL;
-} /* __PHYSFS_createNativeIo */
-
-
-/* PHYSFS_Io implementation for i/o to a memory buffer... */
-
-typedef struct __PHYSFS_MemoryIoInfo
-{
- const PHYSFS_uint8 *buf;
- PHYSFS_uint64 len;
- PHYSFS_uint64 pos;
- PHYSFS_Io *parent;
- volatile PHYSFS_uint32 refcount;
- void (*destruct)(void *);
-} MemoryIoInfo;
-
-static PHYSFS_sint64 memoryIo_read(PHYSFS_Io *io, void *buf, PHYSFS_uint64 len)
-{
- MemoryIoInfo *info = (MemoryIoInfo *) io->opaque;
- const PHYSFS_uint64 avail = info->len - info->pos;
- assert(avail <= info->len);
-
- if (avail == 0)
- return 0; /* we're at EOF; nothing to do. */
-
- if (len > avail)
- len = avail;
-
- memcpy(buf, info->buf + info->pos, (size_t) len);
- info->pos += len;
- return len;
-} /* memoryIo_read */
-
-static PHYSFS_sint64 memoryIo_write(PHYSFS_Io *io, const void *buffer,
- PHYSFS_uint64 len)
-{
- BAIL_MACRO(PHYSFS_ERR_OPEN_FOR_READING, -1);
-} /* memoryIo_write */
-
-static int memoryIo_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
-{
- MemoryIoInfo *info = (MemoryIoInfo *) io->opaque;
- BAIL_IF_MACRO(offset > info->len, PHYSFS_ERR_PAST_EOF, 0);
- info->pos = offset;
- return 1;
-} /* memoryIo_seek */
-
-static PHYSFS_sint64 memoryIo_tell(PHYSFS_Io *io)
-{
- const MemoryIoInfo *info = (MemoryIoInfo *) io->opaque;
- return (PHYSFS_sint64) info->pos;
-} /* memoryIo_tell */
-
-static PHYSFS_sint64 memoryIo_length(PHYSFS_Io *io)
-{
- const MemoryIoInfo *info = (MemoryIoInfo *) io->opaque;
- return (PHYSFS_sint64) info->len;
-} /* memoryIo_length */
-
-static PHYSFS_Io *memoryIo_duplicate(PHYSFS_Io *io)
-{
- MemoryIoInfo *info = (MemoryIoInfo *) io->opaque;
- MemoryIoInfo *newinfo = NULL;
- PHYSFS_Io *parent = info->parent;
- PHYSFS_Io *retval = NULL;
-
- /* avoid deep copies. */
- assert((!parent) || (!((MemoryIoInfo *) parent->opaque)->parent) );
-
- /* share the buffer between duplicates. */
- if (parent != NULL) /* dup the parent, increment its refcount. */
- return parent->duplicate(parent);
-
- /* we're the parent. */
-
- retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
- BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
- newinfo = (MemoryIoInfo *) allocator.Malloc(sizeof (MemoryIoInfo));
- if (!newinfo)
- {
- allocator.Free(retval);
- BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
- } /* if */
-
- /* !!! FIXME: want lockless atomic increment. */
- __PHYSFS_platformGrabMutex(stateLock);
- info->refcount++;
- __PHYSFS_platformReleaseMutex(stateLock);
-
- memset(newinfo, '\0', sizeof (*info));
- newinfo->buf = info->buf;
- newinfo->len = info->len;
- newinfo->pos = 0;
- newinfo->parent = io;
- newinfo->refcount = 0;
- newinfo->destruct = NULL;
-
- memcpy(retval, io, sizeof (*retval));
- retval->opaque = newinfo;
- return retval;
-} /* memoryIo_duplicate */
-
-static int memoryIo_flush(PHYSFS_Io *io) { return 1; /* it's read-only. */ }
-
-static void memoryIo_destroy(PHYSFS_Io *io)
-{
- MemoryIoInfo *info = (MemoryIoInfo *) io->opaque;
- PHYSFS_Io *parent = info->parent;
- int should_die = 0;
-
- if (parent != NULL)
- {
- assert(info->buf == ((MemoryIoInfo *) info->parent->opaque)->buf);
- assert(info->len == ((MemoryIoInfo *) info->parent->opaque)->len);
- assert(info->refcount == 0);
- assert(info->destruct == NULL);
- allocator.Free(info);
- allocator.Free(io);
- parent->destroy(parent); /* decrements refcount. */
- return;
- } /* if */
-
- /* we _are_ the parent. */
- assert(info->refcount > 0); /* even in a race, we hold a reference. */
-
- /* !!! FIXME: want lockless atomic decrement. */
- __PHYSFS_platformGrabMutex(stateLock);
- info->refcount--;
- should_die = (info->refcount == 0);
- __PHYSFS_platformReleaseMutex(stateLock);
-
- if (should_die)
- {
- void (*destruct)(void *) = info->destruct;
- void *buf = (void *) info->buf;
- io->opaque = NULL; /* kill this here in case of race. */
- allocator.Free(info);
- allocator.Free(io);
- if (destruct != NULL)
- destruct(buf);
- } /* if */
-} /* memoryIo_destroy */
-
-
-static const PHYSFS_Io __PHYSFS_memoryIoInterface =
-{
- CURRENT_PHYSFS_IO_API_VERSION, NULL,
- memoryIo_read,
- memoryIo_write,
- memoryIo_seek,
- memoryIo_tell,
- memoryIo_length,
- memoryIo_duplicate,
- memoryIo_flush,
- memoryIo_destroy
-};
-
-PHYSFS_Io *__PHYSFS_createMemoryIo(const void *buf, PHYSFS_uint64 len,
- void (*destruct)(void *))
-{
- PHYSFS_Io *io = NULL;
- MemoryIoInfo *info = NULL;
-
- io = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
- GOTO_IF_MACRO(!io, PHYSFS_ERR_OUT_OF_MEMORY, createMemoryIo_failed);
- info = (MemoryIoInfo *) allocator.Malloc(sizeof (MemoryIoInfo));
- GOTO_IF_MACRO(!info, PHYSFS_ERR_OUT_OF_MEMORY, createMemoryIo_failed);
-
- memset(info, '\0', sizeof (*info));
- info->buf = (const PHYSFS_uint8 *) buf;
- info->len = len;
- info->pos = 0;
- info->parent = NULL;
- info->refcount = 1;
- info->destruct = destruct;
-
- memcpy(io, &__PHYSFS_memoryIoInterface, sizeof (*io));
- io->opaque = info;
- return io;
-
-createMemoryIo_failed:
- if (info != NULL) allocator.Free(info);
- if (io != NULL) allocator.Free(io);
- return NULL;
-} /* __PHYSFS_createMemoryIo */
-
-
-/* PHYSFS_Io implementation for i/o to a PHYSFS_File... */
-
-static PHYSFS_sint64 handleIo_read(PHYSFS_Io *io, void *buf, PHYSFS_uint64 len)
-{
- return PHYSFS_readBytes((PHYSFS_File *) io->opaque, buf, len);
-} /* handleIo_read */
-
-static PHYSFS_sint64 handleIo_write(PHYSFS_Io *io, const void *buffer,
- PHYSFS_uint64 len)
-{
- return PHYSFS_writeBytes((PHYSFS_File *) io->opaque, buffer, len);
-} /* handleIo_write */
-
-static int handleIo_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
-{
- return PHYSFS_seek((PHYSFS_File *) io->opaque, offset);
-} /* handleIo_seek */
-
-static PHYSFS_sint64 handleIo_tell(PHYSFS_Io *io)
-{
- return PHYSFS_tell((PHYSFS_File *) io->opaque);
-} /* handleIo_tell */
-
-static PHYSFS_sint64 handleIo_length(PHYSFS_Io *io)
-{
- return PHYSFS_fileLength((PHYSFS_File *) io->opaque);
-} /* handleIo_length */
-
-static PHYSFS_Io *handleIo_duplicate(PHYSFS_Io *io)
-{
- /*
- * There's no duplicate at the PHYSFS_File level, so we break the
- * abstraction. We're allowed to: we're physfs.c!
- */
- FileHandle *origfh = (FileHandle *) io->opaque;
- FileHandle *newfh = (FileHandle *) allocator.Malloc(sizeof (FileHandle));
- PHYSFS_Io *retval = NULL;
-
- GOTO_IF_MACRO(!newfh, PHYSFS_ERR_OUT_OF_MEMORY, handleIo_dupe_failed);
- memset(newfh, '\0', sizeof (*newfh));
-
- retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
- GOTO_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, handleIo_dupe_failed);
-
-#if 0 /* we don't buffer the duplicate, at least not at the moment. */
- if (origfh->buffer != NULL)
- {
- newfh->buffer = (PHYSFS_uint8 *) allocator.Malloc(origfh->bufsize);
- if (!newfh->buffer)
- GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, handleIo_dupe_failed);
- newfh->bufsize = origfh->bufsize;
- } /* if */
-#endif
-
- newfh->io = origfh->io->duplicate(origfh->io);
- GOTO_IF_MACRO(!newfh->io, ERRPASS, handleIo_dupe_failed);
-
- newfh->forReading = origfh->forReading;
- newfh->dirHandle = origfh->dirHandle;
-
- __PHYSFS_platformGrabMutex(stateLock);
- if (newfh->forReading)
- {
- newfh->next = openReadList;
- openReadList = newfh;
- } /* if */
- else
- {
- newfh->next = openWriteList;
- openWriteList = newfh;
- } /* else */
- __PHYSFS_platformReleaseMutex(stateLock);
-
- memcpy(retval, io, sizeof (PHYSFS_Io));
- retval->opaque = newfh;
- return retval;
-
-handleIo_dupe_failed:
- if (newfh)
- {
- if (newfh->io != NULL) newfh->io->destroy(newfh->io);
- if (newfh->buffer != NULL) allocator.Free(newfh->buffer);
- allocator.Free(newfh);
- } /* if */
-
- return NULL;
-} /* handleIo_duplicate */
-
-static int handleIo_flush(PHYSFS_Io *io)
-{
- return PHYSFS_flush((PHYSFS_File *) io->opaque);
-} /* handleIo_flush */
-
-static void handleIo_destroy(PHYSFS_Io *io)
-{
- if (io->opaque != NULL)
- PHYSFS_close((PHYSFS_File *) io->opaque);
- allocator.Free(io);
-} /* handleIo_destroy */
-
-static const PHYSFS_Io __PHYSFS_handleIoInterface =
-{
- CURRENT_PHYSFS_IO_API_VERSION, NULL,
- handleIo_read,
- handleIo_write,
- handleIo_seek,
- handleIo_tell,
- handleIo_length,
- handleIo_duplicate,
- handleIo_flush,
- handleIo_destroy
-};
-
-static PHYSFS_Io *__PHYSFS_createHandleIo(PHYSFS_File *f)
-{
- PHYSFS_Io *io = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
- BAIL_IF_MACRO(!io, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
- memcpy(io, &__PHYSFS_handleIoInterface, sizeof (*io));
- io->opaque = f;
- return io;
-} /* __PHYSFS_createHandleIo */
-
-
-/* functions ... */
-
-typedef struct
-{
- char **list;
- PHYSFS_uint32 size;
- PHYSFS_ErrorCode errcode;
-} EnumStringListCallbackData;
-
-static void enumStringListCallback(void *data, const char *str)
-{
- void *ptr;
- char *newstr;
- EnumStringListCallbackData *pecd = (EnumStringListCallbackData *) data;
-
- if (pecd->errcode)
- return;
-
- ptr = allocator.Realloc(pecd->list, (pecd->size + 2) * sizeof (char *));
- newstr = (char *) allocator.Malloc(strlen(str) + 1);
- if (ptr != NULL)
- pecd->list = (char **) ptr;
-
- if ((ptr == NULL) || (newstr == NULL))
- {
- pecd->errcode = PHYSFS_ERR_OUT_OF_MEMORY;
- pecd->list[pecd->size] = NULL;
- PHYSFS_freeList(pecd->list);
- return;
- } /* if */
-
- strcpy(newstr, str);
- pecd->list[pecd->size] = newstr;
- pecd->size++;
-} /* enumStringListCallback */
-
-
-static char **doEnumStringList(void (*func)(PHYSFS_StringCallback, void *))
-{
- EnumStringListCallbackData ecd;
- memset(&ecd, '\0', sizeof (ecd));
- ecd.list = (char **) allocator.Malloc(sizeof (char *));
- BAIL_IF_MACRO(!ecd.list, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
- func(enumStringListCallback, &ecd);
-
- if (ecd.errcode)
- {
- __PHYSFS_setError(ecd.errcode);
- return NULL;
- } /* if */
-
- ecd.list[ecd.size] = NULL;
- return ecd.list;
-} /* doEnumStringList */
-
-
-static void __PHYSFS_bubble_sort(void *a, size_t lo, size_t hi,
- int (*cmpfn)(void *, size_t, size_t),
- void (*swapfn)(void *, size_t, size_t))
-{
- size_t i;
- int sorted;
-
- do
- {
- sorted = 1;
- for (i = lo; i < hi; i++)
- {
- if (cmpfn(a, i, i + 1) > 0)
- {
- swapfn(a, i, i + 1);
- sorted = 0;
- } /* if */
- } /* for */
- } while (!sorted);
-} /* __PHYSFS_bubble_sort */
-
-
-static void __PHYSFS_quick_sort(void *a, size_t lo, size_t hi,
- int (*cmpfn)(void *, size_t, size_t),
- void (*swapfn)(void *, size_t, size_t))
-{
- size_t i;
- size_t j;
- size_t v;
-
- if ((hi - lo) <= PHYSFS_QUICKSORT_THRESHOLD)
- __PHYSFS_bubble_sort(a, lo, hi, cmpfn, swapfn);
- else
- {
- i = (hi + lo) / 2;
-
- if (cmpfn(a, lo, i) > 0) swapfn(a, lo, i);
- if (cmpfn(a, lo, hi) > 0) swapfn(a, lo, hi);
- if (cmpfn(a, i, hi) > 0) swapfn(a, i, hi);
-
- j = hi - 1;
- swapfn(a, i, j);
- i = lo;
- v = j;
- while (1)
- {
- while(cmpfn(a, ++i, v) < 0) { /* do nothing */ }
- while(cmpfn(a, --j, v) > 0) { /* do nothing */ }
- if (j < i)
- break;
- swapfn(a, i, j);
- } /* while */
- if (i != (hi-1))
- swapfn(a, i, hi-1);
- __PHYSFS_quick_sort(a, lo, j, cmpfn, swapfn);
- __PHYSFS_quick_sort(a, i+1, hi, cmpfn, swapfn);
- } /* else */
-} /* __PHYSFS_quick_sort */
-
-
-void __PHYSFS_sort(void *entries, size_t max,
- int (*cmpfn)(void *, size_t, size_t),
- void (*swapfn)(void *, size_t, size_t))
-{
- /*
- * Quicksort w/ Bubblesort fallback algorithm inspired by code from here:
- * http://www.cs.ubc.ca/spider/harrison/Java/sorting-demo.html
- */
- if (max > 0)
- __PHYSFS_quick_sort(entries, 0, max - 1, cmpfn, swapfn);
-} /* __PHYSFS_sort */
-
-
-static ErrState *findErrorForCurrentThread(void)
-{
- ErrState *i;
- void *tid;
-
- if (errorLock != NULL)
- __PHYSFS_platformGrabMutex(errorLock);
-
- if (errorStates != NULL)
- {
- tid = __PHYSFS_platformGetThreadID();
-
- for (i = errorStates; i != NULL; i = i->next)
- {
- if (i->tid == tid)
- {
- if (errorLock != NULL)
- __PHYSFS_platformReleaseMutex(errorLock);
- return i;
- } /* if */
- } /* for */
- } /* if */
-
- if (errorLock != NULL)
- __PHYSFS_platformReleaseMutex(errorLock);
-
- return NULL; /* no error available. */
-} /* findErrorForCurrentThread */
-
-
-void __PHYSFS_setError(const PHYSFS_ErrorCode errcode)
-{
- ErrState *err;
-
- if (!errcode)
- return;
-
- err = findErrorForCurrentThread();
- if (err == NULL)
- {
- err = (ErrState *) allocator.Malloc(sizeof (ErrState));
- if (err == NULL)
- return; /* uhh...? */
-
- memset(err, '\0', sizeof (ErrState));
- err->tid = __PHYSFS_platformGetThreadID();
-
- if (errorLock != NULL)
- __PHYSFS_platformGrabMutex(errorLock);
-
- err->next = errorStates;
- errorStates = err;
-
- if (errorLock != NULL)
- __PHYSFS_platformReleaseMutex(errorLock);
- } /* if */
-
- err->code = errcode;
-} /* __PHYSFS_setError */
-
-
-PHYSFS_ErrorCode PHYSFS_getLastErrorCode(void)
-{
- ErrState *err = findErrorForCurrentThread();
- const PHYSFS_ErrorCode retval = (err) ? err->code : PHYSFS_ERR_OK;
- if (err)
- err->code = PHYSFS_ERR_OK;
- return retval;
-} /* PHYSFS_getLastErrorCode */
-
-
-PHYSFS_DECL const char *PHYSFS_getErrorByCode(PHYSFS_ErrorCode code)
-{
- switch (code)
- {
- case PHYSFS_ERR_OK: return "no error";
- case PHYSFS_ERR_OTHER_ERROR: return "unknown error";
- case PHYSFS_ERR_OUT_OF_MEMORY: return "out of memory";
- case PHYSFS_ERR_NOT_INITIALIZED: return "not initialized";
- case PHYSFS_ERR_IS_INITIALIZED: return "already initialized";
- case PHYSFS_ERR_ARGV0_IS_NULL: return "argv[0] is NULL";
- case PHYSFS_ERR_UNSUPPORTED: return "unsupported";
- case PHYSFS_ERR_PAST_EOF: return "past end of file";
- case PHYSFS_ERR_FILES_STILL_OPEN: return "files still open";
- case PHYSFS_ERR_INVALID_ARGUMENT: return "invalid argument";
- case PHYSFS_ERR_NOT_MOUNTED: return "not mounted";
- case PHYSFS_ERR_NO_SUCH_PATH: return "no such path";
- case PHYSFS_ERR_SYMLINK_FORBIDDEN: return "symlinks are forbidden";
- case PHYSFS_ERR_NO_WRITE_DIR: return "write directory is not set";
- case PHYSFS_ERR_OPEN_FOR_READING: return "file open for reading";
- case PHYSFS_ERR_OPEN_FOR_WRITING: return "file open for writing";
- case PHYSFS_ERR_NOT_A_FILE: return "not a file";
- case PHYSFS_ERR_READ_ONLY: return "read-only filesystem";
- case PHYSFS_ERR_CORRUPT: return "corrupted";
- case PHYSFS_ERR_SYMLINK_LOOP: return "infinite symbolic link loop";
- case PHYSFS_ERR_IO: return "i/o error";
- case PHYSFS_ERR_PERMISSION: return "permission denied";
- case PHYSFS_ERR_NO_SPACE: return "no space available for writing";
- case PHYSFS_ERR_BAD_FILENAME: return "filename is illegal or insecure";
- case PHYSFS_ERR_BUSY: return "tried to modify a file the OS needs";
- case PHYSFS_ERR_DIR_NOT_EMPTY: return "directory isn't empty";
- case PHYSFS_ERR_OS_ERROR: return "OS reported an error";
- } /* switch */
-
- return NULL; /* don't know this error code. */
-} /* PHYSFS_getErrorByCode */
-
-
-void PHYSFS_setErrorCode(PHYSFS_ErrorCode code)
-{
- __PHYSFS_setError(code);
-} /* PHYSFS_setErrorCode */
-
-
-const char *PHYSFS_getLastError(void)
-{
- const PHYSFS_ErrorCode err = PHYSFS_getLastErrorCode();
- return (err) ? PHYSFS_getErrorByCode(err) : NULL;
-} /* PHYSFS_getLastError */
-
-
-/* MAKE SURE that errorLock is held before calling this! */
-static void freeErrorStates(void)
-{
- ErrState *i;
- ErrState *next;
-
- for (i = errorStates; i != NULL; i = next)
- {
- next = i->next;
- allocator.Free(i);
- } /* for */
-
- errorStates = NULL;
-} /* freeErrorStates */
-
-
-void PHYSFS_getLinkedVersion(PHYSFS_Version *ver)
-{
- if (ver != NULL)
- {
- ver->major = PHYSFS_VER_MAJOR;
- ver->minor = PHYSFS_VER_MINOR;
- ver->patch = PHYSFS_VER_PATCH;
- } /* if */
-} /* PHYSFS_getLinkedVersion */
-
-
-static const char *find_filename_extension(const char *fname)
-{
- const char *retval = NULL;
- if (fname != NULL)
- {
- const char *p = strchr(fname, '.');
- retval = p;
-
- while (p != NULL)
- {
- p = strchr(p + 1, '.');
- if (p != NULL)
- retval = p;
- } /* while */
-
- if (retval != NULL)
- retval++; /* skip '.' */
- } /* if */
-
- return retval;
-} /* find_filename_extension */
-
-
-static DirHandle *tryOpenDir(PHYSFS_Io *io, const PHYSFS_Archiver *funcs,
- const char *d, int forWriting)
-{
- DirHandle *retval = NULL;
- void *opaque = NULL;
-
- if (io != NULL)
- BAIL_IF_MACRO(!io->seek(io, 0), ERRPASS, NULL);
-
- opaque = funcs->openArchive(io, d, forWriting);
- if (opaque != NULL)
- {
- retval = (DirHandle *) allocator.Malloc(sizeof (DirHandle));
- if (retval == NULL)
- funcs->closeArchive(opaque);
- else
- {
- memset(retval, '\0', sizeof (DirHandle));
- retval->mountPoint = NULL;
- retval->funcs = funcs;
- retval->opaque = opaque;
- } /* else */
- } /* if */
-
- return retval;
-} /* tryOpenDir */
-
-
-static DirHandle *openDirectory(PHYSFS_Io *io, const char *d, int forWriting)
-{
- DirHandle *retval = NULL;
- const PHYSFS_Archiver **i;
- const char *ext;
-
- assert((io != NULL) || (d != NULL));
-
- if (io == NULL)
- {
- /* DIR gets first shot (unlike the rest, it doesn't deal with files). */
- retval = tryOpenDir(io, &__PHYSFS_Archiver_DIR, d, forWriting);
- if (retval != NULL)
- return retval;
-
- io = __PHYSFS_createNativeIo(d, forWriting ? 'w' : 'r');
- BAIL_IF_MACRO(!io, ERRPASS, 0);
- } /* if */
-
- ext = find_filename_extension(d);
- if (ext != NULL)
- {
- /* Look for archivers with matching file extensions first... */
- for (i = archivers; (*i != NULL) && (retval == NULL); i++)
- {
- if (__PHYSFS_stricmpASCII(ext, (*i)->info.extension) == 0)
- retval = tryOpenDir(io, *i, d, forWriting);
- } /* for */
-
- /* failing an exact file extension match, try all the others... */
- for (i = archivers; (*i != NULL) && (retval == NULL); i++)
- {
- if (__PHYSFS_stricmpASCII(ext, (*i)->info.extension) != 0)
- retval = tryOpenDir(io, *i, d, forWriting);
- } /* for */
- } /* if */
-
- else /* no extension? Try them all. */
- {
- for (i = archivers; (*i != NULL) && (retval == NULL); i++)
- retval = tryOpenDir(io, *i, d, forWriting);
- } /* else */
-
- BAIL_IF_MACRO(!retval, PHYSFS_ERR_UNSUPPORTED, NULL);
- return retval;
-} /* openDirectory */
-
-
-/*
- * Make a platform-independent path string sane. Doesn't actually check the
- * file hierarchy, it just cleans up the string.
- * (dst) must be a buffer at least as big as (src), as this is where the
- * cleaned up string is deposited.
- * If there are illegal bits in the path (".." entries, etc) then we
- * return zero and (dst) is undefined. Non-zero if the path was sanitized.
- */
-static int sanitizePlatformIndependentPath(const char *src, char *dst)
-{
- char *prev;
- char ch;
-
- while (*src == '/') /* skip initial '/' chars... */
- src++;
-
- prev = dst;
- do
- {
- ch = *(src++);
-
- if ((ch == ':') || (ch == '\\')) /* illegal chars in a physfs path. */
- BAIL_MACRO(PHYSFS_ERR_BAD_FILENAME, 0);
-
- if (ch == '/') /* path separator. */
- {
- *dst = '\0'; /* "." and ".." are illegal pathnames. */
- if ((strcmp(prev, ".") == 0) || (strcmp(prev, "..") == 0))
- BAIL_MACRO(PHYSFS_ERR_BAD_FILENAME, 0);
-
- while (*src == '/') /* chop out doubles... */
- src++;
-
- if (*src == '\0') /* ends with a pathsep? */
- break; /* we're done, don't add final pathsep to dst. */
-
- prev = dst + 1;
- } /* if */
-
- *(dst++) = ch;
- } while (ch != '\0');
-
- return 1;
-} /* sanitizePlatformIndependentPath */
-
-
-/*
- * Figure out if (fname) is part of (h)'s mountpoint. (fname) must be an
- * output from sanitizePlatformIndependentPath(), so that it is in a known
- * state.
- *
- * This only finds legitimate segments of a mountpoint. If the mountpoint is
- * "/a/b/c" and (fname) is "/a/b/c", "/", or "/a/b/c/d", then the results are
- * all zero. "/a/b" will succeed, though.
- */
-static int partOfMountPoint(DirHandle *h, char *fname)
-{
- /* !!! FIXME: This code feels gross. */
- int rc;
- size_t len, mntpntlen;
-
- if (h->mountPoint == NULL)
- return 0;
- else if (*fname == '\0')
- return 1;
-
- len = strlen(fname);
- mntpntlen = strlen(h->mountPoint);
- if (len > mntpntlen) /* can't be a subset of mountpoint. */
- return 0;
-
- /* if true, must be not a match or a complete match, but not a subset. */
- if ((len + 1) == mntpntlen)
- return 0;
-
- rc = strncmp(fname, h->mountPoint, len); /* !!! FIXME: case insensitive? */
- if (rc != 0)
- return 0; /* not a match. */
-
- /* make sure /a/b matches /a/b/ and not /a/bc ... */
- return h->mountPoint[len] == '/';
-} /* partOfMountPoint */
-
-
-static DirHandle *createDirHandle(PHYSFS_Io *io, const char *newDir,
- const char *mountPoint, int forWriting)
-{
- DirHandle *dirHandle = NULL;
- char *tmpmntpnt = NULL;
-
- if (mountPoint != NULL)
- {
- const size_t len = strlen(mountPoint) + 1;
- tmpmntpnt = (char *) __PHYSFS_smallAlloc(len);
- GOTO_IF_MACRO(!tmpmntpnt, PHYSFS_ERR_OUT_OF_MEMORY, badDirHandle);
- if (!sanitizePlatformIndependentPath(mountPoint, tmpmntpnt))
- goto badDirHandle;
- mountPoint = tmpmntpnt; /* sanitized version. */
- } /* if */
-
- dirHandle = openDirectory(io, newDir, forWriting);
- GOTO_IF_MACRO(!dirHandle, ERRPASS, badDirHandle);
-
- if (newDir == NULL)
- dirHandle->dirName = NULL;
- else
- {
- dirHandle->dirName = (char *) allocator.Malloc(strlen(newDir) + 1);
- if (!dirHandle->dirName)
- GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, badDirHandle);
- strcpy(dirHandle->dirName, newDir);
- } /* else */
-
- if ((mountPoint != NULL) && (*mountPoint != '\0'))
- {
- dirHandle->mountPoint = (char *)allocator.Malloc(strlen(mountPoint)+2);
- if (!dirHandle->mountPoint)
- GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, badDirHandle);
- strcpy(dirHandle->mountPoint, mountPoint);
- strcat(dirHandle->mountPoint, "/");
- } /* if */
-
- __PHYSFS_smallFree(tmpmntpnt);
- return dirHandle;
-
-badDirHandle:
- if (dirHandle != NULL)
- {
- dirHandle->funcs->closeArchive(dirHandle->opaque);
- allocator.Free(dirHandle->dirName);
- allocator.Free(dirHandle->mountPoint);
- allocator.Free(dirHandle);
- } /* if */
-
- __PHYSFS_smallFree(tmpmntpnt);
- return NULL;
-} /* createDirHandle */
-
-
-/* MAKE SURE you've got the stateLock held before calling this! */
-static int freeDirHandle(DirHandle *dh, FileHandle *openList)
-{
- FileHandle *i;
-
- if (dh == NULL)
- return 1;
-
- for (i = openList; i != NULL; i = i->next)
- BAIL_IF_MACRO(i->dirHandle == dh, PHYSFS_ERR_FILES_STILL_OPEN, 0);
-
- dh->funcs->closeArchive(dh->opaque);
- allocator.Free(dh->dirName);
- allocator.Free(dh->mountPoint);
- allocator.Free(dh);
- return 1;
-} /* freeDirHandle */
-
-
-static char *calculateBaseDir(const char *argv0)
-{
- const char dirsep = __PHYSFS_platformDirSeparator;
- char *retval = NULL;
- char *ptr = NULL;
-
- /* Give the platform layer first shot at this. */
- retval = __PHYSFS_platformCalcBaseDir(argv0);
- if (retval != NULL)
- return retval;
-
- /* We need argv0 to go on. */
- BAIL_IF_MACRO(argv0 == NULL, PHYSFS_ERR_ARGV0_IS_NULL, NULL);
-
- ptr = strrchr(argv0, dirsep);
- if (ptr != NULL)
- {
- const size_t size = ((size_t) (ptr - argv0)) + 1;
- retval = (char *) allocator.Malloc(size + 1);
- BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
- memcpy(retval, argv0, size);
- retval[size] = '\0';
- return retval;
- } /* if */
-
- /* argv0 wasn't helpful. */
- BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, NULL);
-} /* calculateBaseDir */
-
-
-static int initializeMutexes(void)
-{
- errorLock = __PHYSFS_platformCreateMutex();
- if (errorLock == NULL)
- goto initializeMutexes_failed;
-
- stateLock = __PHYSFS_platformCreateMutex();
- if (stateLock == NULL)
- goto initializeMutexes_failed;
-
- return 1; /* success. */
-
-initializeMutexes_failed:
- if (errorLock != NULL)
- __PHYSFS_platformDestroyMutex(errorLock);
-
- if (stateLock != NULL)
- __PHYSFS_platformDestroyMutex(stateLock);
-
- errorLock = stateLock = NULL;
- return 0; /* failed. */
-} /* initializeMutexes */
-
-
-static void setDefaultAllocator(void);
-
-static int initStaticArchivers(void)
-{
- const size_t numStaticArchivers = __PHYSFS_ARRAYLEN(staticArchivers);
- const size_t len = numStaticArchivers * sizeof (void *);
- size_t i;
-
- assert(numStaticArchivers > 0); /* seriously, none at all?! */
- assert(staticArchivers[numStaticArchivers - 1] == NULL);
-
- archiveInfo = (const PHYSFS_ArchiveInfo **) allocator.Malloc(len);
- BAIL_IF_MACRO(!archiveInfo, PHYSFS_ERR_OUT_OF_MEMORY, 0);
- archivers = (const PHYSFS_Archiver **) allocator.Malloc(len);
- BAIL_IF_MACRO(!archivers, PHYSFS_ERR_OUT_OF_MEMORY, 0);
-
- for (i = 0; i < numStaticArchivers - 1; i++)
- archiveInfo[i] = &staticArchivers[i]->info;
- archiveInfo[numStaticArchivers - 1] = NULL;
-
- memcpy(archivers, staticArchivers, len);
-
- return 1;
-} /* initStaticArchivers */
-
-
-static int doDeinit(void);
-
-int PHYSFS_init(const char *argv0)
-{
- BAIL_IF_MACRO(initialized, PHYSFS_ERR_IS_INITIALIZED, 0);
-
- if (!externalAllocator)
- setDefaultAllocator();
-
- if ((allocator.Init != NULL) && (!allocator.Init())) return 0;
-
- if (!__PHYSFS_platformInit())
- {
- if (allocator.Deinit != NULL) allocator.Deinit();
- return 0;
- } /* if */
-
- /* everything below here can be cleaned up safely by doDeinit(). */
-
- if (!initializeMutexes()) goto initFailed;
-
- baseDir = calculateBaseDir(argv0);
- if (!baseDir) goto initFailed;
-
- userDir = __PHYSFS_platformCalcUserDir();
- if (!userDir) goto initFailed;
-
- /* Platform layer is required to append a dirsep. */
- assert(baseDir[strlen(baseDir) - 1] == __PHYSFS_platformDirSeparator);
- assert(userDir[strlen(userDir) - 1] == __PHYSFS_platformDirSeparator);
-
- if (!initStaticArchivers()) goto initFailed;
-
- initialized = 1;
-
- /* This makes sure that the error subsystem is initialized. */
- __PHYSFS_setError(PHYSFS_getLastErrorCode());
-
- return 1;
-
-initFailed:
- doDeinit();
- return 0;
-} /* PHYSFS_init */
-
-
-/* MAKE SURE you hold stateLock before calling this! */
-static int closeFileHandleList(FileHandle **list)
-{
- FileHandle *i;
- FileHandle *next = NULL;
-
- for (i = *list; i != NULL; i = next)
- {
- PHYSFS_Io *io = i->io;
- next = i->next;
-
- if (!io->flush(io))
- {
- *list = i;
- return 0;
- } /* if */
-
- io->destroy(io);
- allocator.Free(i);
- } /* for */
-
- *list = NULL;
- return 1;
-} /* closeFileHandleList */
-
-
-/* MAKE SURE you hold the stateLock before calling this! */
-static void freeSearchPath(void)
-{
- DirHandle *i;
- DirHandle *next = NULL;
-
- closeFileHandleList(&openReadList);
-
- if (searchPath != NULL)
- {
- for (i = searchPath; i != NULL; i = next)
- {
- next = i->next;
- freeDirHandle(i, openReadList);
- } /* for */
- searchPath = NULL;
- } /* if */
-} /* freeSearchPath */
-
-
-static int doDeinit(void)
-{
- BAIL_IF_MACRO(!__PHYSFS_platformDeinit(), ERRPASS, 0);
-
- closeFileHandleList(&openWriteList);
- BAIL_IF_MACRO(!PHYSFS_setWriteDir(NULL), PHYSFS_ERR_FILES_STILL_OPEN, 0);
-
- freeSearchPath();
- freeErrorStates();
-
- if (baseDir != NULL)
- {
- allocator.Free(baseDir);
- baseDir = NULL;
- } /* if */
-
- if (userDir != NULL)
- {
- allocator.Free(userDir);
- userDir = NULL;
- } /* if */
-
- if (prefDir != NULL)
- {
- allocator.Free(prefDir);
- prefDir = NULL;
- } /* if */
-
- if (archiveInfo != NULL)
- {
- allocator.Free(archiveInfo);
- archiveInfo = NULL;
- } /* if */
-
- if (archivers != NULL)
- {
- allocator.Free(archivers);
- archivers = NULL;
- } /* if */
-
- allowSymLinks = 0;
- initialized = 0;
-
- if (errorLock) __PHYSFS_platformDestroyMutex(errorLock);
- if (stateLock) __PHYSFS_platformDestroyMutex(stateLock);
-
- if (allocator.Deinit != NULL)
- allocator.Deinit();
-
- errorLock = stateLock = NULL;
- return 1;
-} /* doDeinit */
-
-
-int PHYSFS_deinit(void)
-{
- BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, 0);
- return doDeinit();
-} /* PHYSFS_deinit */
-
-
-int PHYSFS_isInit(void)
-{
- return initialized;
-} /* PHYSFS_isInit */
-
-
-const PHYSFS_ArchiveInfo **PHYSFS_supportedArchiveTypes(void)
-{
- BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, NULL);
- return archiveInfo;
-} /* PHYSFS_supportedArchiveTypes */
-
-
-void PHYSFS_freeList(void *list)
-{
- void **i;
- if (list != NULL)
- {
- for (i = (void **) list; *i != NULL; i++)
- allocator.Free(*i);
-
- allocator.Free(list);
- } /* if */
-} /* PHYSFS_freeList */
-
-
-const char *PHYSFS_getDirSeparator(void)
-{
- static char retval[2] = { __PHYSFS_platformDirSeparator, '\0' };
- return retval;
-} /* PHYSFS_getDirSeparator */
-
-
-char **PHYSFS_getCdRomDirs(void)
-{
- return doEnumStringList(__PHYSFS_platformDetectAvailableCDs);
-} /* PHYSFS_getCdRomDirs */
-
-
-void PHYSFS_getCdRomDirsCallback(PHYSFS_StringCallback callback, void *data)
-{
- __PHYSFS_platformDetectAvailableCDs(callback, data);
-} /* PHYSFS_getCdRomDirsCallback */
-
-
-const char *PHYSFS_getPrefDir(const char *org, const char *app)
-{
- const char dirsep = __PHYSFS_platformDirSeparator;
- PHYSFS_Stat statbuf;
- char *ptr = NULL;
- char *endstr = NULL;
- int exists = 0;
-
- BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, 0);
- BAIL_IF_MACRO(!org, PHYSFS_ERR_INVALID_ARGUMENT, NULL);
- BAIL_IF_MACRO(*org == '\0', PHYSFS_ERR_INVALID_ARGUMENT, NULL);
- BAIL_IF_MACRO(!app, PHYSFS_ERR_INVALID_ARGUMENT, NULL);
- BAIL_IF_MACRO(*app == '\0', PHYSFS_ERR_INVALID_ARGUMENT, NULL);
-
- allocator.Free(prefDir);
- prefDir = __PHYSFS_platformCalcPrefDir(org, app);
- BAIL_IF_MACRO(!prefDir, ERRPASS, NULL);
-
- assert(strlen(prefDir) > 0);
- endstr = prefDir + (strlen(prefDir) - 1);
- assert(*endstr == dirsep);
- *endstr = '\0'; /* mask out the final dirsep for now. */
-
- if (!__PHYSFS_platformStat(prefDir, &exists, &statbuf))
- {
- for (ptr = strchr(prefDir, dirsep); ptr; ptr = strchr(ptr+1, dirsep))
- {
- *ptr = '\0';
- __PHYSFS_platformMkDir(prefDir);
- *ptr = dirsep;
- } /* for */
-
- if (!__PHYSFS_platformMkDir(prefDir))
- {
- allocator.Free(prefDir);
- prefDir = NULL;
- } /* if */
- } /* if */
-
- *endstr = dirsep; /* readd the final dirsep. */
-
- return prefDir;
-} /* PHYSFS_getPrefDir */
-
-
-const char *PHYSFS_getBaseDir(void)
-{
- return baseDir; /* this is calculated in PHYSFS_init()... */
-} /* PHYSFS_getBaseDir */
-
-
-const char *__PHYSFS_getUserDir(void) /* not deprecated internal version. */
-{
- return userDir; /* this is calculated in PHYSFS_init()... */
-} /* __PHYSFS_getUserDir */
-
-
-const char *PHYSFS_getUserDir(void)
-{
- return __PHYSFS_getUserDir();
-} /* PHYSFS_getUserDir */
-
-
-const char *PHYSFS_getWriteDir(void)
-{
- const char *retval = NULL;
-
- __PHYSFS_platformGrabMutex(stateLock);
- if (writeDir != NULL)
- retval = writeDir->dirName;
- __PHYSFS_platformReleaseMutex(stateLock);
-
- return retval;
-} /* PHYSFS_getWriteDir */
-
-
-int PHYSFS_setWriteDir(const char *newDir)
-{
- int retval = 1;
-
- __PHYSFS_platformGrabMutex(stateLock);
-
- if (writeDir != NULL)
- {
- BAIL_IF_MACRO_MUTEX(!freeDirHandle(writeDir, openWriteList), ERRPASS,
- stateLock, 0);
- writeDir = NULL;
- } /* if */
-
- if (newDir != NULL)
- {
- /* !!! FIXME: PHYSFS_Io shouldn't be NULL */
- writeDir = createDirHandle(NULL, newDir, NULL, 1);
- retval = (writeDir != NULL);
- } /* if */
-
- __PHYSFS_platformReleaseMutex(stateLock);
-
- return retval;
-} /* PHYSFS_setWriteDir */
-
-
-static int doMount(PHYSFS_Io *io, const char *fname,
- const char *mountPoint, int appendToPath)
-{
- DirHandle *dh;
- DirHandle *prev = NULL;
- DirHandle *i;
-
- if (mountPoint == NULL)
- mountPoint = "/";
-
- __PHYSFS_platformGrabMutex(stateLock);
-
- if (fname != NULL)
- {
- for (i = searchPath; i != NULL; i = i->next)
- {
- /* already in search path? */
- if ((i->dirName != NULL) && (strcmp(fname, i->dirName) == 0))
- BAIL_MACRO_MUTEX(ERRPASS, stateLock, 1);
- prev = i;
- } /* for */
- } /* if */
-
- dh = createDirHandle(io, fname, mountPoint, 0);
- BAIL_IF_MACRO_MUTEX(!dh, ERRPASS, stateLock, 0);
-
- if (appendToPath)
- {
- if (prev == NULL)
- searchPath = dh;
- else
- prev->next = dh;
- } /* if */
- else
- {
- dh->next = searchPath;
- searchPath = dh;
- } /* else */
-
- __PHYSFS_platformReleaseMutex(stateLock);
- return 1;
-} /* doMount */
-
-
-int PHYSFS_mountIo(PHYSFS_Io *io, const char *fname,
- const char *mountPoint, int appendToPath)
-{
- BAIL_IF_MACRO(!io, PHYSFS_ERR_INVALID_ARGUMENT, 0);
- BAIL_IF_MACRO(io->version != 0, PHYSFS_ERR_UNSUPPORTED, 0);
- return doMount(io, fname, mountPoint, appendToPath);
-} /* PHYSFS_mountIo */
-
-
-int PHYSFS_mountMemory(const void *buf, PHYSFS_uint64 len, void (*del)(void *),
- const char *fname, const char *mountPoint,
- int appendToPath)
-{
- int retval = 0;
- PHYSFS_Io *io = NULL;
-
- BAIL_IF_MACRO(!buf, PHYSFS_ERR_INVALID_ARGUMENT, 0);
-
- io = __PHYSFS_createMemoryIo(buf, len, del);
- BAIL_IF_MACRO(!io, ERRPASS, 0);
- retval = doMount(io, fname, mountPoint, appendToPath);
- if (!retval)
- {
- /* docs say not to call (del) in case of failure, so cheat. */
- MemoryIoInfo *info = (MemoryIoInfo *) io->opaque;
- info->destruct = NULL;
- io->destroy(io);
- } /* if */
-
- return retval;
-} /* PHYSFS_mountMemory */
-
-
-int PHYSFS_mountHandle(PHYSFS_File *file, const char *fname,
- const char *mountPoint, int appendToPath)
-{
- int retval = 0;
- PHYSFS_Io *io = NULL;
-
- BAIL_IF_MACRO(file == NULL, PHYSFS_ERR_INVALID_ARGUMENT, 0);
-
- io = __PHYSFS_createHandleIo(file);
- BAIL_IF_MACRO(!io, ERRPASS, 0);
- retval = doMount(io, fname, mountPoint, appendToPath);
- if (!retval)
- {
- /* docs say not to destruct in case of failure, so cheat. */
- io->opaque = NULL;
- io->destroy(io);
- } /* if */
-
- return retval;
-} /* PHYSFS_mountHandle */
-
-
-int PHYSFS_mount(const char *newDir, const char *mountPoint, int appendToPath)
-{
- BAIL_IF_MACRO(!newDir, PHYSFS_ERR_INVALID_ARGUMENT, 0);
- return doMount(NULL, newDir, mountPoint, appendToPath);
-} /* PHYSFS_mount */
-
-
-int PHYSFS_addToSearchPath(const char *newDir, int appendToPath)
-{
- return doMount(NULL, newDir, NULL, appendToPath);
-} /* PHYSFS_addToSearchPath */
-
-
-int PHYSFS_removeFromSearchPath(const char *oldDir)
-{
- return PHYSFS_unmount(oldDir);
-} /* PHYSFS_removeFromSearchPath */
-
-
-int PHYSFS_unmount(const char *oldDir)
-{
- DirHandle *i;
- DirHandle *prev = NULL;
- DirHandle *next = NULL;
-
- BAIL_IF_MACRO(oldDir == NULL, PHYSFS_ERR_INVALID_ARGUMENT, 0);
-
- __PHYSFS_platformGrabMutex(stateLock);
- for (i = searchPath; i != NULL; i = i->next)
- {
- if (strcmp(i->dirName, oldDir) == 0)
- {
- next = i->next;
- BAIL_IF_MACRO_MUTEX(!freeDirHandle(i, openReadList), ERRPASS,
- stateLock, 0);
-
- if (prev == NULL)
- searchPath = next;
- else
- prev->next = next;
-
- BAIL_MACRO_MUTEX(ERRPASS, stateLock, 1);
- } /* if */
- prev = i;
- } /* for */
-
- BAIL_MACRO_MUTEX(PHYSFS_ERR_NOT_MOUNTED, stateLock, 0);
-} /* PHYSFS_unmount */
-
-
-char **PHYSFS_getSearchPath(void)
-{
- return doEnumStringList(PHYSFS_getSearchPathCallback);
-} /* PHYSFS_getSearchPath */
-
-
-const char *PHYSFS_getMountPoint(const char *dir)
-{
- DirHandle *i;
- __PHYSFS_platformGrabMutex(stateLock);
- for (i = searchPath; i != NULL; i = i->next)
- {
- if (strcmp(i->dirName, dir) == 0)
- {
- const char *retval = ((i->mountPoint) ? i->mountPoint : "/");
- __PHYSFS_platformReleaseMutex(stateLock);
- return retval;
- } /* if */
- } /* for */
- __PHYSFS_platformReleaseMutex(stateLock);
-
- BAIL_MACRO(PHYSFS_ERR_NOT_MOUNTED, NULL);
-} /* PHYSFS_getMountPoint */
-
-
-void PHYSFS_getSearchPathCallback(PHYSFS_StringCallback callback, void *data)
-{
- DirHandle *i;
-
- __PHYSFS_platformGrabMutex(stateLock);
-
- for (i = searchPath; i != NULL; i = i->next)
- callback(data, i->dirName);
-
- __PHYSFS_platformReleaseMutex(stateLock);
-} /* PHYSFS_getSearchPathCallback */
-
-
-/* Split out to avoid stack allocation in a loop. */
-static void setSaneCfgAddPath(const char *i, const size_t l, const char *dirsep,
- int archivesFirst)
-{
- const char *d = PHYSFS_getRealDir(i);
- const size_t allocsize = strlen(d) + strlen(dirsep) + l + 1;
- char *str = (char *) __PHYSFS_smallAlloc(allocsize);
- if (str != NULL)
- {
- sprintf(str, "%s%s%s", d, dirsep, i);
- PHYSFS_mount(str, NULL, archivesFirst == 0);
- __PHYSFS_smallFree(str);
- } /* if */
-} /* setSaneCfgAddPath */
-
-
-int PHYSFS_setSaneConfig(const char *organization, const char *appName,
- const char *archiveExt, int includeCdRoms,
- int archivesFirst)
-{
- const char *dirsep = PHYSFS_getDirSeparator();
- const char *basedir;
- const char *prefdir;
-
- BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, 0);
-
- prefdir = PHYSFS_getPrefDir(organization, appName);
- BAIL_IF_MACRO(!prefdir, ERRPASS, 0);
-
- basedir = PHYSFS_getBaseDir();
- BAIL_IF_MACRO(!basedir, ERRPASS, 0);
-
- BAIL_IF_MACRO(!PHYSFS_setWriteDir(prefdir), PHYSFS_ERR_NO_WRITE_DIR, 0);
-
- /* Put write dir first in search path... */
- PHYSFS_mount(prefdir, NULL, 0);
-
- /* Put base path on search path... */
- PHYSFS_mount(basedir, NULL, 1);
-
- /* handle CD-ROMs... */
- if (includeCdRoms)
- {
- char **cds = PHYSFS_getCdRomDirs();
- char **i;
- for (i = cds; *i != NULL; i++)
- PHYSFS_mount(*i, NULL, 1);
- PHYSFS_freeList(cds);
- } /* if */
-
- /* Root out archives, and add them to search path... */
- if (archiveExt != NULL)
- {
- char **rc = PHYSFS_enumerateFiles("/");
- char **i;
- size_t extlen = strlen(archiveExt);
- char *ext;
-
- for (i = rc; *i != NULL; i++)
- {
- size_t l = strlen(*i);
- if ((l > extlen) && ((*i)[l - extlen - 1] == '.'))
- {
- ext = (*i) + (l - extlen);
- if (__PHYSFS_stricmpASCII(ext, archiveExt) == 0)
- setSaneCfgAddPath(*i, l, dirsep, archivesFirst);
- } /* if */
- } /* for */
-
- PHYSFS_freeList(rc);
- } /* if */
-
- return 1;
-} /* PHYSFS_setSaneConfig */
-
-
-void PHYSFS_permitSymbolicLinks(int allow)
-{
- allowSymLinks = allow;
-} /* PHYSFS_permitSymbolicLinks */
-
-
-int PHYSFS_symbolicLinksPermitted(void)
-{
- return allowSymLinks;
-} /* PHYSFS_symbolicLinksPermitted */
-
-
-/*
- * Verify that (fname) (in platform-independent notation), in relation
- * to (h) is secure. That means that each element of fname is checked
- * for symlinks (if they aren't permitted). This also allows for quick
- * rejection of files that exist outside an archive's mountpoint.
- *
- * With some exceptions (like PHYSFS_mkdir(), which builds multiple subdirs
- * at a time), you should always pass zero for "allowMissing" for efficiency.
- *
- * (fname) must point to an output from sanitizePlatformIndependentPath(),
- * since it will make sure that path names are in the right format for
- * passing certain checks. It will also do checks for "insecure" pathnames
- * like ".." which should be done once instead of once per archive. This also
- * gives us license to treat (fname) as scratch space in this function.
- *
- * Returns non-zero if string is safe, zero if there's a security issue.
- * PHYSFS_getLastError() will specify what was wrong. (*fname) will be
- * updated to point past any mount point elements so it is prepared to
- * be used with the archiver directly.
- */
-static int verifyPath(DirHandle *h, char **_fname, int allowMissing)
-{
- char *fname = *_fname;
- int retval = 1;
- char *start;
- char *end;
-
- if (*fname == '\0') /* quick rejection. */
- return 1;
-
- /* !!! FIXME: This codeblock sucks. */
- if (h->mountPoint != NULL) /* NULL mountpoint means "/". */
- {
- size_t mntpntlen = strlen(h->mountPoint);
- size_t len = strlen(fname);
- assert(mntpntlen > 1); /* root mount points should be NULL. */
- /* not under the mountpoint, so skip this archive. */
- BAIL_IF_MACRO(len < mntpntlen-1, PHYSFS_ERR_NO_SUCH_PATH, 0);
- /* !!! FIXME: Case insensitive? */
- retval = strncmp(h->mountPoint, fname, mntpntlen-1);
- BAIL_IF_MACRO(retval != 0, PHYSFS_ERR_NO_SUCH_PATH, 0);
- if (len > mntpntlen-1) /* corner case... */
- BAIL_IF_MACRO(fname[mntpntlen-1]!='/', PHYSFS_ERR_NO_SUCH_PATH, 0);
- fname += mntpntlen-1; /* move to start of actual archive path. */
- if (*fname == '/')
- fname++;
- *_fname = fname; /* skip mountpoint for later use. */
- retval = 1; /* may be reset, below. */
- } /* if */
-
- start = fname;
- if (!allowSymLinks)
- {
- while (1)
- {
- PHYSFS_Stat statbuf;
- int rc = 0;
- end = strchr(start, '/');
-
- if (end != NULL) *end = '\0';
- rc = h->funcs->stat(h->opaque, fname, &retval, &statbuf);
- if (rc)
- rc = (statbuf.filetype == PHYSFS_FILETYPE_SYMLINK);
- if (end != NULL) *end = '/';
-
- /* insecure path (has a disallowed symlink in it)? */
- BAIL_IF_MACRO(rc, PHYSFS_ERR_SYMLINK_FORBIDDEN, 0);
-
- /* break out early if path element is missing. */
- if (!retval)
- {
- /*
- * We need to clear it if it's the last element of the path,
- * since this might be a non-existant file we're opening
- * for writing...
- */
- if ((end == NULL) || (allowMissing))
- retval = 1;
- break;
- } /* if */
-
- if (end == NULL)
- break;
-
- start = end + 1;
- } /* while */
- } /* if */
-
- return retval;
-} /* verifyPath */
-
-
-static int doMkdir(const char *_dname, char *dname)
-{
- DirHandle *h;
- char *start;
- char *end;
- int retval = 0;
- int exists = 1; /* force existance check on first path element. */
-
- BAIL_IF_MACRO(!sanitizePlatformIndependentPath(_dname, dname), ERRPASS, 0);
-
- __PHYSFS_platformGrabMutex(stateLock);
- BAIL_IF_MACRO_MUTEX(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, stateLock, 0);
- h = writeDir;
- BAIL_IF_MACRO_MUTEX(!verifyPath(h, &dname, 1), ERRPASS, stateLock, 0);
-
- start = dname;
- while (1)
- {
- end = strchr(start, '/');
- if (end != NULL)
- *end = '\0';
-
- /* only check for existance if all parent dirs existed, too... */
- if (exists)
- {
- PHYSFS_Stat statbuf;
- const int rc = h->funcs->stat(h->opaque, dname, &exists, &statbuf);
- retval = ((rc) && (statbuf.filetype == PHYSFS_FILETYPE_DIRECTORY));
- } /* if */
-
- if (!exists)
- retval = h->funcs->mkdir(h->opaque, dname);
-
- if (!retval)
- break;
-
- if (end == NULL)
- break;
-
- *end = '/';
- start = end + 1;
- } /* while */
-
- __PHYSFS_platformReleaseMutex(stateLock);
- return retval;
-} /* doMkdir */
-
-
-int PHYSFS_mkdir(const char *_dname)
-{
- int retval = 0;
- char *dname;
- size_t len;
-
- BAIL_IF_MACRO(!_dname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
- len = strlen(_dname) + 1;
- dname = (char *) __PHYSFS_smallAlloc(len);
- BAIL_IF_MACRO(!dname, PHYSFS_ERR_OUT_OF_MEMORY, 0);
- retval = doMkdir(_dname, dname);
- __PHYSFS_smallFree(dname);
- return retval;
-} /* PHYSFS_mkdir */
-
-
-static int doDelete(const char *_fname, char *fname)
-{
- int retval;
- DirHandle *h;
- BAIL_IF_MACRO(!sanitizePlatformIndependentPath(_fname, fname), ERRPASS, 0);
-
- __PHYSFS_platformGrabMutex(stateLock);
-
- BAIL_IF_MACRO_MUTEX(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, stateLock, 0);
- h = writeDir;
- BAIL_IF_MACRO_MUTEX(!verifyPath(h, &fname, 0), ERRPASS, stateLock, 0);
- retval = h->funcs->remove(h->opaque, fname);
-
- __PHYSFS_platformReleaseMutex(stateLock);
- return retval;
-} /* doDelete */
-
-
-int PHYSFS_delete(const char *_fname)
-{
- int retval;
- char *fname;
- size_t len;
-
- BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
- len = strlen(_fname) + 1;
- fname = (char *) __PHYSFS_smallAlloc(len);
- BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0);
- retval = doDelete(_fname, fname);
- __PHYSFS_smallFree(fname);
- return retval;
-} /* PHYSFS_delete */
-
-
-const char *PHYSFS_getRealDir(const char *_fname)
-{
- const char *retval = NULL;
- char *fname = NULL;
- size_t len;
-
- BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, NULL);
- len = strlen(_fname) + 1;
- fname = __PHYSFS_smallAlloc(len);
- BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
- if (sanitizePlatformIndependentPath(_fname, fname))
- {
- DirHandle *i;
- __PHYSFS_platformGrabMutex(stateLock);
- for (i = searchPath; i != NULL; i = i->next)
- {
- char *arcfname = fname;
- if (partOfMountPoint(i, arcfname))
- {
- retval = i->dirName;
- break;
- } /* if */
- else if (verifyPath(i, &arcfname, 0))
- {
- PHYSFS_Stat statbuf;
- int exists = 0;
- if (i->funcs->stat(i->opaque, arcfname, &exists, &statbuf))
- {
- if (exists)
- retval = i->dirName;
- break;
- } /* if */
- } /* if */
- } /* for */
- __PHYSFS_platformReleaseMutex(stateLock);
- } /* if */
-
- __PHYSFS_smallFree(fname);
- return retval;
-} /* PHYSFS_getRealDir */
-
-
-static int locateInStringList(const char *str,
- char **list,
- PHYSFS_uint32 *pos)
-{
- PHYSFS_uint32 len = *pos;
- PHYSFS_uint32 half_len;
- PHYSFS_uint32 lo = 0;
- PHYSFS_uint32 middle;
- int cmp;
-
- while (len > 0)
- {
- half_len = len >> 1;
- middle = lo + half_len;
- cmp = strcmp(list[middle], str);
-
- if (cmp == 0) /* it's in the list already. */
- return 1;
- else if (cmp > 0)
- len = half_len;
- else
- {
- lo = middle + 1;
- len -= half_len + 1;
- } /* else */
- } /* while */
-
- *pos = lo;
- return 0;
-} /* locateInStringList */
-
-
-static void enumFilesCallback(void *data, const char *origdir, const char *str)
-{
- PHYSFS_uint32 pos;
- void *ptr;
- char *newstr;
- EnumStringListCallbackData *pecd = (EnumStringListCallbackData *) data;
-
- /*
- * See if file is in the list already, and if not, insert it in there
- * alphabetically...
- */
- pos = pecd->size;
- if (locateInStringList(str, pecd->list, &pos))
- return; /* already in the list. */
-
- ptr = allocator.Realloc(pecd->list, (pecd->size + 2) * sizeof (char *));
- newstr = (char *) allocator.Malloc(strlen(str) + 1);
- if (ptr != NULL)
- pecd->list = (char **) ptr;
-
- if ((ptr == NULL) || (newstr == NULL))
- return; /* better luck next time. */
-
- strcpy(newstr, str);
-
- if (pos != pecd->size)
- {
- memmove(&pecd->list[pos+1], &pecd->list[pos],
- sizeof (char *) * ((pecd->size) - pos));
- } /* if */
-
- pecd->list[pos] = newstr;
- pecd->size++;
-} /* enumFilesCallback */
-
-
-char **PHYSFS_enumerateFiles(const char *path)
-{
- EnumStringListCallbackData ecd;
- memset(&ecd, '\0', sizeof (ecd));
- ecd.list = (char **) allocator.Malloc(sizeof (char *));
- BAIL_IF_MACRO(!ecd.list, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
- PHYSFS_enumerateFilesCallback(path, enumFilesCallback, &ecd);
- ecd.list[ecd.size] = NULL;
- return ecd.list;
-} /* PHYSFS_enumerateFiles */
-
-
-/*
- * Broke out to seperate function so we can use stack allocation gratuitously.
- */
-static void enumerateFromMountPoint(DirHandle *i, const char *arcfname,
- PHYSFS_EnumFilesCallback callback,
- const char *_fname, void *data)
-{
- const size_t len = strlen(arcfname);
- char *ptr = NULL;
- char *end = NULL;
- const size_t slen = strlen(i->mountPoint) + 1;
- char *mountPoint = (char *) __PHYSFS_smallAlloc(slen);
-
- if (mountPoint == NULL)
- return; /* oh well. */
-
- strcpy(mountPoint, i->mountPoint);
- ptr = mountPoint + ((len) ? len + 1 : 0);
- end = strchr(ptr, '/');
- assert(end); /* should always find a terminating '/'. */
- *end = '\0';
- callback(data, _fname, ptr);
- __PHYSFS_smallFree(mountPoint);
-} /* enumerateFromMountPoint */
-
-
-/* !!! FIXME: this should report error conditions. */
-void PHYSFS_enumerateFilesCallback(const char *_fname,
- PHYSFS_EnumFilesCallback callback,
- void *data)
-{
- size_t len;
- char *fname;
-
- BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, ) /*0*/;
- BAIL_IF_MACRO(!callback, PHYSFS_ERR_INVALID_ARGUMENT, ) /*0*/;
-
- len = strlen(_fname) + 1;
- fname = (char *) __PHYSFS_smallAlloc(len);
- BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, ) /*0*/;
-
- if (sanitizePlatformIndependentPath(_fname, fname))
- {
- DirHandle *i;
- int noSyms;
-
- __PHYSFS_platformGrabMutex(stateLock);
- noSyms = !allowSymLinks;
- for (i = searchPath; i != NULL; i = i->next)
- {
- char *arcfname = fname;
- if (partOfMountPoint(i, arcfname))
- enumerateFromMountPoint(i, arcfname, callback, _fname, data);
-
- else if (verifyPath(i, &arcfname, 0))
- {
- i->funcs->enumerateFiles(i->opaque, arcfname, noSyms,
- callback, _fname, data);
- } /* else if */
- } /* for */
- __PHYSFS_platformReleaseMutex(stateLock);
- } /* if */
-
- __PHYSFS_smallFree(fname);
-} /* PHYSFS_enumerateFilesCallback */
-
-
-int PHYSFS_exists(const char *fname)
-{
- return (PHYSFS_getRealDir(fname) != NULL);
-} /* PHYSFS_exists */
-
-
-PHYSFS_sint64 PHYSFS_getLastModTime(const char *fname)
-{
- PHYSFS_Stat statbuf;
- BAIL_IF_MACRO(!PHYSFS_stat(fname, &statbuf), ERRPASS, -1);
- return statbuf.modtime;
-} /* PHYSFS_getLastModTime */
-
-
-int PHYSFS_isDirectory(const char *fname)
-{
- PHYSFS_Stat statbuf;
- BAIL_IF_MACRO(!PHYSFS_stat(fname, &statbuf), ERRPASS, 0);
- return (statbuf.filetype == PHYSFS_FILETYPE_DIRECTORY);
-} /* PHYSFS_isDirectory */
-
-
-int PHYSFS_isSymbolicLink(const char *fname)
-{
- PHYSFS_Stat statbuf;
- BAIL_IF_MACRO(!PHYSFS_stat(fname, &statbuf), ERRPASS, 0);
- return (statbuf.filetype == PHYSFS_FILETYPE_SYMLINK);
-} /* PHYSFS_isSymbolicLink */
-
-
-static PHYSFS_File *doOpenWrite(const char *_fname, int appending)
-{
- FileHandle *fh = NULL;
- size_t len;
- char *fname;
-
- BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
- len = strlen(_fname) + 1;
- fname = (char *) __PHYSFS_smallAlloc(len);
- BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0);
-
- if (sanitizePlatformIndependentPath(_fname, fname))
- {
- PHYSFS_Io *io = NULL;
- DirHandle *h = NULL;
- const PHYSFS_Archiver *f;
-
- __PHYSFS_platformGrabMutex(stateLock);
-
- GOTO_IF_MACRO(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, doOpenWriteEnd);
-
- h = writeDir;
- GOTO_IF_MACRO(!verifyPath(h, &fname, 0), ERRPASS, doOpenWriteEnd);
-
- f = h->funcs;
- if (appending)
- io = f->openAppend(h->opaque, fname);
- else
- io = f->openWrite(h->opaque, fname);
-
- GOTO_IF_MACRO(!io, ERRPASS, doOpenWriteEnd);
-
- fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle));
- if (fh == NULL)
- {
- io->destroy(io);
- GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, doOpenWriteEnd);
- } /* if */
- else
- {
- memset(fh, '\0', sizeof (FileHandle));
- fh->io = io;
- fh->dirHandle = h;
- fh->next = openWriteList;
- openWriteList = fh;
- } /* else */
-
- doOpenWriteEnd:
- __PHYSFS_platformReleaseMutex(stateLock);
- } /* if */
-
- __PHYSFS_smallFree(fname);
- return ((PHYSFS_File *) fh);
-} /* doOpenWrite */
-
-
-PHYSFS_File *PHYSFS_openWrite(const char *filename)
-{
- return doOpenWrite(filename, 0);
-} /* PHYSFS_openWrite */
-
-
-PHYSFS_File *PHYSFS_openAppend(const char *filename)
-{
- return doOpenWrite(filename, 1);
-} /* PHYSFS_openAppend */
-
-
-PHYSFS_File *PHYSFS_openRead(const char *_fname)
-{
- FileHandle *fh = NULL;
- char *fname;
- size_t len;
-
- BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
- len = strlen(_fname) + 1;
- fname = (char *) __PHYSFS_smallAlloc(len);
- BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0);
-
- if (sanitizePlatformIndependentPath(_fname, fname))
- {
- int fileExists = 0;
- DirHandle *i = NULL;
- PHYSFS_Io *io = NULL;
-
- __PHYSFS_platformGrabMutex(stateLock);
-
- GOTO_IF_MACRO(!searchPath, PHYSFS_ERR_NO_SUCH_PATH, openReadEnd);
-
- for (i = searchPath; (i != NULL) && (!fileExists); i = i->next)
- {
- char *arcfname = fname;
- if (verifyPath(i, &arcfname, 0))
- {
- io = i->funcs->openRead(i->opaque, arcfname, &fileExists);
- if (io)
- break;
- } /* if */
- } /* for */
-
- GOTO_IF_MACRO(!io, ERRPASS, openReadEnd);
-
- fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle));
- if (fh == NULL)
- {
- io->destroy(io);
- GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, openReadEnd);
- } /* if */
-
- memset(fh, '\0', sizeof (FileHandle));
- fh->io = io;
- fh->forReading = 1;
- fh->dirHandle = i;
- fh->next = openReadList;
- openReadList = fh;
-
- openReadEnd:
- __PHYSFS_platformReleaseMutex(stateLock);
- } /* if */
-
- __PHYSFS_smallFree(fname);
- return ((PHYSFS_File *) fh);
-} /* PHYSFS_openRead */
-
-
-static int closeHandleInOpenList(FileHandle **list, FileHandle *handle)
-{
- FileHandle *prev = NULL;
- FileHandle *i;
- int rc = 1;
-
- for (i = *list; i != NULL; i = i->next)
- {
- if (i == handle) /* handle is in this list? */
- {
- PHYSFS_Io *io = handle->io;
- PHYSFS_uint8 *tmp = handle->buffer;
- rc = PHYSFS_flush((PHYSFS_File *) handle);
- if (!rc)
- return -1;
- io->destroy(io);
-
- if (tmp != NULL) /* free any associated buffer. */
- allocator.Free(tmp);
-
- if (prev == NULL)
- *list = handle->next;
- else
- prev->next = handle->next;
-
- allocator.Free(handle);
- return 1;
- } /* if */
- prev = i;
- } /* for */
-
- return 0;
-} /* closeHandleInOpenList */
-
-
-int PHYSFS_close(PHYSFS_File *_handle)
-{
- FileHandle *handle = (FileHandle *) _handle;
- int rc;
-
- __PHYSFS_platformGrabMutex(stateLock);
-
- /* -1 == close failure. 0 == not found. 1 == success. */
- rc = closeHandleInOpenList(&openReadList, handle);
- BAIL_IF_MACRO_MUTEX(rc == -1, ERRPASS, stateLock, 0);
- if (!rc)
- {
- rc = closeHandleInOpenList(&openWriteList, handle);
- BAIL_IF_MACRO_MUTEX(rc == -1, ERRPASS, stateLock, 0);
- } /* if */
-
- __PHYSFS_platformReleaseMutex(stateLock);
- BAIL_IF_MACRO(!rc, PHYSFS_ERR_INVALID_ARGUMENT, 0);
- return 1;
-} /* PHYSFS_close */
-
-
-static PHYSFS_sint64 doBufferedRead(FileHandle *fh, void *buffer,
- PHYSFS_uint64 len)
-{
- PHYSFS_Io *io = NULL;
- PHYSFS_sint64 retval = 0;
- PHYSFS_uint32 buffered = 0;
- PHYSFS_sint64 rc = 0;
-
- if (len == 0)
- return 0;
-
- buffered = fh->buffill - fh->bufpos;
- if (buffered >= len) /* totally in the buffer, just copy and return! */
- {
- memcpy(buffer, fh->buffer + fh->bufpos, (size_t) len);
- fh->bufpos += (PHYSFS_uint32) len;
- return (PHYSFS_sint64) len;
- } /* else if */
-
- if (buffered > 0) /* partially in the buffer... */
- {
- memcpy(buffer, fh->buffer + fh->bufpos, (size_t) buffered);
- buffer = ((PHYSFS_uint8 *) buffer) + buffered;
- len -= buffered;
- retval = buffered;
- fh->buffill = fh->bufpos = 0;
- } /* if */
-
- /* if you got here, the buffer is drained and we still need bytes. */
- assert(len > 0);
-
- io = fh->io;
- if (len >= fh->bufsize) /* need more than the buffer takes. */
- {
- /* leave buffer empty, go right to output instead. */
- rc = io->read(io, buffer, len);
- if (rc < 0)
- return ((retval == 0) ? rc : retval);
- return retval + rc;
- } /* if */
-
- /* need less than buffer can take. Fill buffer. */
- rc = io->read(io, fh->buffer, fh->bufsize);
- if (rc < 0)
- return ((retval == 0) ? rc : retval);
-
- assert(fh->bufpos == 0);
- fh->buffill = (PHYSFS_uint32) rc;
- rc = doBufferedRead(fh, buffer, len); /* go from the start, again. */
- if (rc < 0)
- return ((retval == 0) ? rc : retval);
-
- return retval + rc;
-} /* doBufferedRead */
-
-
-PHYSFS_sint64 PHYSFS_read(PHYSFS_File *handle, void *buffer,
- PHYSFS_uint32 size, PHYSFS_uint32 count)
-{
- const PHYSFS_uint64 len = ((PHYSFS_uint64) size) * ((PHYSFS_uint64) count);
- const PHYSFS_sint64 retval = PHYSFS_readBytes(handle, buffer, len);
- return ( (retval <= 0) ? retval : (retval / ((PHYSFS_sint64) size)) );
-} /* PHYSFS_read */
-
-
-PHYSFS_sint64 PHYSFS_readBytes(PHYSFS_File *handle, void *buffer,
- PHYSFS_uint64 len)
-{
- FileHandle *fh = (FileHandle *) handle;
-
-#ifdef PHYSFS_NO_64BIT_SUPPORT
- const PHYSFS_uint64 maxlen = __PHYSFS_UI64(0x7FFFFFFF);
-#else
- const PHYSFS_uint64 maxlen = __PHYSFS_UI64(0x7FFFFFFFFFFFFFFF);
-#endif
-
- if (!__PHYSFS_ui64FitsAddressSpace(len))
- BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1);
-
- BAIL_IF_MACRO(len > maxlen, PHYSFS_ERR_INVALID_ARGUMENT, -1);
- BAIL_IF_MACRO(!fh->forReading, PHYSFS_ERR_OPEN_FOR_WRITING, -1);
- BAIL_IF_MACRO(len == 0, ERRPASS, 0);
- if (fh->buffer)
- return doBufferedRead(fh, buffer, len);
-
- return fh->io->read(fh->io, buffer, len);
-} /* PHYSFS_readBytes */
-
-
-static PHYSFS_sint64 doBufferedWrite(PHYSFS_File *handle, const void *buffer,
- PHYSFS_uint64 len)
-{
- FileHandle *fh = (FileHandle *) handle;
-
- /* whole thing fits in the buffer? */
- if ( (((PHYSFS_uint64) fh->buffill) + len) < fh->bufsize )
- {
- memcpy(fh->buffer + fh->buffill, buffer, (size_t) len);
- fh->buffill += (PHYSFS_uint32) len;
- return (PHYSFS_sint64) len;
- } /* if */
-
- /* would overflow buffer. Flush and then write the new objects, too. */
- BAIL_IF_MACRO(!PHYSFS_flush(handle), ERRPASS, -1);
- return fh->io->write(fh->io, buffer, len);
-} /* doBufferedWrite */
-
-
-PHYSFS_sint64 PHYSFS_write(PHYSFS_File *handle, const void *buffer,
- PHYSFS_uint32 size, PHYSFS_uint32 count)
-{
- const PHYSFS_uint64 len = ((PHYSFS_uint64) size) * ((PHYSFS_uint64) count);
- const PHYSFS_sint64 retval = PHYSFS_writeBytes(handle, buffer, len);
- return ( (retval <= 0) ? retval : (retval / ((PHYSFS_sint64) size)) );
-} /* PHYSFS_write */
-
-
-PHYSFS_sint64 PHYSFS_writeBytes(PHYSFS_File *handle, const void *buffer,
- PHYSFS_uint64 len)
-{
- FileHandle *fh = (FileHandle *) handle;
-
-#ifdef PHYSFS_NO_64BIT_SUPPORT
- const PHYSFS_uint64 maxlen = __PHYSFS_UI64(0x7FFFFFFF);
-#else
- const PHYSFS_uint64 maxlen = __PHYSFS_UI64(0x7FFFFFFFFFFFFFFF);
-#endif
-
- if (!__PHYSFS_ui64FitsAddressSpace(len))
- BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1);
-
- BAIL_IF_MACRO(len > maxlen, PHYSFS_ERR_INVALID_ARGUMENT, -1);
- BAIL_IF_MACRO(fh->forReading, PHYSFS_ERR_OPEN_FOR_READING, -1);
- BAIL_IF_MACRO(len == 0, ERRPASS, 0);
- if (fh->buffer)
- return doBufferedWrite(handle, buffer, len);
-
- return fh->io->write(fh->io, buffer, len);
-} /* PHYSFS_write */
-
-
-int PHYSFS_eof(PHYSFS_File *handle)
-{
- FileHandle *fh = (FileHandle *) handle;
-
- if (!fh->forReading) /* never EOF on files opened for write/append. */
- return 0;
-
- /* can't be eof if buffer isn't empty */
- if (fh->bufpos == fh->buffill)
- {
- /* check the Io. */
- PHYSFS_Io *io = fh->io;
- const PHYSFS_sint64 pos = io->tell(io);
- const PHYSFS_sint64 len = io->length(io);
- if ((pos < 0) || (len < 0))
- return 0; /* beats me. */
- return (pos >= len);
- } /* if */
-
- return 0;
-} /* PHYSFS_eof */
-
-
-PHYSFS_sint64 PHYSFS_tell(PHYSFS_File *handle)
-{
- FileHandle *fh = (FileHandle *) handle;
- const PHYSFS_sint64 pos = fh->io->tell(fh->io);
- const PHYSFS_sint64 retval = fh->forReading ?
- (pos - fh->buffill) + fh->bufpos :
- (pos + fh->buffill);
- return retval;
-} /* PHYSFS_tell */
-
-
-int PHYSFS_seek(PHYSFS_File *handle, PHYSFS_uint64 pos)
-{
- FileHandle *fh = (FileHandle *) handle;
- BAIL_IF_MACRO(!PHYSFS_flush(handle), ERRPASS, 0);
-
- if (fh->buffer && fh->forReading)
- {
- /* avoid throwing away our precious buffer if seeking within it. */
- PHYSFS_sint64 offset = pos - PHYSFS_tell(handle);
- if ( /* seeking within the already-buffered range? */
- ((offset >= 0) && (offset <= fh->buffill - fh->bufpos)) /* fwd */
- || ((offset < 0) && (-offset <= fh->bufpos)) /* backward */ )
- {
- fh->bufpos += (PHYSFS_uint32) offset;
- return 1; /* successful seek */
- } /* if */
- } /* if */
-
- /* we have to fall back to a 'raw' seek. */
- fh->buffill = fh->bufpos = 0;
- return fh->io->seek(fh->io, pos);
-} /* PHYSFS_seek */
-
-
-PHYSFS_sint64 PHYSFS_fileLength(PHYSFS_File *handle)
-{
- PHYSFS_Io *io = ((FileHandle *) handle)->io;
- return io->length(io);
-} /* PHYSFS_filelength */
-
-
-int PHYSFS_setBuffer(PHYSFS_File *handle, PHYSFS_uint64 _bufsize)
-{
- FileHandle *fh = (FileHandle *) handle;
- PHYSFS_uint32 bufsize;
-
- /* !!! FIXME: actually, why use 32 bits here? */
- /*BAIL_IF_MACRO(_bufsize > 0xFFFFFFFF, "buffer must fit in 32-bits", 0);*/
- BAIL_IF_MACRO(_bufsize > 0xFFFFFFFF, PHYSFS_ERR_INVALID_ARGUMENT, 0);
- bufsize = (PHYSFS_uint32) _bufsize;
-
- BAIL_IF_MACRO(!PHYSFS_flush(handle), ERRPASS, 0);
-
- /*
- * For reads, we need to move the file pointer to where it would be
- * if we weren't buffering, so that the next read will get the
- * right chunk of stuff from the file. PHYSFS_flush() handles writes.
- */
- if ((fh->forReading) && (fh->buffill != fh->bufpos))
- {
- PHYSFS_uint64 pos;
- const PHYSFS_sint64 curpos = fh->io->tell(fh->io);
- BAIL_IF_MACRO(curpos == -1, ERRPASS, 0);
- pos = ((curpos - fh->buffill) + fh->bufpos);
- BAIL_IF_MACRO(!fh->io->seek(fh->io, pos), ERRPASS, 0);
- } /* if */
-
- if (bufsize == 0) /* delete existing buffer. */
- {
- if (fh->buffer)
- {
- allocator.Free(fh->buffer);
- fh->buffer = NULL;
- } /* if */
- } /* if */
-
- else
- {
- PHYSFS_uint8 *newbuf;
- newbuf = (PHYSFS_uint8 *) allocator.Realloc(fh->buffer, bufsize);
- BAIL_IF_MACRO(!newbuf, PHYSFS_ERR_OUT_OF_MEMORY, 0);
- fh->buffer = newbuf;
- } /* else */
-
- fh->bufsize = bufsize;
- fh->buffill = fh->bufpos = 0;
- return 1;
-} /* PHYSFS_setBuffer */
-
-
-int PHYSFS_flush(PHYSFS_File *handle)
-{
- FileHandle *fh = (FileHandle *) handle;
- PHYSFS_Io *io;
- PHYSFS_sint64 rc;
-
- if ((fh->forReading) || (fh->bufpos == fh->buffill))
- return 1; /* open for read or buffer empty are successful no-ops. */
-
- /* dump buffer to disk. */
- io = fh->io;
- rc = io->write(io, fh->buffer + fh->bufpos, fh->buffill - fh->bufpos);
- BAIL_IF_MACRO(rc <= 0, ERRPASS, 0);
- fh->bufpos = fh->buffill = 0;
- return io->flush(io);
-} /* PHYSFS_flush */
-
-
-int PHYSFS_stat(const char *_fname, PHYSFS_Stat *stat)
-{
- int retval = 0;
- char *fname;
- size_t len;
-
- BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, -1);
- BAIL_IF_MACRO(!stat, PHYSFS_ERR_INVALID_ARGUMENT, -1);
- len = strlen(_fname) + 1;
- fname = (char *) __PHYSFS_smallAlloc(len);
- BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, -1);
-
- /* set some sane defaults... */
- stat->filesize = -1;
- stat->modtime = -1;
- stat->createtime = -1;
- stat->accesstime = -1;
- stat->filetype = PHYSFS_FILETYPE_OTHER;
- stat->readonly = 1; /* !!! FIXME */
-
- if (sanitizePlatformIndependentPath(_fname, fname))
- {
- if (*fname == '\0')
- {
- stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
- stat->readonly = !writeDir; /* Writeable if we have a writeDir */
- retval = 1;
- } /* if */
- else
- {
- DirHandle *i;
- int exists = 0;
- __PHYSFS_platformGrabMutex(stateLock);
- for (i = searchPath; ((i != NULL) && (!exists)); i = i->next)
- {
- char *arcfname = fname;
- exists = partOfMountPoint(i, arcfname);
- if (exists)
- {
- stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
- stat->readonly = 1; /* !!! FIXME */
- retval = 1;
- } /* if */
- else if (verifyPath(i, &arcfname, 0))
- {
- /* !!! FIXME: this test is wrong and should be elsewhere. */
- stat->readonly = !(writeDir &&
- (strcmp(writeDir->dirName, i->dirName) == 0));
- retval = i->funcs->stat(i->opaque, arcfname, &exists, stat);
- } /* else if */
- } /* for */
- __PHYSFS_platformReleaseMutex(stateLock);
- } /* else */
- } /* if */
-
- __PHYSFS_smallFree(fname);
- return retval;
-} /* PHYSFS_stat */
-
-
-int __PHYSFS_readAll(PHYSFS_Io *io, void *buf, const PHYSFS_uint64 len)
-{
- return (io->read(io, buf, len) == len);
-} /* __PHYSFS_readAll */
-
-
-void *__PHYSFS_initSmallAlloc(void *ptr, PHYSFS_uint64 len)
-{
- void *useHeap = ((ptr == NULL) ? ((void *) 1) : ((void *) 0));
- if (useHeap) /* too large for stack allocation or alloca() failed. */
- ptr = allocator.Malloc(len+sizeof (void *));
-
- if (ptr != NULL)
- {
- void **retval = (void **) ptr;
- /*printf("%s alloc'd (%d) bytes at (%p).\n",
- useHeap ? "heap" : "stack", (int) len, ptr);*/
- *retval = useHeap;
- return retval + 1;
- } /* if */
-
- return NULL; /* allocation failed. */
-} /* __PHYSFS_initSmallAlloc */
-
-
-void __PHYSFS_smallFree(void *ptr)
-{
- if (ptr != NULL)
- {
- void **block = ((void **) ptr) - 1;
- const int useHeap = (*block != 0);
- if (useHeap)
- allocator.Free(block);
- /*printf("%s free'd (%p).\n", useHeap ? "heap" : "stack", block);*/
- } /* if */
-} /* __PHYSFS_smallFree */
-
-
-int PHYSFS_setAllocator(const PHYSFS_Allocator *a)
-{
- BAIL_IF_MACRO(initialized, PHYSFS_ERR_IS_INITIALIZED, 0);
- externalAllocator = (a != NULL);
- if (externalAllocator)
- memcpy(&allocator, a, sizeof (PHYSFS_Allocator));
-
- return 1;
-} /* PHYSFS_setAllocator */
-
-
-const PHYSFS_Allocator *PHYSFS_getAllocator(void)
-{
- BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, NULL);
- return &allocator;
-} /* PHYSFS_getAllocator */
-
-
-static void *mallocAllocatorMalloc(PHYSFS_uint64 s)
-{
- if (!__PHYSFS_ui64FitsAddressSpace(s))
- BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
- #undef malloc
- return malloc((size_t) s);
-} /* mallocAllocatorMalloc */
-
-
-static void *mallocAllocatorRealloc(void *ptr, PHYSFS_uint64 s)
-{
- if (!__PHYSFS_ui64FitsAddressSpace(s))
- BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
- #undef realloc
- return realloc(ptr, (size_t) s);
-} /* mallocAllocatorRealloc */
-
-
-static void mallocAllocatorFree(void *ptr)
-{
- #undef free
- free(ptr);
-} /* mallocAllocatorFree */
-
-
-static void setDefaultAllocator(void)
-{
- assert(!externalAllocator);
- if (!__PHYSFS_platformSetDefaultAllocator(&allocator))
- {
- allocator.Init = NULL;
- allocator.Deinit = NULL;
- allocator.Malloc = mallocAllocatorMalloc;
- allocator.Realloc = mallocAllocatorRealloc;
- allocator.Free = mallocAllocatorFree;
- } /* if */
-} /* setDefaultAllocator */
-
-/* end of physfs.c ... */
-
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/src/physfs.h
--- a/misc/physfs/src/physfs.h Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,3324 +0,0 @@
-/**
- * \file physfs.h
- *
- * Main header file for PhysicsFS.
- */
-
-/**
- * \mainpage PhysicsFS
- *
- * The latest version of PhysicsFS can be found at:
- * http://icculus.org/physfs/
- *
- * PhysicsFS; a portable, flexible file i/o abstraction.
- *
- * This API gives you access to a system file system in ways superior to the
- * stdio or system i/o calls. The brief benefits:
- *
- * - It's portable.
- * - It's safe. No file access is permitted outside the specified dirs.
- * - It's flexible. Archives (.ZIP files) can be used transparently as
- * directory structures.
- *
- * This system is largely inspired by Quake 3's PK3 files and the related
- * fs_* cvars. If you've ever tinkered with these, then this API will be
- * familiar to you.
- *
- * With PhysicsFS, you have a single writing directory and multiple
- * directories (the "search path") for reading. You can think of this as a
- * filesystem within a filesystem. If (on Windows) you were to set the
- * writing directory to "C:\MyGame\MyWritingDirectory", then no PHYSFS calls
- * could touch anything above this directory, including the "C:\MyGame" and
- * "C:\" directories. This prevents an application's internal scripting
- * language from piddling over c:\\config.sys, for example. If you'd rather
- * give PHYSFS full access to the system's REAL file system, set the writing
- * dir to "C:\", but that's generally A Bad Thing for several reasons.
- *
- * Drive letters are hidden in PhysicsFS once you set up your initial paths.
- * The search path creates a single, hierarchical directory structure.
- * Not only does this lend itself well to general abstraction with archives,
- * it also gives better support to operating systems like MacOS and Unix.
- * Generally speaking, you shouldn't ever hardcode a drive letter; not only
- * does this hurt portability to non-Microsoft OSes, but it limits your win32
- * users to a single drive, too. Use the PhysicsFS abstraction functions and
- * allow user-defined configuration options, too. When opening a file, you
- * specify it like it was on a Unix filesystem: if you want to write to
- * "C:\MyGame\MyConfigFiles\game.cfg", then you might set the write dir to
- * "C:\MyGame" and then open "MyConfigFiles/game.cfg". This gives an
- * abstraction across all platforms. Specifying a file in this way is termed
- * "platform-independent notation" in this documentation. Specifying a
- * a filename in a form such as "C:\mydir\myfile" or
- * "MacOS hard drive:My Directory:My File" is termed "platform-dependent
- * notation". The only time you use platform-dependent notation is when
- * setting up your write directory and search path; after that, all file
- * access into those directories are done with platform-independent notation.
- *
- * All files opened for writing are opened in relation to the write directory,
- * which is the root of the writable filesystem. When opening a file for
- * reading, PhysicsFS goes through the search path. This is NOT the
- * same thing as the PATH environment variable. An application using
- * PhysicsFS specifies directories to be searched which may be actual
- * directories, or archive files that contain files and subdirectories of
- * their own. See the end of these docs for currently supported archive
- * formats.
- *
- * Once the search path is defined, you may open files for reading. If you've
- * got the following search path defined (to use a win32 example again):
- *
- * - C:\\mygame
- * - C:\\mygame\\myuserfiles
- * - D:\\mygamescdromdatafiles
- * - C:\\mygame\\installeddatafiles.zip
- *
- * Then a call to PHYSFS_openRead("textfiles/myfile.txt") (note the directory
- * separator, lack of drive letter, and lack of dir separator at the start of
- * the string; this is platform-independent notation) will check for
- * C:\\mygame\\textfiles\\myfile.txt, then
- * C:\\mygame\\myuserfiles\\textfiles\\myfile.txt, then
- * D:\\mygamescdromdatafiles\\textfiles\\myfile.txt, then, finally, for
- * textfiles\\myfile.txt inside of C:\\mygame\\installeddatafiles.zip.
- * Remember that most archive types and platform filesystems store their
- * filenames in a case-sensitive manner, so you should be careful to specify
- * it correctly.
- *
- * Files opened through PhysicsFS may NOT contain "." or ".." or ":" as dir
- * elements. Not only are these meaningless on MacOS Classic and/or Unix,
- * they are a security hole. Also, symbolic links (which can be found in
- * some archive types and directly in the filesystem on Unix platforms) are
- * NOT followed until you call PHYSFS_permitSymbolicLinks(). That's left to
- * your own discretion, as following a symlink can allow for access outside
- * the write dir and search paths. For portability, there is no mechanism for
- * creating new symlinks in PhysicsFS.
- *
- * The write dir is not included in the search path unless you specifically
- * add it. While you CAN change the write dir as many times as you like,
- * you should probably set it once and stick to it. Remember that your
- * program will not have permission to write in every directory on Unix and
- * NT systems.
- *
- * All files are opened in binary mode; there is no endline conversion for
- * textfiles. Other than that, PhysicsFS has some convenience functions for
- * platform-independence. There is a function to tell you the current
- * platform's dir separator ("\\" on windows, "/" on Unix, ":" on MacOS),
- * which is needed only to set up your search/write paths. There is a
- * function to tell you what CD-ROM drives contain accessible discs, and a
- * function to recommend a good search path, etc.
- *
- * A recommended order for the search path is the write dir, then the base dir,
- * then the cdrom dir, then any archives discovered. Quake 3 does something
- * like this, but moves the archives to the start of the search path. Build
- * Engine games, like Duke Nukem 3D and Blood, place the archives last, and
- * use the base dir for both searching and writing. There is a helper
- * function (PHYSFS_setSaneConfig()) that puts together a basic configuration
- * for you, based on a few parameters. Also see the comments on
- * PHYSFS_getBaseDir(), and PHYSFS_getPrefDir() for info on what those
- * are and how they can help you determine an optimal search path.
- *
- * PhysicsFS 2.0 adds the concept of "mounting" archives to arbitrary points
- * in the search path. If a zipfile contains "maps/level.map" and you mount
- * that archive at "mods/mymod", then you would have to open
- * "mods/mymod/maps/level.map" to access the file, even though "mods/mymod"
- * isn't actually specified in the .zip file. Unlike the Unix mentality of
- * mounting a filesystem, "mods/mymod" doesn't actually have to exist when
- * mounting the zipfile. It's a "virtual" directory. The mounting mechanism
- * allows the developer to seperate archives in the tree and avoid trampling
- * over files when added new archives, such as including mod support in a
- * game...keeping external content on a tight leash in this manner can be of
- * utmost importance to some applications.
- *
- * PhysicsFS is mostly thread safe. The error messages returned by
- * PHYSFS_getLastError() are unique by thread, and library-state-setting
- * functions are mutex'd. For efficiency, individual file accesses are
- * not locked, so you can not safely read/write/seek/close/etc the same
- * file from two threads at the same time. Other race conditions are bugs
- * that should be reported/patched.
- *
- * While you CAN use stdio/syscall file access in a program that has PHYSFS_*
- * calls, doing so is not recommended, and you can not use system
- * filehandles with PhysicsFS and vice versa.
- *
- * Note that archives need not be named as such: if you have a ZIP file and
- * rename it with a .PKG extension, the file will still be recognized as a
- * ZIP archive by PhysicsFS; the file's contents are used to determine its
- * type where possible.
- *
- * Currently supported archive types:
- * - .ZIP (pkZip/WinZip/Info-ZIP compatible)
- * - .7Z (7zip archives)
- * - .ISO (ISO9660 files, CD-ROM images)
- * - .GRP (Build Engine groupfile archives)
- * - .PAK (Quake I/II archive format)
- * - .HOG (Descent I/II HOG file archives)
- * - .MVL (Descent II movielib archives)
- * - .WAD (DOOM engine archives)
- *
- *
- * String policy for PhysicsFS 2.0 and later:
- *
- * PhysicsFS 1.0 could only deal with null-terminated ASCII strings. All high
- * ASCII chars resulted in undefined behaviour, and there was no Unicode
- * support at all. PhysicsFS 2.0 supports Unicode without breaking binary
- * compatibility with the 1.0 API by using UTF-8 encoding of all strings
- * passed in and out of the library.
- *
- * All strings passed through PhysicsFS are in null-terminated UTF-8 format.
- * This means that if all you care about is English (ASCII characters <= 127)
- * then you just use regular C strings. If you care about Unicode (and you
- * should!) then you need to figure out what your platform wants, needs, and
- * offers. If you are on Windows before Win2000 and build with Unicode
- * support, your TCHAR strings are two bytes per character (this is called
- * "UCS-2 encoding"). Any modern Windows uses UTF-16, which is two bytes
- * per character for most characters, but some characters are four. You
- * should convert them to UTF-8 before handing them to PhysicsFS with
- * PHYSFS_utf8FromUtf16(), which handles both UTF-16 and UCS-2. If you're
- * using Unix or Mac OS X, your wchar_t strings are four bytes per character
- * ("UCS-4 encoding"). Use PHYSFS_utf8FromUcs4(). Mac OS X can give you UTF-8
- * directly from a CFString or NSString, and many Unixes generally give you C
- * strings in UTF-8 format everywhere. If you have a single-byte high ASCII
- * charset, like so-many European "codepages" you may be out of luck. We'll
- * convert from "Latin1" to UTF-8 only, and never back to Latin1. If you're
- * above ASCII 127, all bets are off: move to Unicode or use your platform's
- * facilities. Passing a C string with high-ASCII data that isn't UTF-8
- * encoded will NOT do what you expect!
- *
- * Naturally, there's also PHYSFS_utf8ToUcs2(), PHYSFS_utf8ToUtf16(), and
- * PHYSFS_utf8ToUcs4() to get data back into a format you like. Behind the
- * scenes, PhysicsFS will use Unicode where possible: the UTF-8 strings on
- * Windows will be converted and used with the multibyte Windows APIs, for
- * example.
- *
- * PhysicsFS offers basic encoding conversion support, but not a whole string
- * library. Get your stuff into whatever format you can work with.
- *
- * All platforms supported by PhysicsFS 2.1 and later fully support Unicode.
- * We have dropped platforms that don't (OS/2, Mac OS 9, Windows 95, etc), as
- * even an OS that's over a decade old should be expected to handle this well.
- * If you absolutely must support one of these platforms, you should use an
- * older release of PhysicsFS.
- *
- * Many game-specific archivers are seriously unprepared for Unicode (the
- * Descent HOG/MVL and Build Engine GRP archivers, for example, only offer a
- * DOS 8.3 filename, for example). Nothing can be done for these, but they
- * tend to be legacy formats for existing content that was all ASCII (and
- * thus, valid UTF-8) anyhow. Other formats, like .ZIP, don't explicitly
- * offer Unicode support, but unofficially expect filenames to be UTF-8
- * encoded, and thus Just Work. Most everything does the right thing without
- * bothering you, but it's good to be aware of these nuances in case they
- * don't.
- *
- *
- * Other stuff:
- *
- * Please see the file LICENSE.txt in the source's root directory for
- * licensing and redistribution rights.
- *
- * Please see the file CREDITS.txt in the source's "docs" directory for
- * a more or less complete list of who's responsible for this.
- *
- * \author Ryan C. Gordon.
- */
-
-#ifndef _INCLUDE_PHYSFS_H_
-#define _INCLUDE_PHYSFS_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if defined(PHYSFS_DECL)
-/* do nothing. */
-#elif (defined SWIG)
-#define PHYSFS_DECL extern
-#elif (defined _MSC_VER)
-#define PHYSFS_DECL __declspec(dllexport)
-#elif (defined __SUNPRO_C)
-#define PHYSFS_DECL __global
-#elif ((__GNUC__ >= 3) && (!__EMX__) && (!sun))
-#define PHYSFS_DECL __attribute__((visibility("default")))
-#else
-#define PHYSFS_DECL
-#endif
-
-#if defined(PHYSFS_DEPRECATED)
-/* do nothing. */
-#elif (defined SWIG) /* ignore deprecated, since bindings use everything. */
-#define PHYSFS_DEPRECATED
-#elif (__GNUC__ >= 4) /* technically, this arrived in gcc 3.1, but oh well. */
-#define PHYSFS_DEPRECATED __attribute__((deprecated))
-#else
-#define PHYSFS_DEPRECATED
-#endif
-
-#if 0 /* !!! FIXME: look into this later. */
-#if defined(PHYSFS_CALL)
-/* do nothing. */
-#elif defined(__WIN32__) && !defined(__GNUC__)
-#define PHYSFS_CALL __cdecl
-#else
-#define PHYSFS_CALL
-#endif
-#endif
-
-/**
- * \typedef PHYSFS_uint8
- * \brief An unsigned, 8-bit integer type.
- */
-typedef unsigned char PHYSFS_uint8;
-
-/**
- * \typedef PHYSFS_sint8
- * \brief A signed, 8-bit integer type.
- */
-typedef signed char PHYSFS_sint8;
-
-/**
- * \typedef PHYSFS_uint16
- * \brief An unsigned, 16-bit integer type.
- */
-typedef unsigned short PHYSFS_uint16;
-
-/**
- * \typedef PHYSFS_sint16
- * \brief A signed, 16-bit integer type.
- */
-typedef signed short PHYSFS_sint16;
-
-/**
- * \typedef PHYSFS_uint32
- * \brief An unsigned, 32-bit integer type.
- */
-typedef unsigned int PHYSFS_uint32;
-
-/**
- * \typedef PHYSFS_sint32
- * \brief A signed, 32-bit integer type.
- */
-typedef signed int PHYSFS_sint32;
-
-/**
- * \typedef PHYSFS_uint64
- * \brief An unsigned, 64-bit integer type.
- * \warning on platforms without any sort of 64-bit datatype, this is
- * equivalent to PHYSFS_uint32!
- */
-
-/**
- * \typedef PHYSFS_sint64
- * \brief A signed, 64-bit integer type.
- * \warning on platforms without any sort of 64-bit datatype, this is
- * equivalent to PHYSFS_sint32!
- */
-
-
-#if (defined PHYSFS_NO_64BIT_SUPPORT) /* oh well. */
-typedef PHYSFS_uint32 PHYSFS_uint64;
-typedef PHYSFS_sint32 PHYSFS_sint64;
-#elif (defined _MSC_VER)
-typedef signed __int64 PHYSFS_sint64;
-typedef unsigned __int64 PHYSFS_uint64;
-#else
-typedef unsigned long long PHYSFS_uint64;
-typedef signed long long PHYSFS_sint64;
-#endif
-
-
-#ifndef SWIG
-#ifndef DOXYGEN_SHOULD_IGNORE_THIS
-/* Make sure the types really have the right sizes */
-#define PHYSFS_COMPILE_TIME_ASSERT(name, x) \
- typedef int PHYSFS_dummy_ ## name[(x) * 2 - 1]
-
-PHYSFS_COMPILE_TIME_ASSERT(uint8, sizeof(PHYSFS_uint8) == 1);
-PHYSFS_COMPILE_TIME_ASSERT(sint8, sizeof(PHYSFS_sint8) == 1);
-PHYSFS_COMPILE_TIME_ASSERT(uint16, sizeof(PHYSFS_uint16) == 2);
-PHYSFS_COMPILE_TIME_ASSERT(sint16, sizeof(PHYSFS_sint16) == 2);
-PHYSFS_COMPILE_TIME_ASSERT(uint32, sizeof(PHYSFS_uint32) == 4);
-PHYSFS_COMPILE_TIME_ASSERT(sint32, sizeof(PHYSFS_sint32) == 4);
-
-#ifndef PHYSFS_NO_64BIT_SUPPORT
-PHYSFS_COMPILE_TIME_ASSERT(uint64, sizeof(PHYSFS_uint64) == 8);
-PHYSFS_COMPILE_TIME_ASSERT(sint64, sizeof(PHYSFS_sint64) == 8);
-#endif
-
-#undef PHYSFS_COMPILE_TIME_ASSERT
-
-#endif /* DOXYGEN_SHOULD_IGNORE_THIS */
-#endif /* SWIG */
-
-
-/**
- * \struct PHYSFS_File
- * \brief A PhysicsFS file handle.
- *
- * You get a pointer to one of these when you open a file for reading,
- * writing, or appending via PhysicsFS.
- *
- * As you can see from the lack of meaningful fields, you should treat this
- * as opaque data. Don't try to manipulate the file handle, just pass the
- * pointer you got, unmolested, to various PhysicsFS APIs.
- *
- * \sa PHYSFS_openRead
- * \sa PHYSFS_openWrite
- * \sa PHYSFS_openAppend
- * \sa PHYSFS_close
- * \sa PHYSFS_read
- * \sa PHYSFS_write
- * \sa PHYSFS_seek
- * \sa PHYSFS_tell
- * \sa PHYSFS_eof
- * \sa PHYSFS_setBuffer
- * \sa PHYSFS_flush
- */
-typedef struct PHYSFS_File
-{
- void *opaque; /**< That's all you get. Don't touch. */
-} PHYSFS_File;
-
-
-/**
- * \def PHYSFS_file
- * \brief 1.0 API compatibility define.
- *
- * PHYSFS_file is identical to PHYSFS_File. This #define is here for backwards
- * compatibility with the 1.0 API, which had an inconsistent capitalization
- * convention in this case. New code should use PHYSFS_File, as this #define
- * may go away someday.
- *
- * \sa PHYSFS_File
- */
-#define PHYSFS_file PHYSFS_File
-
-
-/**
- * \struct PHYSFS_ArchiveInfo
- * \brief Information on various PhysicsFS-supported archives.
- *
- * This structure gives you details on what sort of archives are supported
- * by this implementation of PhysicsFS. Archives tend to be things like
- * ZIP files and such.
- *
- * \warning Not all binaries are created equal! PhysicsFS can be built with
- * or without support for various archives. You can check with
- * PHYSFS_supportedArchiveTypes() to see if your archive type is
- * supported.
- *
- * \sa PHYSFS_supportedArchiveTypes
- */
-typedef struct PHYSFS_ArchiveInfo
-{
- const char *extension; /**< Archive file extension: "ZIP", for example. */
- const char *description; /**< Human-readable archive description. */
- const char *author; /**< Person who did support for this archive. */
- const char *url; /**< URL related to this archive */
-} PHYSFS_ArchiveInfo;
-
-
-/**
- * \struct PHYSFS_Version
- * \brief Information the version of PhysicsFS in use.
- *
- * Represents the library's version as three levels: major revision
- * (increments with massive changes, additions, and enhancements),
- * minor revision (increments with backwards-compatible changes to the
- * major revision), and patchlevel (increments with fixes to the minor
- * revision).
- *
- * \sa PHYSFS_VERSION
- * \sa PHYSFS_getLinkedVersion
- */
-typedef struct PHYSFS_Version
-{
- PHYSFS_uint8 major; /**< major revision */
- PHYSFS_uint8 minor; /**< minor revision */
- PHYSFS_uint8 patch; /**< patchlevel */
-} PHYSFS_Version;
-
-
-#ifndef SWIG /* not available from scripting languages. */
-
-#ifndef DOXYGEN_SHOULD_IGNORE_THIS
-#define PHYSFS_VER_MAJOR 2
-#define PHYSFS_VER_MINOR 1
-#define PHYSFS_VER_PATCH 0
-#endif /* DOXYGEN_SHOULD_IGNORE_THIS */
-
-
-/* PhysicsFS state stuff ... */
-
-/**
- * \def PHYSFS_VERSION(x)
- * \brief Macro to determine PhysicsFS version program was compiled against.
- *
- * This macro fills in a PHYSFS_Version structure with the version of the
- * library you compiled against. This is determined by what header the
- * compiler uses. Note that if you dynamically linked the library, you might
- * have a slightly newer or older version at runtime. That version can be
- * determined with PHYSFS_getLinkedVersion(), which, unlike PHYSFS_VERSION,
- * is not a macro.
- *
- * \param x A pointer to a PHYSFS_Version struct to initialize.
- *
- * \sa PHYSFS_Version
- * \sa PHYSFS_getLinkedVersion
- */
-#define PHYSFS_VERSION(x) \
-{ \
- (x)->major = PHYSFS_VER_MAJOR; \
- (x)->minor = PHYSFS_VER_MINOR; \
- (x)->patch = PHYSFS_VER_PATCH; \
-}
-
-#endif /* SWIG */
-
-
-/**
- * \fn void PHYSFS_getLinkedVersion(PHYSFS_Version *ver)
- * \brief Get the version of PhysicsFS that is linked against your program.
- *
- * If you are using a shared library (DLL) version of PhysFS, then it is
- * possible that it will be different than the version you compiled against.
- *
- * This is a real function; the macro PHYSFS_VERSION tells you what version
- * of PhysFS you compiled against:
- *
- * \code
- * PHYSFS_Version compiled;
- * PHYSFS_Version linked;
- *
- * PHYSFS_VERSION(&compiled);
- * PHYSFS_getLinkedVersion(&linked);
- * printf("We compiled against PhysFS version %d.%d.%d ...\n",
- * compiled.major, compiled.minor, compiled.patch);
- * printf("But we linked against PhysFS version %d.%d.%d.\n",
- * linked.major, linked.minor, linked.patch);
- * \endcode
- *
- * This function may be called safely at any time, even before PHYSFS_init().
- *
- * \sa PHYSFS_VERSION
- */
-PHYSFS_DECL void PHYSFS_getLinkedVersion(PHYSFS_Version *ver);
-
-
-/**
- * \fn int PHYSFS_init(const char *argv0)
- * \brief Initialize the PhysicsFS library.
- *
- * This must be called before any other PhysicsFS function.
- *
- * This should be called prior to any attempts to change your process's
- * current working directory.
- *
- * \param argv0 the argv[0] string passed to your program's mainline.
- * This may be NULL on most platforms (such as ones without a
- * standard main() function), but you should always try to pass
- * something in here. Unix-like systems such as Linux _need_ to
- * pass argv[0] from main() in here.
- * \return nonzero on success, zero on error. Specifics of the error can be
- * gleaned from PHYSFS_getLastError().
- *
- * \sa PHYSFS_deinit
- * \sa PHYSFS_isInit
- */
-PHYSFS_DECL int PHYSFS_init(const char *argv0);
-
-
-/**
- * \fn int PHYSFS_deinit(void)
- * \brief Deinitialize the PhysicsFS library.
- *
- * This closes any files opened via PhysicsFS, blanks the search/write paths,
- * frees memory, and invalidates all of your file handles.
- *
- * Note that this call can FAIL if there's a file open for writing that
- * refuses to close (for example, the underlying operating system was
- * buffering writes to network filesystem, and the fileserver has crashed,
- * or a hard drive has failed, etc). It is usually best to close all write
- * handles yourself before calling this function, so that you can gracefully
- * handle a specific failure.
- *
- * Once successfully deinitialized, PHYSFS_init() can be called again to
- * restart the subsystem. All default API states are restored at this
- * point, with the exception of any custom allocator you might have
- * specified, which survives between initializations.
- *
- * \return nonzero on success, zero on error. Specifics of the error can be
- * gleaned from PHYSFS_getLastError(). If failure, state of PhysFS is
- * undefined, and probably badly screwed up.
- *
- * \sa PHYSFS_init
- * \sa PHYSFS_isInit
- */
-PHYSFS_DECL int PHYSFS_deinit(void);
-
-
-/**
- * \fn const PHYSFS_ArchiveInfo **PHYSFS_supportedArchiveTypes(void)
- * \brief Get a list of supported archive types.
- *
- * Get a list of archive types supported by this implementation of PhysicFS.
- * These are the file formats usable for search path entries. This is for
- * informational purposes only. Note that the extension listed is merely
- * convention: if we list "ZIP", you can open a PkZip-compatible archive
- * with an extension of "XYZ", if you like.
- *
- * The returned value is an array of pointers to PHYSFS_ArchiveInfo structures,
- * with a NULL entry to signify the end of the list:
- *
- * \code
- * PHYSFS_ArchiveInfo **i;
- *
- * for (i = PHYSFS_supportedArchiveTypes(); *i != NULL; i++)
- * {
- * printf("Supported archive: [%s], which is [%s].\n",
- * (*i)->extension, (*i)->description);
- * }
- * \endcode
- *
- * The return values are pointers to internal memory, and should
- * be considered READ ONLY, and never freed. The returned values are
- * valid until the next call to PHYSFS_deinit().
- *
- * \return READ ONLY Null-terminated array of READ ONLY structures.
- */
-PHYSFS_DECL const PHYSFS_ArchiveInfo **PHYSFS_supportedArchiveTypes(void);
-
-
-/**
- * \fn void PHYSFS_freeList(void *listVar)
- * \brief Deallocate resources of lists returned by PhysicsFS.
- *
- * Certain PhysicsFS functions return lists of information that are
- * dynamically allocated. Use this function to free those resources.
- *
- * It is safe to pass a NULL here, but doing so will cause a crash in versions
- * before PhysicsFS 2.1.0.
- *
- * \param listVar List of information specified as freeable by this function.
- * Passing NULL is safe; it is a valid no-op.
- *
- * \sa PHYSFS_getCdRomDirs
- * \sa PHYSFS_enumerateFiles
- * \sa PHYSFS_getSearchPath
- */
-PHYSFS_DECL void PHYSFS_freeList(void *listVar);
-
-
-/**
- * \fn const char *PHYSFS_getLastError(void)
- * \brief Get human-readable error information.
- *
- * \warning As of PhysicsFS 2.1, this function has been nerfed.
- * Before PhysicsFS 2.1, this function was the only way to get
- * error details beyond a given function's basic return value.
- * This was meant to be a human-readable string in one of several
- * languages, and was not useful for application parsing. This was
- * a problem, because the developer and not the user chose the
- * language at compile time, and the PhysicsFS maintainers had
- * to (poorly) maintain a significant amount of localization work.
- * The app couldn't parse the strings, even if they counted on a
- * specific language, since some were dynamically generated.
- * In 2.1 and later, this always returns a static string in
- * English; you may use it as a key string for your own
- * localizations if you like, as we'll promise not to change
- * existing error strings. Also, if your application wants to
- * look at specific errors, we now offer a better option:
- * use PHYSFS_getLastErrorCode() instead.
- *
- * Get the last PhysicsFS error message as a human-readable, null-terminated
- * string. This will return NULL if there's been no error since the last call
- * to this function. The pointer returned by this call points to an internal
- * buffer. Each thread has a unique error state associated with it, but each
- * time a new error message is set, it will overwrite the previous one
- * associated with that thread. It is safe to call this function at anytime,
- * even before PHYSFS_init().
- *
- * PHYSFS_getLastError() and PHYSFS_getLastErrorCode() both reset the same
- * thread-specific error state. Calling one will wipe out the other's
- * data. If you need both, call PHYSFS_getLastErrorCode(), then pass that
- * value to PHYSFS_getErrorByCode().
- *
- * As of PhysicsFS 2.1, this function only presents text in the English
- * language, but the strings are static, so you can use them as keys into
- * your own localization dictionary. These strings are meant to be passed on
- * directly to the user.
- *
- * Generally, applications should only concern themselves with whether a
- * given function failed; however, if your code require more specifics, you
- * should use PHYSFS_getLastErrorCode() instead of this function.
- *
- * \return READ ONLY string of last error message.
- *
- * \sa PHYSFS_getLastErrorCode
- * \sa PHYSFS_getErrorByCode
- */
-PHYSFS_DECL const char *PHYSFS_getLastError(void);
-
-
-/**
- * \fn const char *PHYSFS_getDirSeparator(void)
- * \brief Get platform-dependent dir separator string.
- *
- * This returns "\\" on win32, "/" on Unix, and ":" on MacOS. It may be more
- * than one character, depending on the platform, and your code should take
- * that into account. Note that this is only useful for setting up the
- * search/write paths, since access into those dirs always use '/'
- * (platform-independent notation) to separate directories. This is also
- * handy for getting platform-independent access when using stdio calls.
- *
- * \return READ ONLY null-terminated string of platform's dir separator.
- */
-PHYSFS_DECL const char *PHYSFS_getDirSeparator(void);
-
-
-/**
- * \fn void PHYSFS_permitSymbolicLinks(int allow)
- * \brief Enable or disable following of symbolic links.
- *
- * Some physical filesystems and archives contain files that are just pointers
- * to other files. On the physical filesystem, opening such a link will
- * (transparently) open the file that is pointed to.
- *
- * By default, PhysicsFS will check if a file is really a symlink during open
- * calls and fail if it is. Otherwise, the link could take you outside the
- * write and search paths, and compromise security.
- *
- * If you want to take that risk, call this function with a non-zero parameter.
- * Note that this is more for sandboxing a program's scripting language, in
- * case untrusted scripts try to compromise the system. Generally speaking,
- * a user could very well have a legitimate reason to set up a symlink, so
- * unless you feel there's a specific danger in allowing them, you should
- * permit them.
- *
- * Symlinks are only explicitly checked when dealing with filenames
- * in platform-independent notation. That is, when setting up your
- * search and write paths, etc, symlinks are never checked for.
- *
- * Please note that PHYSFS_stat() will always check the path specified; if
- * that path is a symlink, it will not be followed in any case. If symlinks
- * aren't permitted through this function, PHYSFS_stat() ignores them, and
- * would treat the query as if the path didn't exist at all.
- *
- * Symbolic link permission can be enabled or disabled at any time after
- * you've called PHYSFS_init(), and is disabled by default.
- *
- * \param allow nonzero to permit symlinks, zero to deny linking.
- *
- * \sa PHYSFS_symbolicLinksPermitted
- */
-PHYSFS_DECL void PHYSFS_permitSymbolicLinks(int allow);
-
-
-/* !!! FIXME: const this? */
-/**
- * \fn char **PHYSFS_getCdRomDirs(void)
- * \brief Get an array of paths to available CD-ROM drives.
- *
- * The dirs returned are platform-dependent ("D:\" on Win32, "/cdrom" or
- * whatnot on Unix). Dirs are only returned if there is a disc ready and
- * accessible in the drive. So if you've got two drives (D: and E:), and only
- * E: has a disc in it, then that's all you get. If the user inserts a disc
- * in D: and you call this function again, you get both drives. If, on a
- * Unix box, the user unmounts a disc and remounts it elsewhere, the next
- * call to this function will reflect that change.
- *
- * This function refers to "CD-ROM" media, but it really means "inserted disc
- * media," such as DVD-ROM, HD-DVD, CDRW, and Blu-Ray discs. It looks for
- * filesystems, and as such won't report an audio CD, unless there's a
- * mounted filesystem track on it.
- *
- * The returned value is an array of strings, with a NULL entry to signify the
- * end of the list:
- *
- * \code
- * char **cds = PHYSFS_getCdRomDirs();
- * char **i;
- *
- * for (i = cds; *i != NULL; i++)
- * printf("cdrom dir [%s] is available.\n", *i);
- *
- * PHYSFS_freeList(cds);
- * \endcode
- *
- * This call may block while drives spin up. Be forewarned.
- *
- * When you are done with the returned information, you may dispose of the
- * resources by calling PHYSFS_freeList() with the returned pointer.
- *
- * \return Null-terminated array of null-terminated strings.
- *
- * \sa PHYSFS_getCdRomDirsCallback
- */
-PHYSFS_DECL char **PHYSFS_getCdRomDirs(void);
-
-
-/**
- * \fn const char *PHYSFS_getBaseDir(void)
- * \brief Get the path where the application resides.
- *
- * Helper function.
- *
- * Get the "base dir". This is the directory where the application was run
- * from, which is probably the installation directory, and may or may not
- * be the process's current working directory.
- *
- * You should probably use the base dir in your search path.
- *
- * \return READ ONLY string of base dir in platform-dependent notation.
- *
- * \sa PHYSFS_getPrefDir
- */
-PHYSFS_DECL const char *PHYSFS_getBaseDir(void);
-
-
-/**
- * \fn const char *PHYSFS_getUserDir(void)
- * \brief Get the path where user's home directory resides.
- *
- * \deprecated As of PhysicsFS 2.1, you probably want PHYSFS_getPrefDir().
- *
- * Helper function.
- *
- * Get the "user dir". This is meant to be a suggestion of where a specific
- * user of the system can store files. On Unix, this is her home directory.
- * On systems with no concept of multiple home directories (MacOS, win95),
- * this will default to something like "C:\mybasedir\users\username"
- * where "username" will either be the login name, or "default" if the
- * platform doesn't support multiple users, either.
- *
- * \return READ ONLY string of user dir in platform-dependent notation.
- *
- * \sa PHYSFS_getBaseDir
- * \sa PHYSFS_getPrefDir
- */
-PHYSFS_DECL const char *PHYSFS_getUserDir(void) PHYSFS_DEPRECATED;
-
-
-/**
- * \fn const char *PHYSFS_getWriteDir(void)
- * \brief Get path where PhysicsFS will allow file writing.
- *
- * Get the current write dir. The default write dir is NULL.
- *
- * \return READ ONLY string of write dir in platform-dependent notation,
- * OR NULL IF NO WRITE PATH IS CURRENTLY SET.
- *
- * \sa PHYSFS_setWriteDir
- */
-PHYSFS_DECL const char *PHYSFS_getWriteDir(void);
-
-
-/**
- * \fn int PHYSFS_setWriteDir(const char *newDir)
- * \brief Tell PhysicsFS where it may write files.
- *
- * Set a new write dir. This will override the previous setting.
- *
- * This call will fail (and fail to change the write dir) if the current
- * write dir still has files open in it.
- *
- * \param newDir The new directory to be the root of the write dir,
- * specified in platform-dependent notation. Setting to NULL
- * disables the write dir, so no files can be opened for
- * writing via PhysicsFS.
- * \return non-zero on success, zero on failure. All attempts to open a file
- * for writing via PhysicsFS will fail until this call succeeds.
- * Specifics of the error can be gleaned from PHYSFS_getLastError().
- *
- * \sa PHYSFS_getWriteDir
- */
-PHYSFS_DECL int PHYSFS_setWriteDir(const char *newDir);
-
-
-/**
- * \fn int PHYSFS_addToSearchPath(const char *newDir, int appendToPath)
- * \brief Add an archive or directory to the search path.
- *
- * \deprecated As of PhysicsFS 2.0, use PHYSFS_mount() instead. This
- * function just wraps it anyhow.
- *
- * This function is equivalent to:
- *
- * \code
- * PHYSFS_mount(newDir, NULL, appendToPath);
- * \endcode
- *
- * You must use this and not PHYSFS_mount if binary compatibility with
- * PhysicsFS 1.0 is important (which it may not be for many people).
- *
- * \sa PHYSFS_mount
- * \sa PHYSFS_removeFromSearchPath
- * \sa PHYSFS_getSearchPath
- */
-PHYSFS_DECL int PHYSFS_addToSearchPath(const char *newDir, int appendToPath)
- PHYSFS_DEPRECATED;
-
-/**
- * \fn int PHYSFS_removeFromSearchPath(const char *oldDir)
- * \brief Remove a directory or archive from the search path.
- *
- * \deprecated As of PhysicsFS 2.1, use PHYSFS_unmount() instead. This
- * function just wraps it anyhow. There's no functional difference
- * except the vocabulary changed from "adding to the search path"
- * to "mounting" when that functionality was extended, and thus
- * the preferred way to accomplish this function's work is now
- * called "unmounting."
- *
- * This function is equivalent to:
- *
- * \code
- * PHYSFS_unmount(oldDir);
- * \endcode
- *
- * You must use this and not PHYSFS_unmount if binary compatibility with
- * PhysicsFS 1.0 is important (which it may not be for many people).
- *
- * \sa PHYSFS_addToSearchPath
- * \sa PHYSFS_getSearchPath
- * \sa PHYSFS_unmount
- */
-PHYSFS_DECL int PHYSFS_removeFromSearchPath(const char *oldDir)
- PHYSFS_DEPRECATED;
-
-
-/**
- * \fn char **PHYSFS_getSearchPath(void)
- * \brief Get the current search path.
- *
- * The default search path is an empty list.
- *
- * The returned value is an array of strings, with a NULL entry to signify the
- * end of the list:
- *
- * \code
- * char **i;
- *
- * for (i = PHYSFS_getSearchPath(); *i != NULL; i++)
- * printf("[%s] is in the search path.\n", *i);
- * \endcode
- *
- * When you are done with the returned information, you may dispose of the
- * resources by calling PHYSFS_freeList() with the returned pointer.
- *
- * \return Null-terminated array of null-terminated strings. NULL if there
- * was a problem (read: OUT OF MEMORY).
- *
- * \sa PHYSFS_getSearchPathCallback
- * \sa PHYSFS_addToSearchPath
- * \sa PHYSFS_removeFromSearchPath
- */
-PHYSFS_DECL char **PHYSFS_getSearchPath(void);
-
-
-/**
- * \fn int PHYSFS_setSaneConfig(const char *organization, const char *appName, const char *archiveExt, int includeCdRoms, int archivesFirst)
- * \brief Set up sane, default paths.
- *
- * Helper function.
- *
- * The write dir will be set to the pref dir returned by
- * \code PHYSFS_getPrefDir(organization, appName) \endcode, which is
- * created if it doesn't exist.
- *
- * The above is sufficient to make sure your program's configuration directory
- * is separated from other clutter, and platform-independent.
- *
- * The search path will be:
- *
- * - The Write Dir (created if it doesn't exist)
- * - The Base Dir (PHYSFS_getBaseDir())
- * - All found CD-ROM dirs (optionally)
- *
- * These directories are then searched for files ending with the extension
- * (archiveExt), which, if they are valid and supported archives, will also
- * be added to the search path. If you specified "PKG" for (archiveExt), and
- * there's a file named data.PKG in the base dir, it'll be checked. Archives
- * can either be appended or prepended to the search path in alphabetical
- * order, regardless of which directories they were found in. All archives
- * are mounted in the root of the virtual file system ("/").
- *
- * All of this can be accomplished from the application, but this just does it
- * all for you. Feel free to add more to the search path manually, too.
- *
- * \param organization Name of your company/group/etc to be used as a
- * dirname, so keep it small, and no-frills.
- *
- * \param appName Program-specific name of your program, to separate it
- * from other programs using PhysicsFS.
- *
- * \param archiveExt File extension used by your program to specify an
- * archive. For example, Quake 3 uses "pk3", even though
- * they are just zipfiles. Specify NULL to not dig out
- * archives automatically. Do not specify the '.' char;
- * If you want to look for ZIP files, specify "ZIP" and
- * not ".ZIP" ... the archive search is case-insensitive.
- *
- * \param includeCdRoms Non-zero to include CD-ROMs in the search path, and
- * (if (archiveExt) != NULL) search them for archives.
- * This may cause a significant amount of blocking
- * while discs are accessed, and if there are no discs
- * in the drive (or even not mounted on Unix systems),
- * then they may not be made available anyhow. You may
- * want to specify zero and handle the disc setup
- * yourself.
- *
- * \param archivesFirst Non-zero to prepend the archives to the search path.
- * Zero to append them. Ignored if !(archiveExt).
- *
- * \return nonzero on success, zero on error. Specifics of the error can be
- * gleaned from PHYSFS_getLastError().
- */
-PHYSFS_DECL int PHYSFS_setSaneConfig(const char *organization,
- const char *appName,
- const char *archiveExt,
- int includeCdRoms,
- int archivesFirst);
-
-
-/* Directory management stuff ... */
-
-/**
- * \fn int PHYSFS_mkdir(const char *dirName)
- * \brief Create a directory.
- *
- * This is specified in platform-independent notation in relation to the
- * write dir. All missing parent directories are also created if they
- * don't exist.
- *
- * So if you've got the write dir set to "C:\mygame\writedir" and call
- * PHYSFS_mkdir("downloads/maps") then the directories
- * "C:\mygame\writedir\downloads" and "C:\mygame\writedir\downloads\maps"
- * will be created if possible. If the creation of "maps" fails after we
- * have successfully created "downloads", then the function leaves the
- * created directory behind and reports failure.
- *
- * \param dirName New dir to create.
- * \return nonzero on success, zero on error. Specifics of the error can be
- * gleaned from PHYSFS_getLastError().
- *
- * \sa PHYSFS_delete
- */
-PHYSFS_DECL int PHYSFS_mkdir(const char *dirName);
-
-
-/**
- * \fn int PHYSFS_delete(const char *filename)
- * \brief Delete a file or directory.
- *
- * (filename) is specified in platform-independent notation in relation to the
- * write dir.
- *
- * A directory must be empty before this call can delete it.
- *
- * Deleting a symlink will remove the link, not what it points to, regardless
- * of whether you "permitSymLinks" or not.
- *
- * So if you've got the write dir set to "C:\mygame\writedir" and call
- * PHYSFS_delete("downloads/maps/level1.map") then the file
- * "C:\mygame\writedir\downloads\maps\level1.map" is removed from the
- * physical filesystem, if it exists and the operating system permits the
- * deletion.
- *
- * Note that on Unix systems, deleting a file may be successful, but the
- * actual file won't be removed until all processes that have an open
- * filehandle to it (including your program) close their handles.
- *
- * Chances are, the bits that make up the file still exist, they are just
- * made available to be written over at a later point. Don't consider this
- * a security method or anything. :)
- *
- * \param filename Filename to delete.
- * \return nonzero on success, zero on error. Specifics of the error can be
- * gleaned from PHYSFS_getLastError().
- */
-PHYSFS_DECL int PHYSFS_delete(const char *filename);
-
-
-/**
- * \fn const char *PHYSFS_getRealDir(const char *filename)
- * \brief Figure out where in the search path a file resides.
- *
- * The file is specified in platform-independent notation. The returned
- * filename will be the element of the search path where the file was found,
- * which may be a directory, or an archive. Even if there are multiple
- * matches in different parts of the search path, only the first one found
- * is used, just like when opening a file.
- *
- * So, if you look for "maps/level1.map", and C:\\mygame is in your search
- * path and C:\\mygame\\maps\\level1.map exists, then "C:\mygame" is returned.
- *
- * If a any part of a match is a symbolic link, and you've not explicitly
- * permitted symlinks, then it will be ignored, and the search for a match
- * will continue.
- *
- * If you specify a fake directory that only exists as a mount point, it'll
- * be associated with the first archive mounted there, even though that
- * directory isn't necessarily contained in a real archive.
- *
- * \warning This will return NULL if there is no real directory associated
- * with (filename). Specifically, PHYSFS_mountIo(),
- * PHYSFS_mountMemory(), and PHYSFS_mountHandle() will return NULL
- * even if the filename is found in the search path. Plan accordingly.
- *
- * \param filename file to look for.
- * \return READ ONLY string of element of search path containing the
- * the file in question. NULL if not found.
- */
-PHYSFS_DECL const char *PHYSFS_getRealDir(const char *filename);
-
-
-/**
- * \fn char **PHYSFS_enumerateFiles(const char *dir)
- * \brief Get a file listing of a search path's directory.
- *
- * Matching directories are interpolated. That is, if "C:\mydir" is in the
- * search path and contains a directory "savegames" that contains "x.sav",
- * "y.sav", and "z.sav", and there is also a "C:\userdir" in the search path
- * that has a "savegames" subdirectory with "w.sav", then the following code:
- *
- * \code
- * char **rc = PHYSFS_enumerateFiles("savegames");
- * char **i;
- *
- * for (i = rc; *i != NULL; i++)
- * printf(" * We've got [%s].\n", *i);
- *
- * PHYSFS_freeList(rc);
- * \endcode
- *
- * \...will print:
- *
- * \verbatim
- * We've got [x.sav].
- * We've got [y.sav].
- * We've got [z.sav].
- * We've got [w.sav].\endverbatim
- *
- * Feel free to sort the list however you like. We only promise there will
- * be no duplicates, but not what order the final list will come back in.
- *
- * Don't forget to call PHYSFS_freeList() with the return value from this
- * function when you are done with it.
- *
- * \param dir directory in platform-independent notation to enumerate.
- * \return Null-terminated array of null-terminated strings.
- *
- * \sa PHYSFS_enumerateFilesCallback
- */
-PHYSFS_DECL char **PHYSFS_enumerateFiles(const char *dir);
-
-
-/**
- * \fn int PHYSFS_exists(const char *fname)
- * \brief Determine if a file exists in the search path.
- *
- * Reports true if there is an entry anywhere in the search path by the
- * name of (fname).
- *
- * Note that entries that are symlinks are ignored if
- * PHYSFS_permitSymbolicLinks(1) hasn't been called, so you
- * might end up further down in the search path than expected.
- *
- * \param fname filename in platform-independent notation.
- * \return non-zero if filename exists. zero otherwise.
- */
-PHYSFS_DECL int PHYSFS_exists(const char *fname);
-
-
-/**
- * \fn int PHYSFS_isDirectory(const char *fname)
- * \brief Determine if a file in the search path is really a directory.
- *
- * \deprecated As of PhysicsFS 2.1, use PHYSFS_stat() instead. This
- * function just wraps it anyhow.
- *
- * Determine if the first occurence of (fname) in the search path is
- * really a directory entry.
- *
- * Note that entries that are symlinks are ignored if
- * PHYSFS_permitSymbolicLinks(1) hasn't been called, so you
- * might end up further down in the search path than expected.
- *
- * \param fname filename in platform-independent notation.
- * \return non-zero if filename exists and is a directory. zero otherwise.
- *
- * \sa PHYSFS_stat
- * \sa PHYSFS_exists
- */
-PHYSFS_DECL int PHYSFS_isDirectory(const char *fname) PHYSFS_DEPRECATED;
-
-
-/**
- * \fn int PHYSFS_isSymbolicLink(const char *fname)
- * \brief Determine if a file in the search path is really a symbolic link.
- *
- * \deprecated As of PhysicsFS 2.1, use PHYSFS_stat() instead. This
- * function just wraps it anyhow.
- *
- * Determine if the first occurence of (fname) in the search path is
- * really a symbolic link.
- *
- * Note that entries that are symlinks are ignored if
- * PHYSFS_permitSymbolicLinks(1) hasn't been called, and as such,
- * this function will always return 0 in that case.
- *
- * \param fname filename in platform-independent notation.
- * \return non-zero if filename exists and is a symlink. zero otherwise.
- *
- * \sa PHYSFS_stat
- * \sa PHYSFS_exists
- */
-PHYSFS_DECL int PHYSFS_isSymbolicLink(const char *fname) PHYSFS_DEPRECATED;
-
-
-/**
- * \fn PHYSFS_sint64 PHYSFS_getLastModTime(const char *filename)
- * \brief Get the last modification time of a file.
- *
- * \deprecated As of PhysicsFS 2.1, use PHYSFS_stat() instead. This
- * function just wraps it anyhow.
- *
- * The modtime is returned as a number of seconds since the Unix epoch
- * (midnight, Jan 1, 1970). The exact derivation and accuracy of this time
- * depends on the particular archiver. If there is no reasonable way to
- * obtain this information for a particular archiver, or there was some sort
- * of error, this function returns (-1).
- *
- * You must use this and not PHYSFS_stat() if binary compatibility with
- * PhysicsFS 2.0 is important (which it may not be for many people).
- *
- * \param filename filename to check, in platform-independent notation.
- * \return last modified time of the file. -1 if it can't be determined.
- *
- * \sa PHYSFS_stat
- */
-PHYSFS_DECL PHYSFS_sint64 PHYSFS_getLastModTime(const char *filename)
- PHYSFS_DEPRECATED;
-
-
-/* i/o stuff... */
-
-/**
- * \fn PHYSFS_File *PHYSFS_openWrite(const char *filename)
- * \brief Open a file for writing.
- *
- * Open a file for writing, in platform-independent notation and in relation
- * to the write dir as the root of the writable filesystem. The specified
- * file is created if it doesn't exist. If it does exist, it is truncated to
- * zero bytes, and the writing offset is set to the start.
- *
- * Note that entries that are symlinks are ignored if
- * PHYSFS_permitSymbolicLinks(1) hasn't been called, and opening a
- * symlink with this function will fail in such a case.
- *
- * \param filename File to open.
- * \return A valid PhysicsFS filehandle on success, NULL on error. Specifics
- * of the error can be gleaned from PHYSFS_getLastError().
- *
- * \sa PHYSFS_openRead
- * \sa PHYSFS_openAppend
- * \sa PHYSFS_write
- * \sa PHYSFS_close
- */
-PHYSFS_DECL PHYSFS_File *PHYSFS_openWrite(const char *filename);
-
-
-/**
- * \fn PHYSFS_File *PHYSFS_openAppend(const char *filename)
- * \brief Open a file for appending.
- *
- * Open a file for writing, in platform-independent notation and in relation
- * to the write dir as the root of the writable filesystem. The specified
- * file is created if it doesn't exist. If it does exist, the writing offset
- * is set to the end of the file, so the first write will be the byte after
- * the end.
- *
- * Note that entries that are symlinks are ignored if
- * PHYSFS_permitSymbolicLinks(1) hasn't been called, and opening a
- * symlink with this function will fail in such a case.
- *
- * \param filename File to open.
- * \return A valid PhysicsFS filehandle on success, NULL on error. Specifics
- * of the error can be gleaned from PHYSFS_getLastError().
- *
- * \sa PHYSFS_openRead
- * \sa PHYSFS_openWrite
- * \sa PHYSFS_write
- * \sa PHYSFS_close
- */
-PHYSFS_DECL PHYSFS_File *PHYSFS_openAppend(const char *filename);
-
-
-/**
- * \fn PHYSFS_File *PHYSFS_openRead(const char *filename)
- * \brief Open a file for reading.
- *
- * Open a file for reading, in platform-independent notation. The search path
- * is checked one at a time until a matching file is found, in which case an
- * abstract filehandle is associated with it, and reading may be done.
- * The reading offset is set to the first byte of the file.
- *
- * Note that entries that are symlinks are ignored if
- * PHYSFS_permitSymbolicLinks(1) hasn't been called, and opening a
- * symlink with this function will fail in such a case.
- *
- * \param filename File to open.
- * \return A valid PhysicsFS filehandle on success, NULL on error. Specifics
- * of the error can be gleaned from PHYSFS_getLastError().
- *
- * \sa PHYSFS_openWrite
- * \sa PHYSFS_openAppend
- * \sa PHYSFS_read
- * \sa PHYSFS_close
- */
-PHYSFS_DECL PHYSFS_File *PHYSFS_openRead(const char *filename);
-
-
-/**
- * \fn int PHYSFS_close(PHYSFS_File *handle)
- * \brief Close a PhysicsFS filehandle.
- *
- * This call is capable of failing if the operating system was buffering
- * writes to the physical media, and, now forced to write those changes to
- * physical media, can not store the data for some reason. In such a case,
- * the filehandle stays open. A well-written program should ALWAYS check the
- * return value from the close call in addition to every writing call!
- *
- * \param handle handle returned from PHYSFS_open*().
- * \return nonzero on success, zero on error. Specifics of the error can be
- * gleaned from PHYSFS_getLastError().
- *
- * \sa PHYSFS_openRead
- * \sa PHYSFS_openWrite
- * \sa PHYSFS_openAppend
- */
-PHYSFS_DECL int PHYSFS_close(PHYSFS_File *handle);
-
-
-/**
- * \fn PHYSFS_sint64 PHYSFS_read(PHYSFS_File *handle, void *buffer, PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
- * \brief Read data from a PhysicsFS filehandle
- *
- * The file must be opened for reading.
- *
- * \deprecated As of PhysicsFS 2.1, use PHYSFS_readBytes() instead. This
- * function just wraps it anyhow. This function never clarified
- * what would happen if you managed to read a partial object, so
- * working at the byte level makes this cleaner for everyone,
- * especially now that PHYSFS_Io interfaces can be supplied by the
- * application.
- *
- * \param handle handle returned from PHYSFS_openRead().
- * \param buffer buffer to store read data into.
- * \param objSize size in bytes of objects being read from (handle).
- * \param objCount number of (objSize) objects to read from (handle).
- * \return number of objects read. PHYSFS_getLastError() can shed light on
- * the reason this might be < (objCount), as can PHYSFS_eof().
- * -1 if complete failure.
- *
- * \sa PHYSFS_readBytes
- * \sa PHYSFS_eof
- */
-PHYSFS_DECL PHYSFS_sint64 PHYSFS_read(PHYSFS_File *handle,
- void *buffer,
- PHYSFS_uint32 objSize,
- PHYSFS_uint32 objCount)
- PHYSFS_DEPRECATED;
-
-/**
- * \fn PHYSFS_sint64 PHYSFS_write(PHYSFS_File *handle, const void *buffer, PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
- * \brief Write data to a PhysicsFS filehandle
- *
- * The file must be opened for writing.
- *
- * \deprecated As of PhysicsFS 2.1, use PHYSFS_writeBytes() instead. This
- * function just wraps it anyhow. This function never clarified
- * what would happen if you managed to write a partial object, so
- * working at the byte level makes this cleaner for everyone,
- * especially now that PHYSFS_Io interfaces can be supplied by the
- * application.
- *
- * \param handle retval from PHYSFS_openWrite() or PHYSFS_openAppend().
- * \param buffer buffer of bytes to write to (handle).
- * \param objSize size in bytes of objects being written to (handle).
- * \param objCount number of (objSize) objects to write to (handle).
- * \return number of objects written. PHYSFS_getLastError() can shed light on
- * the reason this might be < (objCount). -1 if complete failure.
- *
- * \sa PHYSFS_writeBytes
- */
-PHYSFS_DECL PHYSFS_sint64 PHYSFS_write(PHYSFS_File *handle,
- const void *buffer,
- PHYSFS_uint32 objSize,
- PHYSFS_uint32 objCount)
- PHYSFS_DEPRECATED;
-
-
-/* File position stuff... */
-
-/**
- * \fn int PHYSFS_eof(PHYSFS_File *handle)
- * \brief Check for end-of-file state on a PhysicsFS filehandle.
- *
- * Determine if the end of file has been reached in a PhysicsFS filehandle.
- *
- * \param handle handle returned from PHYSFS_openRead().
- * \return nonzero if EOF, zero if not.
- *
- * \sa PHYSFS_read
- * \sa PHYSFS_tell
- */
-PHYSFS_DECL int PHYSFS_eof(PHYSFS_File *handle);
-
-
-/**
- * \fn PHYSFS_sint64 PHYSFS_tell(PHYSFS_File *handle)
- * \brief Determine current position within a PhysicsFS filehandle.
- *
- * \param handle handle returned from PHYSFS_open*().
- * \return offset in bytes from start of file. -1 if error occurred.
- * Specifics of the error can be gleaned from PHYSFS_getLastError().
- *
- * \sa PHYSFS_seek
- */
-PHYSFS_DECL PHYSFS_sint64 PHYSFS_tell(PHYSFS_File *handle);
-
-
-/**
- * \fn int PHYSFS_seek(PHYSFS_File *handle, PHYSFS_uint64 pos)
- * \brief Seek to a new position within a PhysicsFS filehandle.
- *
- * The next read or write will occur at that place. Seeking past the
- * beginning or end of the file is not allowed, and causes an error.
- *
- * \param handle handle returned from PHYSFS_open*().
- * \param pos number of bytes from start of file to seek to.
- * \return nonzero on success, zero on error. Specifics of the error can be
- * gleaned from PHYSFS_getLastError().
- *
- * \sa PHYSFS_tell
- */
-PHYSFS_DECL int PHYSFS_seek(PHYSFS_File *handle, PHYSFS_uint64 pos);
-
-
-/**
- * \fn PHYSFS_sint64 PHYSFS_fileLength(PHYSFS_File *handle)
- * \brief Get total length of a file in bytes.
- *
- * Note that if another process/thread is writing to this file at the same
- * time, then the information this function supplies could be incorrect
- * before you get it. Use with caution, or better yet, don't use at all.
- *
- * \param handle handle returned from PHYSFS_open*().
- * \return size in bytes of the file. -1 if can't be determined.
- *
- * \sa PHYSFS_tell
- * \sa PHYSFS_seek
- */
-PHYSFS_DECL PHYSFS_sint64 PHYSFS_fileLength(PHYSFS_File *handle);
-
-
-/* Buffering stuff... */
-
-/**
- * \fn int PHYSFS_setBuffer(PHYSFS_File *handle, PHYSFS_uint64 bufsize)
- * \brief Set up buffering for a PhysicsFS file handle.
- *
- * Define an i/o buffer for a file handle. A memory block of (bufsize) bytes
- * will be allocated and associated with (handle).
- *
- * For files opened for reading, up to (bufsize) bytes are read from (handle)
- * and stored in the internal buffer. Calls to PHYSFS_read() will pull
- * from this buffer until it is empty, and then refill it for more reading.
- * Note that compressed files, like ZIP archives, will decompress while
- * buffering, so this can be handy for offsetting CPU-intensive operations.
- * The buffer isn't filled until you do your next read.
- *
- * For files opened for writing, data will be buffered to memory until the
- * buffer is full or the buffer is flushed. Closing a handle implicitly
- * causes a flush...check your return values!
- *
- * Seeking, etc transparently accounts for buffering.
- *
- * You can resize an existing buffer by calling this function more than once
- * on the same file. Setting the buffer size to zero will free an existing
- * buffer.
- *
- * PhysicsFS file handles are unbuffered by default.
- *
- * Please check the return value of this function! Failures can include
- * not being able to seek backwards in a read-only file when removing the
- * buffer, not being able to allocate the buffer, and not being able to
- * flush the buffer to disk, among other unexpected problems.
- *
- * \param handle handle returned from PHYSFS_open*().
- * \param bufsize size, in bytes, of buffer to allocate.
- * \return nonzero if successful, zero on error.
- *
- * \sa PHYSFS_flush
- * \sa PHYSFS_read
- * \sa PHYSFS_write
- * \sa PHYSFS_close
- */
-PHYSFS_DECL int PHYSFS_setBuffer(PHYSFS_File *handle, PHYSFS_uint64 bufsize);
-
-
-/**
- * \fn int PHYSFS_flush(PHYSFS_File *handle)
- * \brief Flush a buffered PhysicsFS file handle.
- *
- * For buffered files opened for writing, this will put the current contents
- * of the buffer to disk and flag the buffer as empty if possible.
- *
- * For buffered files opened for reading or unbuffered files, this is a safe
- * no-op, and will report success.
- *
- * \param handle handle returned from PHYSFS_open*().
- * \return nonzero if successful, zero on error.
- *
- * \sa PHYSFS_setBuffer
- * \sa PHYSFS_close
- */
-PHYSFS_DECL int PHYSFS_flush(PHYSFS_File *handle);
-
-
-/* Byteorder stuff... */
-
-#ifndef SWIG /* not available from scripting languages. */
-
-/**
- * \fn PHYSFS_sint16 PHYSFS_swapSLE16(PHYSFS_sint16 val)
- * \brief Swap littleendian signed 16 to platform's native byte order.
- *
- * Take a 16-bit signed value in littleendian format and convert it to
- * the platform's native byte order.
- *
- * \param val value to convert
- * \return converted value.
- */
-PHYSFS_DECL PHYSFS_sint16 PHYSFS_swapSLE16(PHYSFS_sint16 val);
-
-
-/**
- * \fn PHYSFS_uint16 PHYSFS_swapULE16(PHYSFS_uint16 val)
- * \brief Swap littleendian unsigned 16 to platform's native byte order.
- *
- * Take a 16-bit unsigned value in littleendian format and convert it to
- * the platform's native byte order.
- *
- * \param val value to convert
- * \return converted value.
- */
-PHYSFS_DECL PHYSFS_uint16 PHYSFS_swapULE16(PHYSFS_uint16 val);
-
-/**
- * \fn PHYSFS_sint32 PHYSFS_swapSLE32(PHYSFS_sint32 val)
- * \brief Swap littleendian signed 32 to platform's native byte order.
- *
- * Take a 32-bit signed value in littleendian format and convert it to
- * the platform's native byte order.
- *
- * \param val value to convert
- * \return converted value.
- */
-PHYSFS_DECL PHYSFS_sint32 PHYSFS_swapSLE32(PHYSFS_sint32 val);
-
-
-/**
- * \fn PHYSFS_uint32 PHYSFS_swapULE32(PHYSFS_uint32 val)
- * \brief Swap littleendian unsigned 32 to platform's native byte order.
- *
- * Take a 32-bit unsigned value in littleendian format and convert it to
- * the platform's native byte order.
- *
- * \param val value to convert
- * \return converted value.
- */
-PHYSFS_DECL PHYSFS_uint32 PHYSFS_swapULE32(PHYSFS_uint32 val);
-
-/**
- * \fn PHYSFS_sint64 PHYSFS_swapSLE64(PHYSFS_sint64 val)
- * \brief Swap littleendian signed 64 to platform's native byte order.
- *
- * Take a 64-bit signed value in littleendian format and convert it to
- * the platform's native byte order.
- *
- * \param val value to convert
- * \return converted value.
- *
- * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
- * any sort of 64-bit support.
- */
-PHYSFS_DECL PHYSFS_sint64 PHYSFS_swapSLE64(PHYSFS_sint64 val);
-
-
-/**
- * \fn PHYSFS_uint64 PHYSFS_swapULE64(PHYSFS_uint64 val)
- * \brief Swap littleendian unsigned 64 to platform's native byte order.
- *
- * Take a 64-bit unsigned value in littleendian format and convert it to
- * the platform's native byte order.
- *
- * \param val value to convert
- * \return converted value.
- *
- * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
- * any sort of 64-bit support.
- */
-PHYSFS_DECL PHYSFS_uint64 PHYSFS_swapULE64(PHYSFS_uint64 val);
-
-
-/**
- * \fn PHYSFS_sint16 PHYSFS_swapSBE16(PHYSFS_sint16 val)
- * \brief Swap bigendian signed 16 to platform's native byte order.
- *
- * Take a 16-bit signed value in bigendian format and convert it to
- * the platform's native byte order.
- *
- * \param val value to convert
- * \return converted value.
- */
-PHYSFS_DECL PHYSFS_sint16 PHYSFS_swapSBE16(PHYSFS_sint16 val);
-
-
-/**
- * \fn PHYSFS_uint16 PHYSFS_swapUBE16(PHYSFS_uint16 val)
- * \brief Swap bigendian unsigned 16 to platform's native byte order.
- *
- * Take a 16-bit unsigned value in bigendian format and convert it to
- * the platform's native byte order.
- *
- * \param val value to convert
- * \return converted value.
- */
-PHYSFS_DECL PHYSFS_uint16 PHYSFS_swapUBE16(PHYSFS_uint16 val);
-
-/**
- * \fn PHYSFS_sint32 PHYSFS_swapSBE32(PHYSFS_sint32 val)
- * \brief Swap bigendian signed 32 to platform's native byte order.
- *
- * Take a 32-bit signed value in bigendian format and convert it to
- * the platform's native byte order.
- *
- * \param val value to convert
- * \return converted value.
- */
-PHYSFS_DECL PHYSFS_sint32 PHYSFS_swapSBE32(PHYSFS_sint32 val);
-
-
-/**
- * \fn PHYSFS_uint32 PHYSFS_swapUBE32(PHYSFS_uint32 val)
- * \brief Swap bigendian unsigned 32 to platform's native byte order.
- *
- * Take a 32-bit unsigned value in bigendian format and convert it to
- * the platform's native byte order.
- *
- * \param val value to convert
- * \return converted value.
- */
-PHYSFS_DECL PHYSFS_uint32 PHYSFS_swapUBE32(PHYSFS_uint32 val);
-
-
-/**
- * \fn PHYSFS_sint64 PHYSFS_swapSBE64(PHYSFS_sint64 val)
- * \brief Swap bigendian signed 64 to platform's native byte order.
- *
- * Take a 64-bit signed value in bigendian format and convert it to
- * the platform's native byte order.
- *
- * \param val value to convert
- * \return converted value.
- *
- * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
- * any sort of 64-bit support.
- */
-PHYSFS_DECL PHYSFS_sint64 PHYSFS_swapSBE64(PHYSFS_sint64 val);
-
-
-/**
- * \fn PHYSFS_uint64 PHYSFS_swapUBE64(PHYSFS_uint64 val)
- * \brief Swap bigendian unsigned 64 to platform's native byte order.
- *
- * Take a 64-bit unsigned value in bigendian format and convert it to
- * the platform's native byte order.
- *
- * \param val value to convert
- * \return converted value.
- *
- * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
- * any sort of 64-bit support.
- */
-PHYSFS_DECL PHYSFS_uint64 PHYSFS_swapUBE64(PHYSFS_uint64 val);
-
-#endif /* SWIG */
-
-
-/**
- * \fn int PHYSFS_readSLE16(PHYSFS_File *file, PHYSFS_sint16 *val)
- * \brief Read and convert a signed 16-bit littleendian value.
- *
- * Convenience function. Read a signed 16-bit littleendian value from a
- * file and convert it to the platform's native byte order.
- *
- * \param file PhysicsFS file handle from which to read.
- * \param val pointer to where value should be stored.
- * \return zero on failure, non-zero on success. If successful, (*val) will
- * store the result. On failure, you can find out what went wrong
- * from PHYSFS_getLastError().
- */
-PHYSFS_DECL int PHYSFS_readSLE16(PHYSFS_File *file, PHYSFS_sint16 *val);
-
-
-/**
- * \fn int PHYSFS_readULE16(PHYSFS_File *file, PHYSFS_uint16 *val)
- * \brief Read and convert an unsigned 16-bit littleendian value.
- *
- * Convenience function. Read an unsigned 16-bit littleendian value from a
- * file and convert it to the platform's native byte order.
- *
- * \param file PhysicsFS file handle from which to read.
- * \param val pointer to where value should be stored.
- * \return zero on failure, non-zero on success. If successful, (*val) will
- * store the result. On failure, you can find out what went wrong
- * from PHYSFS_getLastError().
- *
- */
-PHYSFS_DECL int PHYSFS_readULE16(PHYSFS_File *file, PHYSFS_uint16 *val);
-
-
-/**
- * \fn int PHYSFS_readSBE16(PHYSFS_File *file, PHYSFS_sint16 *val)
- * \brief Read and convert a signed 16-bit bigendian value.
- *
- * Convenience function. Read a signed 16-bit bigendian value from a
- * file and convert it to the platform's native byte order.
- *
- * \param file PhysicsFS file handle from which to read.
- * \param val pointer to where value should be stored.
- * \return zero on failure, non-zero on success. If successful, (*val) will
- * store the result. On failure, you can find out what went wrong
- * from PHYSFS_getLastError().
- */
-PHYSFS_DECL int PHYSFS_readSBE16(PHYSFS_File *file, PHYSFS_sint16 *val);
-
-
-/**
- * \fn int PHYSFS_readUBE16(PHYSFS_File *file, PHYSFS_uint16 *val)
- * \brief Read and convert an unsigned 16-bit bigendian value.
- *
- * Convenience function. Read an unsigned 16-bit bigendian value from a
- * file and convert it to the platform's native byte order.
- *
- * \param file PhysicsFS file handle from which to read.
- * \param val pointer to where value should be stored.
- * \return zero on failure, non-zero on success. If successful, (*val) will
- * store the result. On failure, you can find out what went wrong
- * from PHYSFS_getLastError().
- *
- */
-PHYSFS_DECL int PHYSFS_readUBE16(PHYSFS_File *file, PHYSFS_uint16 *val);
-
-
-/**
- * \fn int PHYSFS_readSLE32(PHYSFS_File *file, PHYSFS_sint32 *val)
- * \brief Read and convert a signed 32-bit littleendian value.
- *
- * Convenience function. Read a signed 32-bit littleendian value from a
- * file and convert it to the platform's native byte order.
- *
- * \param file PhysicsFS file handle from which to read.
- * \param val pointer to where value should be stored.
- * \return zero on failure, non-zero on success. If successful, (*val) will
- * store the result. On failure, you can find out what went wrong
- * from PHYSFS_getLastError().
- */
-PHYSFS_DECL int PHYSFS_readSLE32(PHYSFS_File *file, PHYSFS_sint32 *val);
-
-
-/**
- * \fn int PHYSFS_readULE32(PHYSFS_File *file, PHYSFS_uint32 *val)
- * \brief Read and convert an unsigned 32-bit littleendian value.
- *
- * Convenience function. Read an unsigned 32-bit littleendian value from a
- * file and convert it to the platform's native byte order.
- *
- * \param file PhysicsFS file handle from which to read.
- * \param val pointer to where value should be stored.
- * \return zero on failure, non-zero on success. If successful, (*val) will
- * store the result. On failure, you can find out what went wrong
- * from PHYSFS_getLastError().
- *
- */
-PHYSFS_DECL int PHYSFS_readULE32(PHYSFS_File *file, PHYSFS_uint32 *val);
-
-
-/**
- * \fn int PHYSFS_readSBE32(PHYSFS_File *file, PHYSFS_sint32 *val)
- * \brief Read and convert a signed 32-bit bigendian value.
- *
- * Convenience function. Read a signed 32-bit bigendian value from a
- * file and convert it to the platform's native byte order.
- *
- * \param file PhysicsFS file handle from which to read.
- * \param val pointer to where value should be stored.
- * \return zero on failure, non-zero on success. If successful, (*val) will
- * store the result. On failure, you can find out what went wrong
- * from PHYSFS_getLastError().
- */
-PHYSFS_DECL int PHYSFS_readSBE32(PHYSFS_File *file, PHYSFS_sint32 *val);
-
-
-/**
- * \fn int PHYSFS_readUBE32(PHYSFS_File *file, PHYSFS_uint32 *val)
- * \brief Read and convert an unsigned 32-bit bigendian value.
- *
- * Convenience function. Read an unsigned 32-bit bigendian value from a
- * file and convert it to the platform's native byte order.
- *
- * \param file PhysicsFS file handle from which to read.
- * \param val pointer to where value should be stored.
- * \return zero on failure, non-zero on success. If successful, (*val) will
- * store the result. On failure, you can find out what went wrong
- * from PHYSFS_getLastError().
- *
- */
-PHYSFS_DECL int PHYSFS_readUBE32(PHYSFS_File *file, PHYSFS_uint32 *val);
-
-
-/**
- * \fn int PHYSFS_readSLE64(PHYSFS_File *file, PHYSFS_sint64 *val)
- * \brief Read and convert a signed 64-bit littleendian value.
- *
- * Convenience function. Read a signed 64-bit littleendian value from a
- * file and convert it to the platform's native byte order.
- *
- * \param file PhysicsFS file handle from which to read.
- * \param val pointer to where value should be stored.
- * \return zero on failure, non-zero on success. If successful, (*val) will
- * store the result. On failure, you can find out what went wrong
- * from PHYSFS_getLastError().
- *
- * \warning Remember, PHYSFS_sint64 is only 32 bits on platforms without
- * any sort of 64-bit support.
- */
-PHYSFS_DECL int PHYSFS_readSLE64(PHYSFS_File *file, PHYSFS_sint64 *val);
-
-
-/**
- * \fn int PHYSFS_readULE64(PHYSFS_File *file, PHYSFS_uint64 *val)
- * \brief Read and convert an unsigned 64-bit littleendian value.
- *
- * Convenience function. Read an unsigned 64-bit littleendian value from a
- * file and convert it to the platform's native byte order.
- *
- * \param file PhysicsFS file handle from which to read.
- * \param val pointer to where value should be stored.
- * \return zero on failure, non-zero on success. If successful, (*val) will
- * store the result. On failure, you can find out what went wrong
- * from PHYSFS_getLastError().
- *
- * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
- * any sort of 64-bit support.
- */
-PHYSFS_DECL int PHYSFS_readULE64(PHYSFS_File *file, PHYSFS_uint64 *val);
-
-
-/**
- * \fn int PHYSFS_readSBE64(PHYSFS_File *file, PHYSFS_sint64 *val)
- * \brief Read and convert a signed 64-bit bigendian value.
- *
- * Convenience function. Read a signed 64-bit bigendian value from a
- * file and convert it to the platform's native byte order.
- *
- * \param file PhysicsFS file handle from which to read.
- * \param val pointer to where value should be stored.
- * \return zero on failure, non-zero on success. If successful, (*val) will
- * store the result. On failure, you can find out what went wrong
- * from PHYSFS_getLastError().
- *
- * \warning Remember, PHYSFS_sint64 is only 32 bits on platforms without
- * any sort of 64-bit support.
- */
-PHYSFS_DECL int PHYSFS_readSBE64(PHYSFS_File *file, PHYSFS_sint64 *val);
-
-
-/**
- * \fn int PHYSFS_readUBE64(PHYSFS_File *file, PHYSFS_uint64 *val)
- * \brief Read and convert an unsigned 64-bit bigendian value.
- *
- * Convenience function. Read an unsigned 64-bit bigendian value from a
- * file and convert it to the platform's native byte order.
- *
- * \param file PhysicsFS file handle from which to read.
- * \param val pointer to where value should be stored.
- * \return zero on failure, non-zero on success. If successful, (*val) will
- * store the result. On failure, you can find out what went wrong
- * from PHYSFS_getLastError().
- *
- * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
- * any sort of 64-bit support.
- */
-PHYSFS_DECL int PHYSFS_readUBE64(PHYSFS_File *file, PHYSFS_uint64 *val);
-
-
-/**
- * \fn int PHYSFS_writeSLE16(PHYSFS_File *file, PHYSFS_sint16 val)
- * \brief Convert and write a signed 16-bit littleendian value.
- *
- * Convenience function. Convert a signed 16-bit value from the platform's
- * native byte order to littleendian and write it to a file.
- *
- * \param file PhysicsFS file handle to which to write.
- * \param val Value to convert and write.
- * \return zero on failure, non-zero on success. On failure, you can
- * find out what went wrong from PHYSFS_getLastError().
- */
-PHYSFS_DECL int PHYSFS_writeSLE16(PHYSFS_File *file, PHYSFS_sint16 val);
-
-
-/**
- * \fn int PHYSFS_writeULE16(PHYSFS_File *file, PHYSFS_uint16 val)
- * \brief Convert and write an unsigned 16-bit littleendian value.
- *
- * Convenience function. Convert an unsigned 16-bit value from the platform's
- * native byte order to littleendian and write it to a file.
- *
- * \param file PhysicsFS file handle to which to write.
- * \param val Value to convert and write.
- * \return zero on failure, non-zero on success. On failure, you can
- * find out what went wrong from PHYSFS_getLastError().
- */
-PHYSFS_DECL int PHYSFS_writeULE16(PHYSFS_File *file, PHYSFS_uint16 val);
-
-
-/**
- * \fn int PHYSFS_writeSBE16(PHYSFS_File *file, PHYSFS_sint16 val)
- * \brief Convert and write a signed 16-bit bigendian value.
- *
- * Convenience function. Convert a signed 16-bit value from the platform's
- * native byte order to bigendian and write it to a file.
- *
- * \param file PhysicsFS file handle to which to write.
- * \param val Value to convert and write.
- * \return zero on failure, non-zero on success. On failure, you can
- * find out what went wrong from PHYSFS_getLastError().
- */
-PHYSFS_DECL int PHYSFS_writeSBE16(PHYSFS_File *file, PHYSFS_sint16 val);
-
-
-/**
- * \fn int PHYSFS_writeUBE16(PHYSFS_File *file, PHYSFS_uint16 val)
- * \brief Convert and write an unsigned 16-bit bigendian value.
- *
- * Convenience function. Convert an unsigned 16-bit value from the platform's
- * native byte order to bigendian and write it to a file.
- *
- * \param file PhysicsFS file handle to which to write.
- * \param val Value to convert and write.
- * \return zero on failure, non-zero on success. On failure, you can
- * find out what went wrong from PHYSFS_getLastError().
- */
-PHYSFS_DECL int PHYSFS_writeUBE16(PHYSFS_File *file, PHYSFS_uint16 val);
-
-
-/**
- * \fn int PHYSFS_writeSLE32(PHYSFS_File *file, PHYSFS_sint32 val)
- * \brief Convert and write a signed 32-bit littleendian value.
- *
- * Convenience function. Convert a signed 32-bit value from the platform's
- * native byte order to littleendian and write it to a file.
- *
- * \param file PhysicsFS file handle to which to write.
- * \param val Value to convert and write.
- * \return zero on failure, non-zero on success. On failure, you can
- * find out what went wrong from PHYSFS_getLastError().
- */
-PHYSFS_DECL int PHYSFS_writeSLE32(PHYSFS_File *file, PHYSFS_sint32 val);
-
-
-/**
- * \fn int PHYSFS_writeULE32(PHYSFS_File *file, PHYSFS_uint32 val)
- * \brief Convert and write an unsigned 32-bit littleendian value.
- *
- * Convenience function. Convert an unsigned 32-bit value from the platform's
- * native byte order to littleendian and write it to a file.
- *
- * \param file PhysicsFS file handle to which to write.
- * \param val Value to convert and write.
- * \return zero on failure, non-zero on success. On failure, you can
- * find out what went wrong from PHYSFS_getLastError().
- */
-PHYSFS_DECL int PHYSFS_writeULE32(PHYSFS_File *file, PHYSFS_uint32 val);
-
-
-/**
- * \fn int PHYSFS_writeSBE32(PHYSFS_File *file, PHYSFS_sint32 val)
- * \brief Convert and write a signed 32-bit bigendian value.
- *
- * Convenience function. Convert a signed 32-bit value from the platform's
- * native byte order to bigendian and write it to a file.
- *
- * \param file PhysicsFS file handle to which to write.
- * \param val Value to convert and write.
- * \return zero on failure, non-zero on success. On failure, you can
- * find out what went wrong from PHYSFS_getLastError().
- */
-PHYSFS_DECL int PHYSFS_writeSBE32(PHYSFS_File *file, PHYSFS_sint32 val);
-
-
-/**
- * \fn int PHYSFS_writeUBE32(PHYSFS_File *file, PHYSFS_uint32 val)
- * \brief Convert and write an unsigned 32-bit bigendian value.
- *
- * Convenience function. Convert an unsigned 32-bit value from the platform's
- * native byte order to bigendian and write it to a file.
- *
- * \param file PhysicsFS file handle to which to write.
- * \param val Value to convert and write.
- * \return zero on failure, non-zero on success. On failure, you can
- * find out what went wrong from PHYSFS_getLastError().
- */
-PHYSFS_DECL int PHYSFS_writeUBE32(PHYSFS_File *file, PHYSFS_uint32 val);
-
-
-/**
- * \fn int PHYSFS_writeSLE64(PHYSFS_File *file, PHYSFS_sint64 val)
- * \brief Convert and write a signed 64-bit littleendian value.
- *
- * Convenience function. Convert a signed 64-bit value from the platform's
- * native byte order to littleendian and write it to a file.
- *
- * \param file PhysicsFS file handle to which to write.
- * \param val Value to convert and write.
- * \return zero on failure, non-zero on success. On failure, you can
- * find out what went wrong from PHYSFS_getLastError().
- *
- * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
- * any sort of 64-bit support.
- */
-PHYSFS_DECL int PHYSFS_writeSLE64(PHYSFS_File *file, PHYSFS_sint64 val);
-
-
-/**
- * \fn int PHYSFS_writeULE64(PHYSFS_File *file, PHYSFS_uint64 val)
- * \brief Convert and write an unsigned 64-bit littleendian value.
- *
- * Convenience function. Convert an unsigned 64-bit value from the platform's
- * native byte order to littleendian and write it to a file.
- *
- * \param file PhysicsFS file handle to which to write.
- * \param val Value to convert and write.
- * \return zero on failure, non-zero on success. On failure, you can
- * find out what went wrong from PHYSFS_getLastError().
- *
- * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
- * any sort of 64-bit support.
- */
-PHYSFS_DECL int PHYSFS_writeULE64(PHYSFS_File *file, PHYSFS_uint64 val);
-
-
-/**
- * \fn int PHYSFS_writeSBE64(PHYSFS_File *file, PHYSFS_sint64 val)
- * \brief Convert and write a signed 64-bit bigending value.
- *
- * Convenience function. Convert a signed 64-bit value from the platform's
- * native byte order to bigendian and write it to a file.
- *
- * \param file PhysicsFS file handle to which to write.
- * \param val Value to convert and write.
- * \return zero on failure, non-zero on success. On failure, you can
- * find out what went wrong from PHYSFS_getLastError().
- *
- * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
- * any sort of 64-bit support.
- */
-PHYSFS_DECL int PHYSFS_writeSBE64(PHYSFS_File *file, PHYSFS_sint64 val);
-
-
-/**
- * \fn int PHYSFS_writeUBE64(PHYSFS_File *file, PHYSFS_uint64 val)
- * \brief Convert and write an unsigned 64-bit bigendian value.
- *
- * Convenience function. Convert an unsigned 64-bit value from the platform's
- * native byte order to bigendian and write it to a file.
- *
- * \param file PhysicsFS file handle to which to write.
- * \param val Value to convert and write.
- * \return zero on failure, non-zero on success. On failure, you can
- * find out what went wrong from PHYSFS_getLastError().
- *
- * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
- * any sort of 64-bit support.
- */
-PHYSFS_DECL int PHYSFS_writeUBE64(PHYSFS_File *file, PHYSFS_uint64 val);
-
-
-/* Everything above this line is part of the PhysicsFS 1.0 API. */
-
-/**
- * \fn int PHYSFS_isInit(void)
- * \brief Determine if the PhysicsFS library is initialized.
- *
- * Once PHYSFS_init() returns successfully, this will return non-zero.
- * Before a successful PHYSFS_init() and after PHYSFS_deinit() returns
- * successfully, this will return zero. This function is safe to call at
- * any time.
- *
- * \return non-zero if library is initialized, zero if library is not.
- *
- * \sa PHYSFS_init
- * \sa PHYSFS_deinit
- */
-PHYSFS_DECL int PHYSFS_isInit(void);
-
-
-/**
- * \fn int PHYSFS_symbolicLinksPermitted(void)
- * \brief Determine if the symbolic links are permitted.
- *
- * This reports the setting from the last call to PHYSFS_permitSymbolicLinks().
- * If PHYSFS_permitSymbolicLinks() hasn't been called since the library was
- * last initialized, symbolic links are implicitly disabled.
- *
- * \return non-zero if symlinks are permitted, zero if not.
- *
- * \sa PHYSFS_permitSymbolicLinks
- */
-PHYSFS_DECL int PHYSFS_symbolicLinksPermitted(void);
-
-
-#ifndef SWIG /* not available from scripting languages. */
-
-/**
- * \struct PHYSFS_Allocator
- * \brief PhysicsFS allocation function pointers.
- *
- * (This is for limited, hardcore use. If you don't immediately see a need
- * for it, you can probably ignore this forever.)
- *
- * You create one of these structures for use with PHYSFS_setAllocator.
- * Allocators are assumed to be reentrant by the caller; please mutex
- * accordingly.
- *
- * Allocations are always discussed in 64-bits, for future expansion...we're
- * on the cusp of a 64-bit transition, and we'll probably be allocating 6
- * gigabytes like it's nothing sooner or later, and I don't want to change
- * this again at that point. If you're on a 32-bit platform and have to
- * downcast, it's okay to return NULL if the allocation is greater than
- * 4 gigabytes, since you'd have to do so anyhow.
- *
- * \sa PHYSFS_setAllocator
- */
-typedef struct PHYSFS_Allocator
-{
- int (*Init)(void); /**< Initialize. Can be NULL. Zero on failure. */
- void (*Deinit)(void); /**< Deinitialize your allocator. Can be NULL. */
- void *(*Malloc)(PHYSFS_uint64); /**< Allocate like malloc(). */
- void *(*Realloc)(void *, PHYSFS_uint64); /**< Reallocate like realloc(). */
- void (*Free)(void *); /**< Free memory from Malloc or Realloc. */
-} PHYSFS_Allocator;
-
-
-/**
- * \fn int PHYSFS_setAllocator(const PHYSFS_Allocator *allocator)
- * \brief Hook your own allocation routines into PhysicsFS.
- *
- * (This is for limited, hardcore use. If you don't immediately see a need
- * for it, you can probably ignore this forever.)
- *
- * By default, PhysicsFS will use whatever is reasonable for a platform
- * to manage dynamic memory (usually ANSI C malloc/realloc/free, but
- * some platforms might use something else), but in some uncommon cases, the
- * app might want more control over the library's memory management. This
- * lets you redirect PhysicsFS to use your own allocation routines instead.
- * You can only call this function before PHYSFS_init(); if the library is
- * initialized, it'll reject your efforts to change the allocator mid-stream.
- * You may call this function after PHYSFS_deinit() if you are willing to
- * shut down the library and restart it with a new allocator; this is a safe
- * and supported operation. The allocator remains intact between deinit/init
- * calls. If you want to return to the platform's default allocator, pass a
- * NULL in here.
- *
- * If you aren't immediately sure what to do with this function, you can
- * safely ignore it altogether.
- *
- * \param allocator Structure containing your allocator's entry points.
- * \return zero on failure, non-zero on success. This call only fails
- * when used between PHYSFS_init() and PHYSFS_deinit() calls.
- */
-PHYSFS_DECL int PHYSFS_setAllocator(const PHYSFS_Allocator *allocator);
-
-#endif /* SWIG */
-
-
-/**
- * \fn int PHYSFS_mount(const char *newDir, const char *mountPoint, int appendToPath)
- * \brief Add an archive or directory to the search path.
- *
- * If this is a duplicate, the entry is not added again, even though the
- * function succeeds. You may not add the same archive to two different
- * mountpoints: duplicate checking is done against the archive and not the
- * mountpoint.
- *
- * When you mount an archive, it is added to a virtual file system...all files
- * in all of the archives are interpolated into a single hierachical file
- * tree. Two archives mounted at the same place (or an archive with files
- * overlapping another mountpoint) may have overlapping files: in such a case,
- * the file earliest in the search path is selected, and the other files are
- * inaccessible to the application. This allows archives to be used to
- * override previous revisions; you can use the mounting mechanism to place
- * archives at a specific point in the file tree and prevent overlap; this
- * is useful for downloadable mods that might trample over application data
- * or each other, for example.
- *
- * The mountpoint does not need to exist prior to mounting, which is different
- * than those familiar with the Unix concept of "mounting" may not expect.
- * As well, more than one archive can be mounted to the same mountpoint, or
- * mountpoints and archive contents can overlap...the interpolation mechanism
- * still functions as usual.
- *
- * \param newDir directory or archive to add to the path, in
- * platform-dependent notation.
- * \param mountPoint Location in the interpolated tree that this archive
- * will be "mounted", in platform-independent notation.
- * NULL or "" is equivalent to "/".
- * \param appendToPath nonzero to append to search path, zero to prepend.
- * \return nonzero if added to path, zero on failure (bogus archive, dir
- * missing, etc). Specifics of the error can be
- * gleaned from PHYSFS_getLastError().
- *
- * \sa PHYSFS_removeFromSearchPath
- * \sa PHYSFS_getSearchPath
- * \sa PHYSFS_getMountPoint
- * \sa PHYSFS_mountIo
- */
-PHYSFS_DECL int PHYSFS_mount(const char *newDir,
- const char *mountPoint,
- int appendToPath);
-
-/**
- * \fn int PHYSFS_getMountPoint(const char *dir)
- * \brief Determine a mounted archive's mountpoint.
- *
- * You give this function the name of an archive or dir you successfully
- * added to the search path, and it reports the location in the interpolated
- * tree where it is mounted. Files mounted with a NULL mountpoint or through
- * PHYSFS_addToSearchPath() will report "/". The return value is READ ONLY
- * and valid until the archive is removed from the search path.
- *
- * \param dir directory or archive previously added to the path, in
- * platform-dependent notation. This must match the string
- * used when adding, even if your string would also reference
- * the same file with a different string of characters.
- * \return READ-ONLY string of mount point if added to path, NULL on failure
- * (bogus archive, etc) Specifics of the error can be gleaned from
- * PHYSFS_getLastError().
- *
- * \sa PHYSFS_removeFromSearchPath
- * \sa PHYSFS_getSearchPath
- * \sa PHYSFS_getMountPoint
- */
-PHYSFS_DECL const char *PHYSFS_getMountPoint(const char *dir);
-
-
-#ifndef SWIG /* not available from scripting languages. */
-
-/**
- * \typedef PHYSFS_StringCallback
- * \brief Function signature for callbacks that report strings.
- *
- * These are used to report a list of strings to an original caller, one
- * string per callback. All strings are UTF-8 encoded. Functions should not
- * try to modify or free the string's memory.
- *
- * These callbacks are used, starting in PhysicsFS 1.1, as an alternative to
- * functions that would return lists that need to be cleaned up with
- * PHYSFS_freeList(). The callback means that the library doesn't need to
- * allocate an entire list and all the strings up front.
- *
- * Be aware that promises data ordering in the list versions are not
- * necessarily so in the callback versions. Check the documentation on
- * specific APIs, but strings may not be sorted as you expect.
- *
- * \param data User-defined data pointer, passed through from the API
- * that eventually called the callback.
- * \param str The string data about which the callback is meant to inform.
- *
- * \sa PHYSFS_getCdRomDirsCallback
- * \sa PHYSFS_getSearchPathCallback
- */
-typedef void (*PHYSFS_StringCallback)(void *data, const char *str);
-
-
-/**
- * \typedef PHYSFS_EnumFilesCallback
- * \brief Function signature for callbacks that enumerate files.
- *
- * These are used to report a list of directory entries to an original caller,
- * one file/dir/symlink per callback. All strings are UTF-8 encoded.
- * Functions should not try to modify or free any string's memory.
- *
- * These callbacks are used, starting in PhysicsFS 1.1, as an alternative to
- * functions that would return lists that need to be cleaned up with
- * PHYSFS_freeList(). The callback means that the library doesn't need to
- * allocate an entire list and all the strings up front.
- *
- * Be aware that promises data ordering in the list versions are not
- * necessarily so in the callback versions. Check the documentation on
- * specific APIs, but strings may not be sorted as you expect.
- *
- * \param data User-defined data pointer, passed through from the API
- * that eventually called the callback.
- * \param origdir A string containing the full path, in platform-independent
- * notation, of the directory containing this file. In most
- * cases, this is the directory on which you requested
- * enumeration, passed in the callback for your convenience.
- * \param fname The filename that is being enumerated. It may not be in
- * alphabetical order compared to other callbacks that have
- * fired, and it will not contain the full path. You can
- * recreate the fullpath with $origdir/$fname ... The file
- * can be a subdirectory, a file, a symlink, etc.
- *
- * \sa PHYSFS_enumerateFilesCallback
- */
-typedef void (*PHYSFS_EnumFilesCallback)(void *data, const char *origdir,
- const char *fname);
-
-
-/**
- * \fn void PHYSFS_getCdRomDirsCallback(PHYSFS_StringCallback c, void *d)
- * \brief Enumerate CD-ROM directories, using an application-defined callback.
- *
- * Internally, PHYSFS_getCdRomDirs() just calls this function and then builds
- * a list before returning to the application, so functionality is identical
- * except for how the information is represented to the application.
- *
- * Unlike PHYSFS_getCdRomDirs(), this function does not return an array.
- * Rather, it calls a function specified by the application once per
- * detected disc:
- *
- * \code
- *
- * static void foundDisc(void *data, const char *cddir)
- * {
- * printf("cdrom dir [%s] is available.\n", cddir);
- * }
- *
- * // ...
- * PHYSFS_getCdRomDirsCallback(foundDisc, NULL);
- * \endcode
- *
- * This call may block while drives spin up. Be forewarned.
- *
- * \param c Callback function to notify about detected drives.
- * \param d Application-defined data passed to callback. Can be NULL.
- *
- * \sa PHYSFS_StringCallback
- * \sa PHYSFS_getCdRomDirs
- */
-PHYSFS_DECL void PHYSFS_getCdRomDirsCallback(PHYSFS_StringCallback c, void *d);
-
-
-/**
- * \fn void PHYSFS_getSearchPathCallback(PHYSFS_StringCallback c, void *d)
- * \brief Enumerate the search path, using an application-defined callback.
- *
- * Internally, PHYSFS_getSearchPath() just calls this function and then builds
- * a list before returning to the application, so functionality is identical
- * except for how the information is represented to the application.
- *
- * Unlike PHYSFS_getSearchPath(), this function does not return an array.
- * Rather, it calls a function specified by the application once per
- * element of the search path:
- *
- * \code
- *
- * static void printSearchPath(void *data, const char *pathItem)
- * {
- * printf("[%s] is in the search path.\n", pathItem);
- * }
- *
- * // ...
- * PHYSFS_getSearchPathCallback(printSearchPath, NULL);
- * \endcode
- *
- * Elements of the search path are reported in order search priority, so the
- * first archive/dir that would be examined when looking for a file is the
- * first element passed through the callback.
- *
- * \param c Callback function to notify about search path elements.
- * \param d Application-defined data passed to callback. Can be NULL.
- *
- * \sa PHYSFS_StringCallback
- * \sa PHYSFS_getSearchPath
- */
-PHYSFS_DECL void PHYSFS_getSearchPathCallback(PHYSFS_StringCallback c, void *d);
-
-
-/**
- * \fn void PHYSFS_enumerateFilesCallback(const char *dir, PHYSFS_EnumFilesCallback c, void *d)
- * \brief Get a file listing of a search path's directory, using an application-defined callback.
- *
- * Internally, PHYSFS_enumerateFiles() just calls this function and then builds
- * a list before returning to the application, so functionality is identical
- * except for how the information is represented to the application.
- *
- * Unlike PHYSFS_enumerateFiles(), this function does not return an array.
- * Rather, it calls a function specified by the application once per
- * element of the search path:
- *
- * \code
- *
- * static void printDir(void *data, const char *origdir, const char *fname)
- * {
- * printf(" * We've got [%s] in [%s].\n", fname, origdir);
- * }
- *
- * // ...
- * PHYSFS_enumerateFilesCallback("/some/path", printDir, NULL);
- * \endcode
- *
- * !!! FIXME: enumerateFiles() does not promise alphabetical sorting by
- * !!! FIXME: case-sensitivity in the code, and doesn't promise sorting at
- * !!! FIXME: all in the above docs.
- *
- * Items sent to the callback are not guaranteed to be in any order whatsoever.
- * There is no sorting done at this level, and if you need that, you should
- * probably use PHYSFS_enumerateFiles() instead, which guarantees
- * alphabetical sorting. This form reports whatever is discovered in each
- * archive before moving on to the next. Even within one archive, we can't
- * guarantee what order it will discover data. Any sorting you find in
- * these callbacks is just pure luck. Do not rely on it. As this walks
- * the entire list of archives, you may receive duplicate filenames.
- *
- * \param dir Directory, in platform-independent notation, to enumerate.
- * \param c Callback function to notify about search path elements.
- * \param d Application-defined data passed to callback. Can be NULL.
- *
- * \sa PHYSFS_EnumFilesCallback
- * \sa PHYSFS_enumerateFiles
- */
-PHYSFS_DECL void PHYSFS_enumerateFilesCallback(const char *dir,
- PHYSFS_EnumFilesCallback c,
- void *d);
-
-/**
- * \fn void PHYSFS_utf8FromUcs4(const PHYSFS_uint32 *src, char *dst, PHYSFS_uint64 len)
- * \brief Convert a UCS-4 string to a UTF-8 string.
- *
- * UCS-4 strings are 32-bits per character: \c wchar_t on Unix.
- *
- * To ensure that the destination buffer is large enough for the conversion,
- * please allocate a buffer that is the same size as the source buffer. UTF-8
- * never uses more than 32-bits per character, so while it may shrink a UCS-4
- * string, it will never expand it.
- *
- * Strings that don't fit in the destination buffer will be truncated, but
- * will always be null-terminated and never have an incomplete UTF-8
- * sequence at the end. If the buffer length is 0, this function does nothing.
- *
- * \param src Null-terminated source string in UCS-4 format.
- * \param dst Buffer to store converted UTF-8 string.
- * \param len Size, in bytes, of destination buffer.
- */
-PHYSFS_DECL void PHYSFS_utf8FromUcs4(const PHYSFS_uint32 *src, char *dst,
- PHYSFS_uint64 len);
-
-/**
- * \fn void PHYSFS_utf8ToUcs4(const char *src, PHYSFS_uint32 *dst, PHYSFS_uint64 len)
- * \brief Convert a UTF-8 string to a UCS-4 string.
- *
- * UCS-4 strings are 32-bits per character: \c wchar_t on Unix.
- *
- * To ensure that the destination buffer is large enough for the conversion,
- * please allocate a buffer that is four times the size of the source buffer.
- * UTF-8 uses from one to four bytes per character, but UCS-4 always uses
- * four, so an entirely low-ASCII string will quadruple in size!
- *
- * Strings that don't fit in the destination buffer will be truncated, but
- * will always be null-terminated and never have an incomplete UCS-4
- * sequence at the end. If the buffer length is 0, this function does nothing.
- *
- * \param src Null-terminated source string in UTF-8 format.
- * \param dst Buffer to store converted UCS-4 string.
- * \param len Size, in bytes, of destination buffer.
- */
-PHYSFS_DECL void PHYSFS_utf8ToUcs4(const char *src, PHYSFS_uint32 *dst,
- PHYSFS_uint64 len);
-
-/**
- * \fn void PHYSFS_utf8FromUcs2(const PHYSFS_uint16 *src, char *dst, PHYSFS_uint64 len)
- * \brief Convert a UCS-2 string to a UTF-8 string.
- *
- * \warning you almost certainly should use PHYSFS_utf8FromUtf16(), which
- * became available in PhysicsFS 2.1, unless you know what you're doing.
- *
- * UCS-2 strings are 16-bits per character: \c TCHAR on Windows, when building
- * with Unicode support. Please note that modern versions of Windows use
- * UTF-16, which is an extended form of UCS-2, and not UCS-2 itself. You
- * almost certainly want PHYSFS_utf8FromUtf16() instead.
- *
- * To ensure that the destination buffer is large enough for the conversion,
- * please allocate a buffer that is double the size of the source buffer.
- * UTF-8 never uses more than 32-bits per character, so while it may shrink
- * a UCS-2 string, it may also expand it.
- *
- * Strings that don't fit in the destination buffer will be truncated, but
- * will always be null-terminated and never have an incomplete UTF-8
- * sequence at the end. If the buffer length is 0, this function does nothing.
- *
- * \param src Null-terminated source string in UCS-2 format.
- * \param dst Buffer to store converted UTF-8 string.
- * \param len Size, in bytes, of destination buffer.
- *
- * \sa PHYSFS_utf8FromUtf16
- */
-PHYSFS_DECL void PHYSFS_utf8FromUcs2(const PHYSFS_uint16 *src, char *dst,
- PHYSFS_uint64 len);
-
-/**
- * \fn PHYSFS_utf8ToUcs2(const char *src, PHYSFS_uint16 *dst, PHYSFS_uint64 len)
- * \brief Convert a UTF-8 string to a UCS-2 string.
- *
- * \warning you almost certainly should use PHYSFS_utf8ToUtf16(), which
- * became available in PhysicsFS 2.1, unless you know what you're doing.
- *
- * UCS-2 strings are 16-bits per character: \c TCHAR on Windows, when building
- * with Unicode support. Please note that modern versions of Windows use
- * UTF-16, which is an extended form of UCS-2, and not UCS-2 itself. You
- * almost certainly want PHYSFS_utf8ToUtf16() instead, but you need to
- * understand how that changes things, too.
- *
- * To ensure that the destination buffer is large enough for the conversion,
- * please allocate a buffer that is double the size of the source buffer.
- * UTF-8 uses from one to four bytes per character, but UCS-2 always uses
- * two, so an entirely low-ASCII string will double in size!
- *
- * Strings that don't fit in the destination buffer will be truncated, but
- * will always be null-terminated and never have an incomplete UCS-2
- * sequence at the end. If the buffer length is 0, this function does nothing.
- *
- * \param src Null-terminated source string in UTF-8 format.
- * \param dst Buffer to store converted UCS-2 string.
- * \param len Size, in bytes, of destination buffer.
- *
- * \sa PHYSFS_utf8ToUtf16
- */
-PHYSFS_DECL void PHYSFS_utf8ToUcs2(const char *src, PHYSFS_uint16 *dst,
- PHYSFS_uint64 len);
-
-/**
- * \fn void PHYSFS_utf8FromLatin1(const char *src, char *dst, PHYSFS_uint64 len)
- * \brief Convert a UTF-8 string to a Latin1 string.
- *
- * Latin1 strings are 8-bits per character: a popular "high ASCII" encoding.
- *
- * To ensure that the destination buffer is large enough for the conversion,
- * please allocate a buffer that is double the size of the source buffer.
- * UTF-8 expands latin1 codepoints over 127 from 1 to 2 bytes, so the string
- * may grow in some cases.
- *
- * Strings that don't fit in the destination buffer will be truncated, but
- * will always be null-terminated and never have an incomplete UTF-8
- * sequence at the end. If the buffer length is 0, this function does nothing.
- *
- * Please note that we do not supply a UTF-8 to Latin1 converter, since Latin1
- * can't express most Unicode codepoints. It's a legacy encoding; you should
- * be converting away from it at all times.
- *
- * \param src Null-terminated source string in Latin1 format.
- * \param dst Buffer to store converted UTF-8 string.
- * \param len Size, in bytes, of destination buffer.
- */
-PHYSFS_DECL void PHYSFS_utf8FromLatin1(const char *src, char *dst,
- PHYSFS_uint64 len);
-
-/* Everything above this line is part of the PhysicsFS 2.0 API. */
-
-/**
- * \fn int PHYSFS_unmount(const char *oldDir)
- * \brief Remove a directory or archive from the search path.
- *
- * This is functionally equivalent to PHYSFS_removeFromSearchPath(), but that
- * function is deprecated to keep the vocabulary paired with PHYSFS_mount().
- *
- * This must be a (case-sensitive) match to a dir or archive already in the
- * search path, specified in platform-dependent notation.
- *
- * This call will fail (and fail to remove from the path) if the element still
- * has files open in it.
- *
- * \param oldDir dir/archive to remove.
- * \return nonzero on success, zero on failure.
- * Specifics of the error can be gleaned from PHYSFS_getLastError().
- *
- * \sa PHYSFS_getSearchPath
- * \sa PHYSFS_mount
- */
-PHYSFS_DECL int PHYSFS_unmount(const char *oldDir);
-
-/**
- * \fn const PHYSFS_Allocator *PHYSFS_getAllocator(void)
- * \brief Discover the current allocator.
- *
- * (This is for limited, hardcore use. If you don't immediately see a need
- * for it, you can probably ignore this forever.)
- *
- * This function exposes the function pointers that make up the currently used
- * allocator. This can be useful for apps that want to access PhysicsFS's
- * internal, default allocation routines, as well as for external code that
- * wants to share the same allocator, even if the application specified their
- * own.
- *
- * This call is only valid between PHYSFS_init() and PHYSFS_deinit() calls;
- * it will return NULL if the library isn't initialized. As we can't
- * guarantee the state of the internal allocators unless the library is
- * initialized, you shouldn't use any allocator returned here after a call
- * to PHYSFS_deinit().
- *
- * Do not call the returned allocator's Init() or Deinit() methods under any
- * circumstances.
- *
- * If you aren't immediately sure what to do with this function, you can
- * safely ignore it altogether.
- *
- * \return Current allocator, as set by PHYSFS_setAllocator(), or PhysicsFS's
- * internal, default allocator if no application defined allocator
- * is currently set. Will return NULL if the library is not
- * initialized.
- *
- * \sa PHYSFS_Allocator
- * \sa PHYSFS_setAllocator
- */
-PHYSFS_DECL const PHYSFS_Allocator *PHYSFS_getAllocator(void);
-
-#endif /* SWIG */
-
-/**
- * \enum PHYSFS_FileType
- * \brief Type of a File
- *
- * Possible types of a file.
- *
- * \sa PHYSFS_stat
- */
-typedef enum PHYSFS_FileType
-{
- PHYSFS_FILETYPE_REGULAR, /**< a normal file */
- PHYSFS_FILETYPE_DIRECTORY, /**< a directory */
- PHYSFS_FILETYPE_SYMLINK, /**< a symlink */
- PHYSFS_FILETYPE_OTHER /**< something completely different like a device */
-} PHYSFS_FileType;
-
-/**
- * \struct PHYSFS_Stat
- * \brief Meta data for a file or directory
- *
- * Container for various meta data about a file in the virtual file system.
- * PHYSFS_stat() uses this structure for returning the information. The time
- * data will be either the number of seconds since the Unix epoch (midnight,
- * Jan 1, 1970), or -1 if the information isn't available or applicable.
- * The (filesize) field is measured in bytes.
- * The (readonly) field tells you whether when you open a file for writing you
- * are writing to the same file as if you were opening it, given you have
- * enough filesystem rights to do that. !!! FIXME: this might change.
- *
- * \sa PHYSFS_stat
- * \sa PHYSFS_FileType
- */
-typedef struct PHYSFS_Stat
-{
- PHYSFS_sint64 filesize; /**< size in bytes, -1 for non-files and unknown */
- PHYSFS_sint64 modtime; /**< last modification time */
- PHYSFS_sint64 createtime; /**< like modtime, but for file creation time */
- PHYSFS_sint64 accesstime; /**< like modtime, but for file access time */
- PHYSFS_FileType filetype; /**< File? Directory? Symlink? */
- int readonly; /**< non-zero if read only, zero if writable. */
-} PHYSFS_Stat;
-
-/**
- * \fn int PHYSFS_stat(const char *fname, PHYSFS_Stat *stat)
- * \brief Get various information about a directory or a file.
- *
- * Obtain various information about a file or directory from the meta data.
- *
- * This function will never follow symbolic links. If you haven't enabled
- * symlinks with PHYSFS_permitSymbolicLinks(), stat'ing a symlink will be
- * treated like stat'ing a non-existant file. If symlinks are enabled,
- * stat'ing a symlink will give you information on the link itself and not
- * what it points to.
- *
- * \param fname filename to check, in platform-indepedent notation.
- * \param stat pointer to structure to fill in with data about (fname).
- * \return non-zero on success, zero on failure. On failure, (stat)'s
- * contents are undefined.
- *
- * \sa PHYSFS_Stat
- */
-PHYSFS_DECL int PHYSFS_stat(const char *fname, PHYSFS_Stat *stat);
-
-
-#ifndef SWIG /* not available from scripting languages. */
-
-/**
- * \fn void PHYSFS_utf8FromUtf16(const PHYSFS_uint16 *src, char *dst, PHYSFS_uint64 len)
- * \brief Convert a UTF-16 string to a UTF-8 string.
- *
- * UTF-16 strings are 16-bits per character (except some chars, which are
- * 32-bits): \c TCHAR on Windows, when building with Unicode support. Modern
- * Windows releases use UTF-16. Windows releases before 2000 used TCHAR, but
- * only handled UCS-2. UTF-16 _is_ UCS-2, except for the characters that
- * are 4 bytes, which aren't representable in UCS-2 at all anyhow. If you
- * aren't sure, you should be using UTF-16 at this point on Windows.
- *
- * To ensure that the destination buffer is large enough for the conversion,
- * please allocate a buffer that is double the size of the source buffer.
- * UTF-8 never uses more than 32-bits per character, so while it may shrink
- * a UTF-16 string, it may also expand it.
- *
- * Strings that don't fit in the destination buffer will be truncated, but
- * will always be null-terminated and never have an incomplete UTF-8
- * sequence at the end. If the buffer length is 0, this function does nothing.
- *
- * \param src Null-terminated source string in UTF-16 format.
- * \param dst Buffer to store converted UTF-8 string.
- * \param len Size, in bytes, of destination buffer.
- */
-PHYSFS_DECL void PHYSFS_utf8FromUtf16(const PHYSFS_uint16 *src, char *dst,
- PHYSFS_uint64 len);
-
-/**
- * \fn PHYSFS_utf8ToUtf16(const char *src, PHYSFS_uint16 *dst, PHYSFS_uint64 len)
- * \brief Convert a UTF-8 string to a UTF-16 string.
- *
- * UTF-16 strings are 16-bits per character (except some chars, which are
- * 32-bits): \c TCHAR on Windows, when building with Unicode support. Modern
- * Windows releases use UTF-16. Windows releases before 2000 used TCHAR, but
- * only handled UCS-2. UTF-16 _is_ UCS-2, except for the characters that
- * are 4 bytes, which aren't representable in UCS-2 at all anyhow. If you
- * aren't sure, you should be using UTF-16 at this point on Windows.
- *
- * To ensure that the destination buffer is large enough for the conversion,
- * please allocate a buffer that is double the size of the source buffer.
- * UTF-8 uses from one to four bytes per character, but UTF-16 always uses
- * two to four, so an entirely low-ASCII string will double in size! The
- * UTF-16 characters that would take four bytes also take four bytes in UTF-8,
- * so you don't need to allocate 4x the space just in case: double will do.
- *
- * Strings that don't fit in the destination buffer will be truncated, but
- * will always be null-terminated and never have an incomplete UTF-16
- * surrogate pair at the end. If the buffer length is 0, this function does
- * nothing.
- *
- * \param src Null-terminated source string in UTF-8 format.
- * \param dst Buffer to store converted UTF-16 string.
- * \param len Size, in bytes, of destination buffer.
- *
- * \sa PHYSFS_utf8ToUtf16
- */
-PHYSFS_DECL void PHYSFS_utf8ToUtf16(const char *src, PHYSFS_uint16 *dst,
- PHYSFS_uint64 len);
-
-#endif /* SWIG */
-
-
-/**
- * \fn PHYSFS_sint64 PHYSFS_readBytes(PHYSFS_File *handle, void *buffer, PHYSFS_uint64 len)
- * \brief Read bytes from a PhysicsFS filehandle
- *
- * The file must be opened for reading.
- *
- * \param handle handle returned from PHYSFS_openRead().
- * \param buffer buffer of at least (len) bytes to store read data into.
- * \param len number of bytes being read from (handle).
- * \return number of bytes read. This may be less than (len); this does not
- * signify an error, necessarily (a short read may mean EOF).
- * PHYSFS_getLastError() can shed light on the reason this might
- * be < (len), as can PHYSFS_eof(). -1 if complete failure.
- *
- * \sa PHYSFS_eof
- */
-PHYSFS_DECL PHYSFS_sint64 PHYSFS_readBytes(PHYSFS_File *handle, void *buffer,
- PHYSFS_uint64 len);
-
-/**
- * \fn PHYSFS_sint64 PHYSFS_writeBytes(PHYSFS_File *handle, const void *buffer, PHYSFS_uint64 len)
- * \brief Write data to a PhysicsFS filehandle
- *
- * The file must be opened for writing.
- *
- * Please note that while (len) is an unsigned 64-bit integer, you are limited
- * to 63 bits (9223372036854775807 bytes), so we can return a negative value
- * on error. If length is greater than 0x7FFFFFFFFFFFFFFF, this function will
- * immediately fail. For systems without a 64-bit datatype, you are limited
- * to 31 bits (0x7FFFFFFF, or 2147483647 bytes). We trust most things won't
- * need to do multiple gigabytes of i/o in one call anyhow, but why limit
- * things?
- *
- * \param handle retval from PHYSFS_openWrite() or PHYSFS_openAppend().
- * \param buffer buffer of (len) bytes to write to (handle).
- * \param len number of bytes being written to (handle).
- * \return number of bytes written. This may be less than (len); in the case
- * of an error, the system may try to write as many bytes as possible,
- * so an incomplete write might occur. PHYSFS_getLastError() can shed
- * light on the reason this might be < (len). -1 if complete failure.
- */
-PHYSFS_DECL PHYSFS_sint64 PHYSFS_writeBytes(PHYSFS_File *handle,
- const void *buffer,
- PHYSFS_uint64 len);
-
-
-#ifndef SWIG /* not available from scripting languages. */
-
-/**
- * \struct PHYSFS_Io
- * \brief An abstract i/o interface.
- *
- * \warning This is advanced, hardcore stuff. You don't need this unless you
- * really know what you're doing. Most apps will not need this.
- *
- * Historically, PhysicsFS provided access to the physical filesystem and
- * archives within that filesystem. However, sometimes you need more power
- * than this. Perhaps you need to provide an archive that is entirely
- * contained in RAM, or you need to bridge some other file i/o API to
- * PhysicsFS, or you need to translate the bits (perhaps you have a
- * a standard .zip file that's encrypted, and you need to decrypt on the fly
- * for the unsuspecting zip archiver).
- *
- * A PHYSFS_Io is the interface that Archivers use to get archive data.
- * Historically, this has mapped to file i/o to the physical filesystem, but
- * as of PhysicsFS 2.1, applications can provide their own i/o implementations
- * at runtime.
- *
- * This interface isn't necessarily a good universal fit for i/o. There are a
- * few requirements of note:
- *
- * - They only do blocking i/o (at least, for now).
- * - They need to be able to duplicate. If you have a file handle from
- * fopen(), you need to be able to create a unique clone of it (so we
- * have two handles to the same file that can both seek/read/etc without
- * stepping on each other).
- * - They need to know the size of their entire data set.
- * - They need to be able to seek and rewind on demand.
- *
- * ...in short, you're probably not going to write an HTTP implementation.
- *
- * Thread safety: TO BE DECIDED. !!! FIXME
- *
- * \sa PHYSFS_mountIo
- */
-typedef struct PHYSFS_Io
-{
- /**
- * \brief Binary compatibility information.
- *
- * This must be set to zero at this time. Future versions of this
- * struct will increment this field, so we know what a given
- * implementation supports. We'll presumably keep supporting older
- * versions as we offer new features, though.
- */
- PHYSFS_uint32 version;
-
- /**
- * \brief Instance data for this struct.
- *
- * Each instance has a pointer associated with it that can be used to
- * store anything it likes. This pointer is per-instance of the stream,
- * so presumably it will change when calling duplicate(). This can be
- * deallocated during the destroy() method.
- */
- void *opaque;
-
- /**
- * \brief Read more data.
- *
- * Read (len) bytes from the interface, at the current i/o position, and
- * store them in (buffer). The current i/o position should move ahead
- * by the number of bytes successfully read.
- *
- * You don't have to implement this; set it to NULL if not implemented.
- * This will only be used if the file is opened for reading. If set to
- * NULL, a default implementation that immediately reports failure will
- * be used.
- *
- * \param io The i/o instance to read from.
- * \param buf The buffer to store data into. It must be at least
- * (len) bytes long and can't be NULL.
- * \param len The number of bytes to read from the interface.
- * \return number of bytes read from file, 0 on EOF, -1 if complete
- * failure.
- */
- PHYSFS_sint64 (*read)(struct PHYSFS_Io *io, void *buf, PHYSFS_uint64 len);
-
- /**
- * \brief Write more data.
- *
- * Write (len) bytes from (buffer) to the interface at the current i/o
- * position. The current i/o position should move ahead by the number of
- * bytes successfully written.
- *
- * You don't have to implement this; set it to NULL if not implemented.
- * This will only be used if the file is opened for writing. If set to
- * NULL, a default implementation that immediately reports failure will
- * be used.
- *
- * You are allowed to buffer; a write can succeed here and then later
- * fail when flushing. Note that PHYSFS_setBuffer() may be operating a
- * level above your i/o, so you should usually not implement your
- * own buffering routines.
- *
- * \param io The i/o instance to write to.
- * \param buffer The buffer to read data from. It must be at least
- * (len) bytes long and can't be NULL.
- * \param len The number of bytes to read from (buffer).
- * \return number of bytes written to file, -1 if complete failure.
- */
- PHYSFS_sint64 (*write)(struct PHYSFS_Io *io, const void *buffer,
- PHYSFS_uint64 len);
-
- /**
- * \brief Move i/o position to a given byte offset from start.
- *
- * This method moves the i/o position, so the next read/write will
- * be of the byte at (offset) offset. Seeks past the end of file should
- * be treated as an error condition.
- *
- * \param io The i/o instance to seek.
- * \param offset The new byte offset for the i/o position.
- * \return non-zero on success, zero on error.
- */
- int (*seek)(struct PHYSFS_Io *io, PHYSFS_uint64 offset);
-
- /**
- * \brief Report current i/o position.
- *
- * Return bytes offset, or -1 if you aren't able to determine. A failure
- * will almost certainly be fatal to further use of this stream, so you
- * may not leave this unimplemented.
- *
- * \param io The i/o instance to query.
- * \return The current byte offset for the i/o position, -1 if unknown.
- */
- PHYSFS_sint64 (*tell)(struct PHYSFS_Io *io);
-
- /**
- * \brief Determine size of the i/o instance's dataset.
- *
- * Return number of bytes available in the file, or -1 if you
- * aren't able to determine. A failure will almost certainly be fatal
- * to further use of this stream, so you may not leave this unimplemented.
- *
- * \param io The i/o instance to query.
- * \return Total size, in bytes, of the dataset.
- */
- PHYSFS_sint64 (*length)(struct PHYSFS_Io *io);
-
- /**
- * \brief Duplicate this i/o instance.
- *
- * // !!! FIXME: write me.
- *
- * \param io The i/o instance to duplicate.
- * \return A new value for a stream's (opaque) field, or NULL on error.
- */
- struct PHYSFS_Io *(*duplicate)(struct PHYSFS_Io *io);
-
- /**
- * \brief Flush resources to media, or wherever.
- *
- * This is the chance to report failure for writes that had claimed
- * success earlier, but still had a chance to actually fail. This method
- * can be NULL if flushing isn't necessary.
- *
- * This function may be called before destroy(), as it can report failure
- * and destroy() can not. It may be called at other times, too.
- *
- * \param io The i/o instance to flush.
- * \return Zero on error, non-zero on success.
- */
- int (*flush)(struct PHYSFS_Io *io);
-
- /**
- * \brief Cleanup and deallocate i/o instance.
- *
- * Free associated resources, including (opaque) if applicable.
- *
- * This function must always succeed: as such, it returns void. The
- * system may call your flush() method before this. You may report
- * failure there if necessary. This method may still be called if
- * flush() fails, in which case you'll have to abandon unflushed data
- * and other failing conditions and clean up.
- *
- * Once this method is called for a given instance, the system will assume
- * it is unsafe to touch that instance again and will discard any
- * references to it.
- *
- * \param s The i/o instance to destroy.
- */
- void (*destroy)(struct PHYSFS_Io *io);
-} PHYSFS_Io;
-
-
-/**
- * \fn int PHYSFS_mountIo(PHYSFS_Io *io, const char *fname, const char *mountPoint, int appendToPath)
- * \brief Add an archive, built on a PHYSFS_Io, to the search path.
- *
- * \warning Unless you have some special, low-level need, you should be using
- * PHYSFS_mount() instead of this.
- *
- * This function operates just like PHYSFS_mount(), but takes a PHYSFS_Io
- * instead of a pathname. Behind the scenes, PHYSFS_mount() calls this
- * function with a physical-filesystem-based PHYSFS_Io.
- *
- * (filename) is only used here to optimize archiver selection (if you name it
- * XXXXX.zip, we might try the ZIP archiver first, for example). It doesn't
- * need to refer to a real file at all, and can even be NULL. If the filename
- * isn't helpful, the system will try every archiver until one works or none
- * of them do.
- *
- * (io) must remain until the archive is unmounted. When the archive is
- * unmounted, the system will call (io)->destroy(io), which will give you
- * a chance to free your resources.
- *
- * If this function fails, (io)->destroy(io) is not called.
- *
- * \param io i/o instance for archive to add to the path.
- * \param fname Filename that can represent this stream. Can be NULL.
- * \param mountPoint Location in the interpolated tree that this archive
- * will be "mounted", in platform-independent notation.
- * NULL or "" is equivalent to "/".
- * \param appendToPath nonzero to append to search path, zero to prepend.
- * \return nonzero if added to path, zero on failure (bogus archive, stream
- * i/o issue, etc). Specifics of the error can be
- * gleaned from PHYSFS_getLastError().
- *
- * \sa PHYSFS_unmount
- * \sa PHYSFS_getSearchPath
- * \sa PHYSFS_getMountPoint
- */
-PHYSFS_DECL int PHYSFS_mountIo(PHYSFS_Io *io, const char *fname,
- const char *mountPoint, int appendToPath);
-
-#endif /* SWIG */
-
-/**
- * \fn int PHYSFS_mountMemory(const void *ptr, PHYSFS_uint64 len, void (*del)(void *), const char *fname, const char *mountPoint, int appendToPath)
- * \brief Add an archive, contained in a memory buffer, to the search path.
- *
- * \warning Unless you have some special, low-level need, you should be using
- * PHYSFS_mount() instead of this.
- *
- * This function operates just like PHYSFS_mount(), but takes a memory buffer
- * instead of a pathname. This buffer contains all the data of the archive,
- * and is used instead of a real file in the physical filesystem.
- *
- * (filename) is only used here to optimize archiver selection (if you name it
- * XXXXX.zip, we might try the ZIP archiver first, for example). It doesn't
- * need to refer to a real file at all, and can even be NULL. If the filename
- * isn't helpful, the system will try every archiver until one works or none
- * of them do.
- *
- * (ptr) must remain until the archive is unmounted. When the archive is
- * unmounted, the system will call (del)(ptr), which will notify you that
- * the system is done with the buffer, and give you a chance to free your
- * resources. (del) can be NULL, in which case the system will make no
- * attempt to free the buffer.
- *
- * If this function fails, (del) is not called.
- *
- * \param ptr Address of the memory buffer containing the archive data.
- * \param len Size of memory buffer, in bytes.
- * \param del A callback that triggers upon unmount. Can be NULL.
- * \param fname Filename that can represent this stream. Can be NULL.
- * \param mountPoint Location in the interpolated tree that this archive
- * will be "mounted", in platform-independent notation.
- * NULL or "" is equivalent to "/".
- * \param appendToPath nonzero to append to search path, zero to prepend.
- * \return nonzero if added to path, zero on failure (bogus archive, etc).
- * Specifics of the error can be gleaned from
- * PHYSFS_getLastError().
- *
- * \sa PHYSFS_unmount
- * \sa PHYSFS_getSearchPath
- * \sa PHYSFS_getMountPoint
- */
-PHYSFS_DECL int PHYSFS_mountMemory(const void *buf, PHYSFS_uint64 len,
- void (*del)(void *), const char *fname,
- const char *mountPoint, int appendToPath);
-
-
-/**
- * \fn int PHYSFS_mountHandle(PHYSFS_File *file, const char *fname, const char *mountPoint, int appendToPath)
- * \brief Add an archive, contained in a PHYSFS_File handle, to the search path.
- *
- * \warning Unless you have some special, low-level need, you should be using
- * PHYSFS_mount() instead of this.
- *
- * \warning Archives-in-archives may be very slow! While a PHYSFS_File can
- * seek even when the data is compressed, it may do so by rewinding
- * to the start and decompressing everything before the seek point.
- * Normal archive usage may do a lot of seeking behind the scenes.
- * As such, you might find normal archive usage extremely painful
- * if mounted this way. Plan accordingly: if you, say, have a
- * self-extracting .zip file, and want to mount something in it,
- * compress the contents of the inner archive and make sure the outer
- * .zip file doesn't compress the inner archive too.
- *
- * This function operates just like PHYSFS_mount(), but takes a PHYSFS_File
- * handle instead of a pathname. This handle contains all the data of the
- * archive, and is used instead of a real file in the physical filesystem.
- * The PHYSFS_File may be backed by a real file in the physical filesystem,
- * but isn't necessarily. The most popular use for this is likely to mount
- * archives stored inside other archives.
- *
- * (filename) is only used here to optimize archiver selection (if you name it
- * XXXXX.zip, we might try the ZIP archiver first, for example). It doesn't
- * need to refer to a real file at all, and can even be NULL. If the filename
- * isn't helpful, the system will try every archiver until one works or none
- * of them do.
- *
- * (file) must remain until the archive is unmounted. When the archive is
- * unmounted, the system will call PHYSFS_close(file). If you need this
- * handle to survive, you will have to wrap this in a PHYSFS_Io and use
- * PHYSFS_mountIo() instead.
- *
- * If this function fails, PHYSFS_close(file) is not called.
- *
- * \param file The PHYSFS_File handle containing archive data.
- * \param fname Filename that can represent this stream. Can be NULL.
- * \param mountPoint Location in the interpolated tree that this archive
- * will be "mounted", in platform-independent notation.
- * NULL or "" is equivalent to "/".
- * \param appendToPath nonzero to append to search path, zero to prepend.
- * \return nonzero if added to path, zero on failure (bogus archive, etc).
- * Specifics of the error can be gleaned from
- * PHYSFS_getLastError().
- *
- * \sa PHYSFS_unmount
- * \sa PHYSFS_getSearchPath
- * \sa PHYSFS_getMountPoint
- */
-PHYSFS_DECL int PHYSFS_mountHandle(PHYSFS_File *file, const char *fname,
- const char *mountPoint, int appendToPath);
-
-
-/**
- * \enum PHYSFS_ErrorCode
- * \brief Values that represent specific causes of failure.
- *
- * Most of the time, you should only concern yourself with whether a given
- * operation failed or not, but there may be occasions where you plan to
- * handle a specific failure case gracefully, so we provide specific error
- * codes.
- *
- * Most of these errors are a little vague, and most aren't things you can
- * fix...if there's a permission error, for example, all you can really do
- * is pass that information on to the user and let them figure out how to
- * handle it. In most these cases, your program should only care that it
- * failed to accomplish its goals, and not care specifically why.
- *
- * \sa PHYSFS_getLastErrorCode
- * \sa PHYSFS_getErrorByCode
- */
-typedef enum PHYSFS_ErrorCode
-{
- PHYSFS_ERR_OK, /**< Success; no error. */
- PHYSFS_ERR_OTHER_ERROR, /**< Error not otherwise covered here. */
- PHYSFS_ERR_OUT_OF_MEMORY, /**< Memory allocation failed. */
- PHYSFS_ERR_NOT_INITIALIZED, /**< PhysicsFS is not initialized. */
- PHYSFS_ERR_IS_INITIALIZED, /**< PhysicsFS is already initialized. */
- PHYSFS_ERR_ARGV0_IS_NULL, /**< Needed argv[0], but it is NULL. */
- PHYSFS_ERR_UNSUPPORTED, /**< Operation or feature unsupported. */
- PHYSFS_ERR_PAST_EOF, /**< Attempted to access past end of file. */
- PHYSFS_ERR_FILES_STILL_OPEN, /**< Files still open. */
- PHYSFS_ERR_INVALID_ARGUMENT, /**< Bad parameter passed to an function. */
- PHYSFS_ERR_NOT_MOUNTED, /**< Requested archive/dir not mounted. */
- PHYSFS_ERR_NO_SUCH_PATH, /**< No such file, directory, or parent. */
- PHYSFS_ERR_SYMLINK_FORBIDDEN,/**< Symlink seen when not permitted. */
- PHYSFS_ERR_NO_WRITE_DIR, /**< No write dir has been specified. */
- PHYSFS_ERR_OPEN_FOR_READING, /**< Wrote to a file opened for reading. */
- PHYSFS_ERR_OPEN_FOR_WRITING, /**< Read from a file opened for writing. */
- PHYSFS_ERR_NOT_A_FILE, /**< Needed a file, got a directory (etc). */
- PHYSFS_ERR_READ_ONLY, /**< Wrote to a read-only filesystem. */
- PHYSFS_ERR_CORRUPT, /**< Corrupted data encountered. */
- PHYSFS_ERR_SYMLINK_LOOP, /**< Infinite symbolic link loop. */
- PHYSFS_ERR_IO, /**< i/o error (hardware failure, etc). */
- PHYSFS_ERR_PERMISSION, /**< Permission denied. */
- PHYSFS_ERR_NO_SPACE, /**< No space (disk full, over quota, etc) */
- PHYSFS_ERR_BAD_FILENAME, /**< Filename is bogus/insecure. */
- PHYSFS_ERR_BUSY, /**< Tried to modify a file the OS needs. */
- PHYSFS_ERR_DIR_NOT_EMPTY, /**< Tried to delete dir with files in it. */
- PHYSFS_ERR_OS_ERROR /**< Unspecified OS-level error. */
-} PHYSFS_ErrorCode;
-
-
-/**
- * \fn PHYSFS_ErrorCode PHYSFS_getLastErrorCode(void)
- * \brief Get machine-readable error information.
- *
- * Get the last PhysicsFS error message as an integer value. This will return
- * PHYSFS_ERR_OK if there's been no error since the last call to this
- * function. Each thread has a unique error state associated with it, but
- * each time a new error message is set, it will overwrite the previous one
- * associated with that thread. It is safe to call this function at anytime,
- * even before PHYSFS_init().
- *
- * PHYSFS_getLastError() and PHYSFS_getLastErrorCode() both reset the same
- * thread-specific error state. Calling one will wipe out the other's
- * data. If you need both, call PHYSFS_getLastErrorCode(), then pass that
- * value to PHYSFS_getErrorByCode().
- *
- * Generally, applications should only concern themselves with whether a
- * given function failed; however, if you require more specifics, you can
- * try this function to glean information, if there's some specific problem
- * you're expecting and plan to handle. But with most things that involve
- * file systems, the best course of action is usually to give up, report the
- * problem to the user, and let them figure out what should be done about it.
- * For that, you might prefer PHYSFS_getLastError() instead.
- *
- * \return Enumeration value that represents last reported error.
- *
- * \sa PHYSFS_getErrorByCode
- */
-PHYSFS_DECL PHYSFS_ErrorCode PHYSFS_getLastErrorCode(void);
-
-
-/**
- * \fn const char *PHYSFS_getErrorByCode(PHYSFS_ErrorCode code)
- * \brief Get human-readable description string for a given error code.
- *
- * Get a static string, in UTF-8 format, that represents an English
- * description of a given error code.
- *
- * This string is guaranteed to never change (although we may add new strings
- * for new error codes in later versions of PhysicsFS), so you can use it
- * for keying a localization dictionary.
- *
- * It is safe to call this function at anytime, even before PHYSFS_init().
- *
- * These strings are meant to be passed on directly to the user.
- * Generally, applications should only concern themselves with whether a
- * given function failed, but not care about the specifics much.
- *
- * Do not attempt to free the returned strings; they are read-only and you
- * don't own their memory pages.
- *
- * \param code Error code to convert to a string.
- * \return READ ONLY string of requested error message, NULL if this
- * is not a valid PhysicsFS error code. Always check for NULL if
- * you might be looking up an error code that didn't exist in an
- * earlier version of PhysicsFS.
- *
- * \sa PHYSFS_getLastErrorCode
- */
-PHYSFS_DECL const char *PHYSFS_getErrorByCode(PHYSFS_ErrorCode code);
-
-/**
- * \fn void PHYSFS_setErrorCode(PHYSFS_ErrorCode code)
- * \brief Set the current thread's error code.
- *
- * This lets you set the value that will be returned by the next call to
- * PHYSFS_getLastErrorCode(). This will replace any existing error code,
- * whether set by your application or internally by PhysicsFS.
- *
- * Error codes are stored per-thread; what you set here will not be
- * accessible to another thread.
- *
- * Any call into PhysicsFS may change the current error code, so any code you
- * set here is somewhat fragile, and thus you shouldn't build any serious
- * error reporting framework on this function. The primary goal of this
- * function is to allow PHYSFS_Io implementations to set the error state,
- * which generally will be passed back to your application when PhysicsFS
- * makes a PHYSFS_Io call that fails internally.
- *
- * This function doesn't care if the error code is a value known to PhysicsFS
- * or not (but PHYSFS_getErrorByCode() will return NULL for unknown values).
- * The value will be reported unmolested by PHYSFS_getLastErrorCode().
- *
- * \param code Error code to become the current thread's new error state.
- *
- * \sa PHYSFS_getLastErrorCode
- * \sa PHYSFS_getErrorByCode
- */
-PHYSFS_DECL void PHYSFS_setErrorCode(PHYSFS_ErrorCode code);
-
-
-/**
- * \fn const char *PHYSFS_getPrefDir(const char *org, const char *app)
- * \brief Get the user-and-app-specific path where files can be written.
- *
- * Helper function.
- *
- * Get the "pref dir". This is meant to be where users can write personal
- * files (preferences and save games, etc) that are specific to your
- * application. This directory is unique per user, per application.
- *
- * This function will decide the appropriate location in the native filesystem,
- * create the directory if necessary, and return a string in
- * platform-dependent notation, suitable for passing to PHYSFS_setWriteDir().
- *
- * On Windows, this might look like:
- * "C:\\Users\\bob\\AppData\\Roaming\\My Company\\My Program Name"
- *
- * On Linux, this might look like:
- * "/home/bob/.local/share/My Program Name"
- *
- * On Mac OS X, this might look like:
- * "/Users/bob/Library/Application Support/My Program Name"
- *
- * (etc.)
- *
- * You should probably use the pref dir for your write dir, and also put it
- * near the beginning of your search path. Older versions of PhysicsFS
- * offered only PHYSFS_getUserDir() and left you to figure out where the
- * files should go under that tree. This finds the correct location
- * for whatever platform, which not only changes between operating systems,
- * but also versions of the same operating system.
- *
- * You specify the name of your organization (if it's not a real organization,
- * your name or an Internet domain you own might do) and the name of your
- * application. These should be proper names.
- *
- * Both the (org) and (app) strings may become part of a directory name, so
- * please follow these rules:
- *
- * - Try to use the same org string (including case-sensitivity) for
- * all your applications that use this function.
- * - Always use a unique app string for each one, and make sure it never
- * changes for an app once you've decided on it.
- * - Unicode characters are legal, as long as it's UTF-8 encoded, but...
- * - ...only use letters, numbers, and spaces. Avoid punctuation like
- * "Game Name 2: Bad Guy's Revenge!" ... "Game Name 2" is sufficient.
- *
- * The pointer returned by this function remains valid until you call this
- * function again, or call PHYSFS_deinit(). This is not necessarily a fast
- * call, though, so you should call this once at startup and copy the string
- * if you need it.
- *
- * You should assume the path returned by this function is the only safe
- * place to write files (and that PHYSFS_getUserDir() and PHYSFS_getBaseDir(),
- * while they might be writable, or even parents of the returned path, aren't
- * where you should be writing things).
- *
- * \param org The name of your organization.
- * \param app The name of your application.
- * \return READ ONLY string of user dir in platform-dependent notation. NULL
- * if there's a problem (creating directory failed, etc).
- *
- * \sa PHYSFS_getBaseDir
- * \sa PHYSFS_getUserDir
- */
-PHYSFS_DECL const char *PHYSFS_getPrefDir(const char *org, const char *app);
-
-
-/* Everything above this line is part of the PhysicsFS 2.1 API. */
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* !defined _INCLUDE_PHYSFS_H_ */
-
-/* end of physfs.h ... */
-
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/src/physfs_byteorder.c
--- a/misc/physfs/src/physfs_byteorder.c Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,137 +0,0 @@
-/**
- * PhysicsFS; a portable, flexible file i/o abstraction.
- *
- * Documentation is in physfs.h. It's verbose, honest. :)
- *
- * Please see the file LICENSE.txt in the source's root directory.
- *
- * This file written by Ryan C. Gordon.
- */
-
-#define __PHYSICSFS_INTERNAL__
-#include "physfs_internal.h"
-
-#ifndef PHYSFS_Swap16
-static inline PHYSFS_uint16 PHYSFS_Swap16(PHYSFS_uint16 D)
-{
- return ((D<<8)|(D>>8));
-}
-#endif
-#ifndef PHYSFS_Swap32
-static inline PHYSFS_uint32 PHYSFS_Swap32(PHYSFS_uint32 D)
-{
- return ((D<<24)|((D<<8)&0x00FF0000)|((D>>8)&0x0000FF00)|(D>>24));
-}
-#endif
-#ifndef PHYSFS_NO_64BIT_SUPPORT
-#ifndef PHYSFS_Swap64
-static inline PHYSFS_uint64 PHYSFS_Swap64(PHYSFS_uint64 val) {
- PHYSFS_uint32 hi, lo;
-
- /* Separate into high and low 32-bit values and swap them */
- lo = (PHYSFS_uint32)(val&0xFFFFFFFF);
- val >>= 32;
- hi = (PHYSFS_uint32)(val&0xFFFFFFFF);
- val = PHYSFS_Swap32(lo);
- val <<= 32;
- val |= PHYSFS_Swap32(hi);
- return val;
-}
-#endif
-#else
-#ifndef PHYSFS_Swap64
-/* This is mainly to keep compilers from complaining in PHYSFS code.
- If there is no real 64-bit datatype, then compilers will complain about
- the fake 64-bit datatype that PHYSFS provides when it compiles user code.
-*/
-#define PHYSFS_Swap64(X) (X)
-#endif
-#endif /* PHYSFS_NO_64BIT_SUPPORT */
-
-
-/* Byteswap item from the specified endianness to the native endianness */
-#if PHYSFS_BYTEORDER == PHYSFS_LIL_ENDIAN
-PHYSFS_uint16 PHYSFS_swapULE16(PHYSFS_uint16 x) { return x; }
-PHYSFS_sint16 PHYSFS_swapSLE16(PHYSFS_sint16 x) { return x; }
-PHYSFS_uint32 PHYSFS_swapULE32(PHYSFS_uint32 x) { return x; }
-PHYSFS_sint32 PHYSFS_swapSLE32(PHYSFS_sint32 x) { return x; }
-PHYSFS_uint64 PHYSFS_swapULE64(PHYSFS_uint64 x) { return x; }
-PHYSFS_sint64 PHYSFS_swapSLE64(PHYSFS_sint64 x) { return x; }
-
-PHYSFS_uint16 PHYSFS_swapUBE16(PHYSFS_uint16 x) { return PHYSFS_Swap16(x); }
-PHYSFS_sint16 PHYSFS_swapSBE16(PHYSFS_sint16 x) { return PHYSFS_Swap16(x); }
-PHYSFS_uint32 PHYSFS_swapUBE32(PHYSFS_uint32 x) { return PHYSFS_Swap32(x); }
-PHYSFS_sint32 PHYSFS_swapSBE32(PHYSFS_sint32 x) { return PHYSFS_Swap32(x); }
-PHYSFS_uint64 PHYSFS_swapUBE64(PHYSFS_uint64 x) { return PHYSFS_Swap64(x); }
-PHYSFS_sint64 PHYSFS_swapSBE64(PHYSFS_sint64 x) { return PHYSFS_Swap64(x); }
-#else
-PHYSFS_uint16 PHYSFS_swapULE16(PHYSFS_uint16 x) { return PHYSFS_Swap16(x); }
-PHYSFS_sint16 PHYSFS_swapSLE16(PHYSFS_sint16 x) { return PHYSFS_Swap16(x); }
-PHYSFS_uint32 PHYSFS_swapULE32(PHYSFS_uint32 x) { return PHYSFS_Swap32(x); }
-PHYSFS_sint32 PHYSFS_swapSLE32(PHYSFS_sint32 x) { return PHYSFS_Swap32(x); }
-PHYSFS_uint64 PHYSFS_swapULE64(PHYSFS_uint64 x) { return PHYSFS_Swap64(x); }
-PHYSFS_sint64 PHYSFS_swapSLE64(PHYSFS_sint64 x) { return PHYSFS_Swap64(x); }
-
-PHYSFS_uint16 PHYSFS_swapUBE16(PHYSFS_uint16 x) { return x; }
-PHYSFS_sint16 PHYSFS_swapSBE16(PHYSFS_sint16 x) { return x; }
-PHYSFS_uint32 PHYSFS_swapUBE32(PHYSFS_uint32 x) { return x; }
-PHYSFS_sint32 PHYSFS_swapSBE32(PHYSFS_sint32 x) { return x; }
-PHYSFS_uint64 PHYSFS_swapUBE64(PHYSFS_uint64 x) { return x; }
-PHYSFS_sint64 PHYSFS_swapSBE64(PHYSFS_sint64 x) { return x; }
-#endif
-
-static inline int readAll(PHYSFS_File *file, void *val, const size_t len)
-{
- return (PHYSFS_readBytes(file, val, len) == len);
-} /* readAll */
-
-#define PHYSFS_BYTEORDER_READ(datatype, swaptype) \
- int PHYSFS_read##swaptype(PHYSFS_File *file, PHYSFS_##datatype *val) { \
- PHYSFS_##datatype in; \
- BAIL_IF_MACRO(val == NULL, PHYSFS_ERR_INVALID_ARGUMENT, 0); \
- BAIL_IF_MACRO(!readAll(file, &in, sizeof (in)), ERRPASS, 0); \
- *val = PHYSFS_swap##swaptype(in); \
- return 1; \
- }
-
-PHYSFS_BYTEORDER_READ(sint16, SLE16)
-PHYSFS_BYTEORDER_READ(uint16, ULE16)
-PHYSFS_BYTEORDER_READ(sint16, SBE16)
-PHYSFS_BYTEORDER_READ(uint16, UBE16)
-PHYSFS_BYTEORDER_READ(sint32, SLE32)
-PHYSFS_BYTEORDER_READ(uint32, ULE32)
-PHYSFS_BYTEORDER_READ(sint32, SBE32)
-PHYSFS_BYTEORDER_READ(uint32, UBE32)
-PHYSFS_BYTEORDER_READ(sint64, SLE64)
-PHYSFS_BYTEORDER_READ(uint64, ULE64)
-PHYSFS_BYTEORDER_READ(sint64, SBE64)
-PHYSFS_BYTEORDER_READ(uint64, UBE64)
-
-
-static inline int writeAll(PHYSFS_File *f, const void *val, const size_t len)
-{
- return (PHYSFS_writeBytes(f, val, len) == len);
-} /* writeAll */
-
-#define PHYSFS_BYTEORDER_WRITE(datatype, swaptype) \
- int PHYSFS_write##swaptype(PHYSFS_File *file, PHYSFS_##datatype val) { \
- const PHYSFS_##datatype out = PHYSFS_swap##swaptype(val); \
- BAIL_IF_MACRO(!writeAll(file, &out, sizeof (out)), ERRPASS, 0); \
- return 1; \
- }
-
-PHYSFS_BYTEORDER_WRITE(sint16, SLE16)
-PHYSFS_BYTEORDER_WRITE(uint16, ULE16)
-PHYSFS_BYTEORDER_WRITE(sint16, SBE16)
-PHYSFS_BYTEORDER_WRITE(uint16, UBE16)
-PHYSFS_BYTEORDER_WRITE(sint32, SLE32)
-PHYSFS_BYTEORDER_WRITE(uint32, ULE32)
-PHYSFS_BYTEORDER_WRITE(sint32, SBE32)
-PHYSFS_BYTEORDER_WRITE(uint32, UBE32)
-PHYSFS_BYTEORDER_WRITE(sint64, SLE64)
-PHYSFS_BYTEORDER_WRITE(uint64, ULE64)
-PHYSFS_BYTEORDER_WRITE(sint64, SBE64)
-PHYSFS_BYTEORDER_WRITE(uint64, UBE64)
-
-/* end of physfs_byteorder.c ... */
-
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/src/physfs_casefolding.h
--- a/misc/physfs/src/physfs_casefolding.h Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2013 +0,0 @@
-/*
- * This file is part of PhysicsFS (http://icculus.org/physfs/)
- *
- * This data generated by physfs/extras/makecasefoldhashtable.pl ...
- * Do not manually edit this file!
- *
- * Please see the file LICENSE.txt in the source's root directory.
- */
-
-#ifndef __PHYSICSFS_INTERNAL__
-#error Do not include this header from your applications.
-#endif
-
-static const CaseFoldMapping case_fold_000[] = {
- { 0x0202, 0x0203, 0x0000, 0x0000 },
- { 0x0404, 0x0454, 0x0000, 0x0000 },
- { 0x1E1E, 0x1E1F, 0x0000, 0x0000 },
- { 0x2C2C, 0x2C5C, 0x0000, 0x0000 },
- { 0x10404, 0x1042C, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_001[] = {
- { 0x0100, 0x0101, 0x0000, 0x0000 },
- { 0x0405, 0x0455, 0x0000, 0x0000 },
- { 0x0504, 0x0505, 0x0000, 0x0000 },
- { 0x2C2D, 0x2C5D, 0x0000, 0x0000 },
- { 0x10405, 0x1042D, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_002[] = {
- { 0x0200, 0x0201, 0x0000, 0x0000 },
- { 0x0406, 0x0456, 0x0000, 0x0000 },
- { 0x1E1C, 0x1E1D, 0x0000, 0x0000 },
- { 0x1F1D, 0x1F15, 0x0000, 0x0000 },
- { 0x2C2E, 0x2C5E, 0x0000, 0x0000 },
- { 0x10406, 0x1042E, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_003[] = {
- { 0x0102, 0x0103, 0x0000, 0x0000 },
- { 0x0407, 0x0457, 0x0000, 0x0000 },
- { 0x0506, 0x0507, 0x0000, 0x0000 },
- { 0x1F1C, 0x1F14, 0x0000, 0x0000 },
- { 0x10407, 0x1042F, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_004[] = {
- { 0x0206, 0x0207, 0x0000, 0x0000 },
- { 0x0400, 0x0450, 0x0000, 0x0000 },
- { 0x1E1A, 0x1E1B, 0x0000, 0x0000 },
- { 0x1F1B, 0x1F13, 0x0000, 0x0000 },
- { 0x2C28, 0x2C58, 0x0000, 0x0000 },
- { 0x10400, 0x10428, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_005[] = {
- { 0x0104, 0x0105, 0x0000, 0x0000 },
- { 0x0401, 0x0451, 0x0000, 0x0000 },
- { 0x0500, 0x0501, 0x0000, 0x0000 },
- { 0x1F1A, 0x1F12, 0x0000, 0x0000 },
- { 0x2C29, 0x2C59, 0x0000, 0x0000 },
- { 0x10401, 0x10429, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_006[] = {
- { 0x0204, 0x0205, 0x0000, 0x0000 },
- { 0x0402, 0x0452, 0x0000, 0x0000 },
- { 0x1E18, 0x1E19, 0x0000, 0x0000 },
- { 0x1F19, 0x1F11, 0x0000, 0x0000 },
- { 0x2C2A, 0x2C5A, 0x0000, 0x0000 },
- { 0x10402, 0x1042A, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_007[] = {
- { 0x0106, 0x0107, 0x0000, 0x0000 },
- { 0x0403, 0x0453, 0x0000, 0x0000 },
- { 0x0502, 0x0503, 0x0000, 0x0000 },
- { 0x1F18, 0x1F10, 0x0000, 0x0000 },
- { 0x2126, 0x03C9, 0x0000, 0x0000 },
- { 0x2C2B, 0x2C5B, 0x0000, 0x0000 },
- { 0x10403, 0x1042B, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_008[] = {
- { 0x020A, 0x020B, 0x0000, 0x0000 },
- { 0x040C, 0x045C, 0x0000, 0x0000 },
- { 0x1E16, 0x1E17, 0x0000, 0x0000 },
- { 0x2C24, 0x2C54, 0x0000, 0x0000 },
- { 0x1040C, 0x10434, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_009[] = {
- { 0x0108, 0x0109, 0x0000, 0x0000 },
- { 0x040D, 0x045D, 0x0000, 0x0000 },
- { 0x050C, 0x050D, 0x0000, 0x0000 },
- { 0x2C25, 0x2C55, 0x0000, 0x0000 },
- { 0x1040D, 0x10435, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_010[] = {
- { 0x0208, 0x0209, 0x0000, 0x0000 },
- { 0x040E, 0x045E, 0x0000, 0x0000 },
- { 0x1E14, 0x1E15, 0x0000, 0x0000 },
- { 0x212B, 0x00E5, 0x0000, 0x0000 },
- { 0x2C26, 0x2C56, 0x0000, 0x0000 },
- { 0x1040E, 0x10436, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_011[] = {
- { 0x010A, 0x010B, 0x0000, 0x0000 },
- { 0x040F, 0x045F, 0x0000, 0x0000 },
- { 0x050E, 0x050F, 0x0000, 0x0000 },
- { 0x212A, 0x006B, 0x0000, 0x0000 },
- { 0x2C27, 0x2C57, 0x0000, 0x0000 },
- { 0x1040F, 0x10437, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_012[] = {
- { 0x020E, 0x020F, 0x0000, 0x0000 },
- { 0x0408, 0x0458, 0x0000, 0x0000 },
- { 0x1E12, 0x1E13, 0x0000, 0x0000 },
- { 0x2C20, 0x2C50, 0x0000, 0x0000 },
- { 0x10408, 0x10430, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_013[] = {
- { 0x010C, 0x010D, 0x0000, 0x0000 },
- { 0x0409, 0x0459, 0x0000, 0x0000 },
- { 0x0508, 0x0509, 0x0000, 0x0000 },
- { 0x2C21, 0x2C51, 0x0000, 0x0000 },
- { 0x10409, 0x10431, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_014[] = {
- { 0x020C, 0x020D, 0x0000, 0x0000 },
- { 0x040A, 0x045A, 0x0000, 0x0000 },
- { 0x1E10, 0x1E11, 0x0000, 0x0000 },
- { 0x2C22, 0x2C52, 0x0000, 0x0000 },
- { 0x1040A, 0x10432, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_015[] = {
- { 0x010E, 0x010F, 0x0000, 0x0000 },
- { 0x040B, 0x045B, 0x0000, 0x0000 },
- { 0x050A, 0x050B, 0x0000, 0x0000 },
- { 0x2C23, 0x2C53, 0x0000, 0x0000 },
- { 0x1040B, 0x10433, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_016[] = {
- { 0x0212, 0x0213, 0x0000, 0x0000 },
- { 0x0414, 0x0434, 0x0000, 0x0000 },
- { 0x1E0E, 0x1E0F, 0x0000, 0x0000 },
- { 0x1F0F, 0x1F07, 0x0000, 0x0000 },
- { 0x10414, 0x1043C, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_017[] = {
- { 0x0110, 0x0111, 0x0000, 0x0000 },
- { 0x0415, 0x0435, 0x0000, 0x0000 },
- { 0x1F0E, 0x1F06, 0x0000, 0x0000 },
- { 0x10415, 0x1043D, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_018[] = {
- { 0x0210, 0x0211, 0x0000, 0x0000 },
- { 0x0416, 0x0436, 0x0000, 0x0000 },
- { 0x1E0C, 0x1E0D, 0x0000, 0x0000 },
- { 0x1F0D, 0x1F05, 0x0000, 0x0000 },
- { 0x10416, 0x1043E, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_019[] = {
- { 0x0112, 0x0113, 0x0000, 0x0000 },
- { 0x0417, 0x0437, 0x0000, 0x0000 },
- { 0x1F0C, 0x1F04, 0x0000, 0x0000 },
- { 0x10417, 0x1043F, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_020[] = {
- { 0x0216, 0x0217, 0x0000, 0x0000 },
- { 0x0410, 0x0430, 0x0000, 0x0000 },
- { 0x1E0A, 0x1E0B, 0x0000, 0x0000 },
- { 0x1F0B, 0x1F03, 0x0000, 0x0000 },
- { 0x10410, 0x10438, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_021[] = {
- { 0x0114, 0x0115, 0x0000, 0x0000 },
- { 0x0411, 0x0431, 0x0000, 0x0000 },
- { 0x1F0A, 0x1F02, 0x0000, 0x0000 },
- { 0x10411, 0x10439, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_022[] = {
- { 0x0214, 0x0215, 0x0000, 0x0000 },
- { 0x0412, 0x0432, 0x0000, 0x0000 },
- { 0x1E08, 0x1E09, 0x0000, 0x0000 },
- { 0x1F09, 0x1F01, 0x0000, 0x0000 },
- { 0x10412, 0x1043A, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_023[] = {
- { 0x0116, 0x0117, 0x0000, 0x0000 },
- { 0x0413, 0x0433, 0x0000, 0x0000 },
- { 0x1F08, 0x1F00, 0x0000, 0x0000 },
- { 0x10413, 0x1043B, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_024[] = {
- { 0x021A, 0x021B, 0x0000, 0x0000 },
- { 0x041C, 0x043C, 0x0000, 0x0000 },
- { 0x1E06, 0x1E07, 0x0000, 0x0000 },
- { 0x1041C, 0x10444, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_025[] = {
- { 0x0118, 0x0119, 0x0000, 0x0000 },
- { 0x041D, 0x043D, 0x0000, 0x0000 },
- { 0x1041D, 0x10445, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_026[] = {
- { 0x0218, 0x0219, 0x0000, 0x0000 },
- { 0x041E, 0x043E, 0x0000, 0x0000 },
- { 0x1E04, 0x1E05, 0x0000, 0x0000 },
- { 0x1041E, 0x10446, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_027[] = {
- { 0x011A, 0x011B, 0x0000, 0x0000 },
- { 0x041F, 0x043F, 0x0000, 0x0000 },
- { 0x1041F, 0x10447, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_028[] = {
- { 0x021E, 0x021F, 0x0000, 0x0000 },
- { 0x0418, 0x0438, 0x0000, 0x0000 },
- { 0x1E02, 0x1E03, 0x0000, 0x0000 },
- { 0x10418, 0x10440, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_029[] = {
- { 0x011C, 0x011D, 0x0000, 0x0000 },
- { 0x0419, 0x0439, 0x0000, 0x0000 },
- { 0x10419, 0x10441, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_030[] = {
- { 0x021C, 0x021D, 0x0000, 0x0000 },
- { 0x041A, 0x043A, 0x0000, 0x0000 },
- { 0x1E00, 0x1E01, 0x0000, 0x0000 },
- { 0x1041A, 0x10442, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_031[] = {
- { 0x011E, 0x011F, 0x0000, 0x0000 },
- { 0x041B, 0x043B, 0x0000, 0x0000 },
- { 0x1041B, 0x10443, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_032[] = {
- { 0x0222, 0x0223, 0x0000, 0x0000 },
- { 0x0424, 0x0444, 0x0000, 0x0000 },
- { 0x1E3E, 0x1E3F, 0x0000, 0x0000 },
- { 0x1F3F, 0x1F37, 0x0000, 0x0000 },
- { 0x2C0C, 0x2C3C, 0x0000, 0x0000 },
- { 0x10424, 0x1044C, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_033[] = {
- { 0x0120, 0x0121, 0x0000, 0x0000 },
- { 0x0425, 0x0445, 0x0000, 0x0000 },
- { 0x1F3E, 0x1F36, 0x0000, 0x0000 },
- { 0x2C0D, 0x2C3D, 0x0000, 0x0000 },
- { 0x10425, 0x1044D, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_034[] = {
- { 0x0220, 0x019E, 0x0000, 0x0000 },
- { 0x0426, 0x0446, 0x0000, 0x0000 },
- { 0x1E3C, 0x1E3D, 0x0000, 0x0000 },
- { 0x1F3D, 0x1F35, 0x0000, 0x0000 },
- { 0x2C0E, 0x2C3E, 0x0000, 0x0000 },
- { 0x10426, 0x1044E, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_035[] = {
- { 0x0122, 0x0123, 0x0000, 0x0000 },
- { 0x0427, 0x0447, 0x0000, 0x0000 },
- { 0x1F3C, 0x1F34, 0x0000, 0x0000 },
- { 0x2C0F, 0x2C3F, 0x0000, 0x0000 },
- { 0x10427, 0x1044F, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_036[] = {
- { 0x0226, 0x0227, 0x0000, 0x0000 },
- { 0x0420, 0x0440, 0x0000, 0x0000 },
- { 0x1E3A, 0x1E3B, 0x0000, 0x0000 },
- { 0x1F3B, 0x1F33, 0x0000, 0x0000 },
- { 0x2C08, 0x2C38, 0x0000, 0x0000 },
- { 0x10420, 0x10448, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_037[] = {
- { 0x0124, 0x0125, 0x0000, 0x0000 },
- { 0x0421, 0x0441, 0x0000, 0x0000 },
- { 0x1F3A, 0x1F32, 0x0000, 0x0000 },
- { 0x2C09, 0x2C39, 0x0000, 0x0000 },
- { 0x10421, 0x10449, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_038[] = {
- { 0x0224, 0x0225, 0x0000, 0x0000 },
- { 0x0422, 0x0442, 0x0000, 0x0000 },
- { 0x1E38, 0x1E39, 0x0000, 0x0000 },
- { 0x1F39, 0x1F31, 0x0000, 0x0000 },
- { 0x2C0A, 0x2C3A, 0x0000, 0x0000 },
- { 0x10422, 0x1044A, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_039[] = {
- { 0x0126, 0x0127, 0x0000, 0x0000 },
- { 0x0423, 0x0443, 0x0000, 0x0000 },
- { 0x1F38, 0x1F30, 0x0000, 0x0000 },
- { 0x2C0B, 0x2C3B, 0x0000, 0x0000 },
- { 0x10423, 0x1044B, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_040[] = {
- { 0x022A, 0x022B, 0x0000, 0x0000 },
- { 0x042C, 0x044C, 0x0000, 0x0000 },
- { 0x1E36, 0x1E37, 0x0000, 0x0000 },
- { 0x2C04, 0x2C34, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_041[] = {
- { 0x0128, 0x0129, 0x0000, 0x0000 },
- { 0x042D, 0x044D, 0x0000, 0x0000 },
- { 0x2C05, 0x2C35, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_042[] = {
- { 0x0228, 0x0229, 0x0000, 0x0000 },
- { 0x042E, 0x044E, 0x0000, 0x0000 },
- { 0x1E34, 0x1E35, 0x0000, 0x0000 },
- { 0x2C06, 0x2C36, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_043[] = {
- { 0x012A, 0x012B, 0x0000, 0x0000 },
- { 0x042F, 0x044F, 0x0000, 0x0000 },
- { 0x2C07, 0x2C37, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_044[] = {
- { 0x022E, 0x022F, 0x0000, 0x0000 },
- { 0x0428, 0x0448, 0x0000, 0x0000 },
- { 0x1E32, 0x1E33, 0x0000, 0x0000 },
- { 0x2C00, 0x2C30, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_045[] = {
- { 0x012C, 0x012D, 0x0000, 0x0000 },
- { 0x0429, 0x0449, 0x0000, 0x0000 },
- { 0x2C01, 0x2C31, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_046[] = {
- { 0x022C, 0x022D, 0x0000, 0x0000 },
- { 0x042A, 0x044A, 0x0000, 0x0000 },
- { 0x1E30, 0x1E31, 0x0000, 0x0000 },
- { 0x2C02, 0x2C32, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_047[] = {
- { 0x012E, 0x012F, 0x0000, 0x0000 },
- { 0x042B, 0x044B, 0x0000, 0x0000 },
- { 0x2C03, 0x2C33, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_048[] = {
- { 0x0232, 0x0233, 0x0000, 0x0000 },
- { 0x0535, 0x0565, 0x0000, 0x0000 },
- { 0x1E2E, 0x1E2F, 0x0000, 0x0000 },
- { 0x1F2F, 0x1F27, 0x0000, 0x0000 },
- { 0x2C1C, 0x2C4C, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_049[] = {
- { 0x0130, 0x0069, 0x0307, 0x0000 },
- { 0x0534, 0x0564, 0x0000, 0x0000 },
- { 0x1F2E, 0x1F26, 0x0000, 0x0000 },
- { 0x2C1D, 0x2C4D, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_050[] = {
- { 0x0230, 0x0231, 0x0000, 0x0000 },
- { 0x0537, 0x0567, 0x0000, 0x0000 },
- { 0x1E2C, 0x1E2D, 0x0000, 0x0000 },
- { 0x1F2D, 0x1F25, 0x0000, 0x0000 },
- { 0x2C1E, 0x2C4E, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_051[] = {
- { 0x0132, 0x0133, 0x0000, 0x0000 },
- { 0x0536, 0x0566, 0x0000, 0x0000 },
- { 0x1F2C, 0x1F24, 0x0000, 0x0000 },
- { 0x2C1F, 0x2C4F, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_052[] = {
- { 0x0531, 0x0561, 0x0000, 0x0000 },
- { 0x1E2A, 0x1E2B, 0x0000, 0x0000 },
- { 0x1F2B, 0x1F23, 0x0000, 0x0000 },
- { 0x2C18, 0x2C48, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_053[] = {
- { 0x0134, 0x0135, 0x0000, 0x0000 },
- { 0x1F2A, 0x1F22, 0x0000, 0x0000 },
- { 0x2C19, 0x2C49, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_054[] = {
- { 0x0533, 0x0563, 0x0000, 0x0000 },
- { 0x1E28, 0x1E29, 0x0000, 0x0000 },
- { 0x1F29, 0x1F21, 0x0000, 0x0000 },
- { 0x2C1A, 0x2C4A, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_055[] = {
- { 0x0136, 0x0137, 0x0000, 0x0000 },
- { 0x0532, 0x0562, 0x0000, 0x0000 },
- { 0x1F28, 0x1F20, 0x0000, 0x0000 },
- { 0x2C1B, 0x2C4B, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_056[] = {
- { 0x0139, 0x013A, 0x0000, 0x0000 },
- { 0x053D, 0x056D, 0x0000, 0x0000 },
- { 0x1E26, 0x1E27, 0x0000, 0x0000 },
- { 0x2C14, 0x2C44, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_057[] = {
- { 0x023B, 0x023C, 0x0000, 0x0000 },
- { 0x053C, 0x056C, 0x0000, 0x0000 },
- { 0x2C15, 0x2C45, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_058[] = {
- { 0x013B, 0x013C, 0x0000, 0x0000 },
- { 0x053F, 0x056F, 0x0000, 0x0000 },
- { 0x1E24, 0x1E25, 0x0000, 0x0000 },
- { 0x2C16, 0x2C46, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_059[] = {
- { 0x053E, 0x056E, 0x0000, 0x0000 },
- { 0x2C17, 0x2C47, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_060[] = {
- { 0x013D, 0x013E, 0x0000, 0x0000 },
- { 0x0539, 0x0569, 0x0000, 0x0000 },
- { 0x1E22, 0x1E23, 0x0000, 0x0000 },
- { 0x2C10, 0x2C40, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_061[] = {
- { 0x0538, 0x0568, 0x0000, 0x0000 },
- { 0x2C11, 0x2C41, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_062[] = {
- { 0x013F, 0x0140, 0x0000, 0x0000 },
- { 0x053B, 0x056B, 0x0000, 0x0000 },
- { 0x1E20, 0x1E21, 0x0000, 0x0000 },
- { 0x2C12, 0x2C42, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_063[] = {
- { 0x023D, 0x019A, 0x0000, 0x0000 },
- { 0x053A, 0x056A, 0x0000, 0x0000 },
- { 0x2C13, 0x2C43, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_064[] = {
- { 0x0141, 0x0142, 0x0000, 0x0000 },
- { 0x0545, 0x0575, 0x0000, 0x0000 },
- { 0x1E5E, 0x1E5F, 0x0000, 0x0000 },
- { 0x1F5F, 0x1F57, 0x0000, 0x0000 },
- { 0x2161, 0x2171, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_065[] = {
- { 0x0041, 0x0061, 0x0000, 0x0000 },
- { 0x0544, 0x0574, 0x0000, 0x0000 },
- { 0x2160, 0x2170, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_066[] = {
- { 0x0042, 0x0062, 0x0000, 0x0000 },
- { 0x0143, 0x0144, 0x0000, 0x0000 },
- { 0x0547, 0x0577, 0x0000, 0x0000 },
- { 0x1E5C, 0x1E5D, 0x0000, 0x0000 },
- { 0x1F5D, 0x1F55, 0x0000, 0x0000 },
- { 0x2163, 0x2173, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_067[] = {
- { 0x0043, 0x0063, 0x0000, 0x0000 },
- { 0x0241, 0x0294, 0x0000, 0x0000 },
- { 0x0546, 0x0576, 0x0000, 0x0000 },
- { 0x2162, 0x2172, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_068[] = {
- { 0x0044, 0x0064, 0x0000, 0x0000 },
- { 0x0145, 0x0146, 0x0000, 0x0000 },
- { 0x0541, 0x0571, 0x0000, 0x0000 },
- { 0x1E5A, 0x1E5B, 0x0000, 0x0000 },
- { 0x1F5B, 0x1F53, 0x0000, 0x0000 },
- { 0x2165, 0x2175, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_069[] = {
- { 0x0045, 0x0065, 0x0000, 0x0000 },
- { 0x0540, 0x0570, 0x0000, 0x0000 },
- { 0x2164, 0x2174, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_070[] = {
- { 0x0046, 0x0066, 0x0000, 0x0000 },
- { 0x0147, 0x0148, 0x0000, 0x0000 },
- { 0x0345, 0x03B9, 0x0000, 0x0000 },
- { 0x0543, 0x0573, 0x0000, 0x0000 },
- { 0x1E58, 0x1E59, 0x0000, 0x0000 },
- { 0x1F59, 0x1F51, 0x0000, 0x0000 },
- { 0x2167, 0x2177, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_071[] = {
- { 0x0047, 0x0067, 0x0000, 0x0000 },
- { 0x0542, 0x0572, 0x0000, 0x0000 },
- { 0x2166, 0x2176, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_072[] = {
- { 0x0048, 0x0068, 0x0000, 0x0000 },
- { 0x0149, 0x02BC, 0x006E, 0x0000 },
- { 0x054D, 0x057D, 0x0000, 0x0000 },
- { 0x1E56, 0x1E57, 0x0000, 0x0000 },
- { 0x2169, 0x2179, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_073[] = {
- { 0x0049, 0x0069, 0x0000, 0x0000 },
- { 0x054C, 0x057C, 0x0000, 0x0000 },
- { 0x1F56, 0x03C5, 0x0313, 0x0342 },
- { 0x2168, 0x2178, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_074[] = {
- { 0x004A, 0x006A, 0x0000, 0x0000 },
- { 0x054F, 0x057F, 0x0000, 0x0000 },
- { 0x1E54, 0x1E55, 0x0000, 0x0000 },
- { 0x216B, 0x217B, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_075[] = {
- { 0x004B, 0x006B, 0x0000, 0x0000 },
- { 0x014A, 0x014B, 0x0000, 0x0000 },
- { 0x054E, 0x057E, 0x0000, 0x0000 },
- { 0x1F54, 0x03C5, 0x0313, 0x0301 },
- { 0x216A, 0x217A, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_076[] = {
- { 0x004C, 0x006C, 0x0000, 0x0000 },
- { 0x0549, 0x0579, 0x0000, 0x0000 },
- { 0x1E52, 0x1E53, 0x0000, 0x0000 },
- { 0x216D, 0x217D, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_077[] = {
- { 0x004D, 0x006D, 0x0000, 0x0000 },
- { 0x014C, 0x014D, 0x0000, 0x0000 },
- { 0x0548, 0x0578, 0x0000, 0x0000 },
- { 0x1F52, 0x03C5, 0x0313, 0x0300 },
- { 0x216C, 0x217C, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_078[] = {
- { 0x004E, 0x006E, 0x0000, 0x0000 },
- { 0x054B, 0x057B, 0x0000, 0x0000 },
- { 0x1E50, 0x1E51, 0x0000, 0x0000 },
- { 0x216F, 0x217F, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_079[] = {
- { 0x004F, 0x006F, 0x0000, 0x0000 },
- { 0x014E, 0x014F, 0x0000, 0x0000 },
- { 0x054A, 0x057A, 0x0000, 0x0000 },
- { 0x1F50, 0x03C5, 0x0313, 0x0000 },
- { 0x216E, 0x217E, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_080[] = {
- { 0x0050, 0x0070, 0x0000, 0x0000 },
- { 0x0555, 0x0585, 0x0000, 0x0000 },
- { 0x1E4E, 0x1E4F, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_081[] = {
- { 0x0051, 0x0071, 0x0000, 0x0000 },
- { 0x0150, 0x0151, 0x0000, 0x0000 },
- { 0x0554, 0x0584, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_082[] = {
- { 0x0052, 0x0072, 0x0000, 0x0000 },
- { 0x1E4C, 0x1E4D, 0x0000, 0x0000 },
- { 0x1F4D, 0x1F45, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_083[] = {
- { 0x0053, 0x0073, 0x0000, 0x0000 },
- { 0x0152, 0x0153, 0x0000, 0x0000 },
- { 0x0556, 0x0586, 0x0000, 0x0000 },
- { 0x1F4C, 0x1F44, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_084[] = {
- { 0x0054, 0x0074, 0x0000, 0x0000 },
- { 0x0551, 0x0581, 0x0000, 0x0000 },
- { 0x1E4A, 0x1E4B, 0x0000, 0x0000 },
- { 0x1F4B, 0x1F43, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_085[] = {
- { 0x0055, 0x0075, 0x0000, 0x0000 },
- { 0x0154, 0x0155, 0x0000, 0x0000 },
- { 0x0550, 0x0580, 0x0000, 0x0000 },
- { 0x1F4A, 0x1F42, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_086[] = {
- { 0x0056, 0x0076, 0x0000, 0x0000 },
- { 0x0553, 0x0583, 0x0000, 0x0000 },
- { 0x1E48, 0x1E49, 0x0000, 0x0000 },
- { 0x1F49, 0x1F41, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_087[] = {
- { 0x0057, 0x0077, 0x0000, 0x0000 },
- { 0x0156, 0x0157, 0x0000, 0x0000 },
- { 0x0552, 0x0582, 0x0000, 0x0000 },
- { 0x1F48, 0x1F40, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_088[] = {
- { 0x0058, 0x0078, 0x0000, 0x0000 },
- { 0x1E46, 0x1E47, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_089[] = {
- { 0x0059, 0x0079, 0x0000, 0x0000 },
- { 0x0158, 0x0159, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_090[] = {
- { 0x005A, 0x007A, 0x0000, 0x0000 },
- { 0x1E44, 0x1E45, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_091[] = {
- { 0x015A, 0x015B, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_092[] = {
- { 0x1E42, 0x1E43, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_093[] = {
- { 0x015C, 0x015D, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_094[] = {
- { 0x1E40, 0x1E41, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_095[] = {
- { 0x015E, 0x015F, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_096[] = {
- { 0x0464, 0x0465, 0x0000, 0x0000 },
- { 0x1E7E, 0x1E7F, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_097[] = {
- { 0x0160, 0x0161, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_098[] = {
- { 0x0466, 0x0467, 0x0000, 0x0000 },
- { 0x1E7C, 0x1E7D, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_099[] = {
- { 0x0162, 0x0163, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_100[] = {
- { 0x0460, 0x0461, 0x0000, 0x0000 },
- { 0x1E7A, 0x1E7B, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_101[] = {
- { 0x0164, 0x0165, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_102[] = {
- { 0x0462, 0x0463, 0x0000, 0x0000 },
- { 0x1E78, 0x1E79, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_103[] = {
- { 0x0166, 0x0167, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_104[] = {
- { 0x046C, 0x046D, 0x0000, 0x0000 },
- { 0x1E76, 0x1E77, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_105[] = {
- { 0x0168, 0x0169, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_106[] = {
- { 0x046E, 0x046F, 0x0000, 0x0000 },
- { 0x1E74, 0x1E75, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_107[] = {
- { 0x016A, 0x016B, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_108[] = {
- { 0x0468, 0x0469, 0x0000, 0x0000 },
- { 0x1E72, 0x1E73, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_109[] = {
- { 0x016C, 0x016D, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_110[] = {
- { 0x046A, 0x046B, 0x0000, 0x0000 },
- { 0x1E70, 0x1E71, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_111[] = {
- { 0x016E, 0x016F, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_112[] = {
- { 0x0474, 0x0475, 0x0000, 0x0000 },
- { 0x1E6E, 0x1E6F, 0x0000, 0x0000 },
- { 0x1F6F, 0x1F67, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_113[] = {
- { 0x0170, 0x0171, 0x0000, 0x0000 },
- { 0x1F6E, 0x1F66, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_114[] = {
- { 0x0476, 0x0477, 0x0000, 0x0000 },
- { 0x1E6C, 0x1E6D, 0x0000, 0x0000 },
- { 0x1F6D, 0x1F65, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_115[] = {
- { 0x0172, 0x0173, 0x0000, 0x0000 },
- { 0x1F6C, 0x1F64, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_116[] = {
- { 0x0470, 0x0471, 0x0000, 0x0000 },
- { 0x1E6A, 0x1E6B, 0x0000, 0x0000 },
- { 0x1F6B, 0x1F63, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_117[] = {
- { 0x0174, 0x0175, 0x0000, 0x0000 },
- { 0x1F6A, 0x1F62, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_118[] = {
- { 0x0472, 0x0473, 0x0000, 0x0000 },
- { 0x1E68, 0x1E69, 0x0000, 0x0000 },
- { 0x1F69, 0x1F61, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_119[] = {
- { 0x0176, 0x0177, 0x0000, 0x0000 },
- { 0x1F68, 0x1F60, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_120[] = {
- { 0x0179, 0x017A, 0x0000, 0x0000 },
- { 0x047C, 0x047D, 0x0000, 0x0000 },
- { 0x1E66, 0x1E67, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_121[] = {
- { 0x0178, 0x00FF, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_122[] = {
- { 0x017B, 0x017C, 0x0000, 0x0000 },
- { 0x047E, 0x047F, 0x0000, 0x0000 },
- { 0x1E64, 0x1E65, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_124[] = {
- { 0x017D, 0x017E, 0x0000, 0x0000 },
- { 0x0478, 0x0479, 0x0000, 0x0000 },
- { 0x1E62, 0x1E63, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_126[] = {
- { 0x017F, 0x0073, 0x0000, 0x0000 },
- { 0x047A, 0x047B, 0x0000, 0x0000 },
- { 0x1E60, 0x1E61, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_128[] = {
- { 0x0181, 0x0253, 0x0000, 0x0000 },
- { 0x1F9F, 0x1F27, 0x03B9, 0x0000 },
- { 0x2CAC, 0x2CAD, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_129[] = {
- { 0x1F9E, 0x1F26, 0x03B9, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_130[] = {
- { 0x0587, 0x0565, 0x0582, 0x0000 },
- { 0x1F9D, 0x1F25, 0x03B9, 0x0000 },
- { 0x2CAE, 0x2CAF, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_131[] = {
- { 0x0182, 0x0183, 0x0000, 0x0000 },
- { 0x1F9C, 0x1F24, 0x03B9, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_132[] = {
- { 0x0480, 0x0481, 0x0000, 0x0000 },
- { 0x1E9A, 0x0061, 0x02BE, 0x0000 },
- { 0x1F9B, 0x1F23, 0x03B9, 0x0000 },
- { 0x2CA8, 0x2CA9, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_133[] = {
- { 0x0184, 0x0185, 0x0000, 0x0000 },
- { 0x0386, 0x03AC, 0x0000, 0x0000 },
- { 0x1E9B, 0x1E61, 0x0000, 0x0000 },
- { 0x1F9A, 0x1F22, 0x03B9, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_134[] = {
- { 0x0187, 0x0188, 0x0000, 0x0000 },
- { 0x1E98, 0x0077, 0x030A, 0x0000 },
- { 0x1F99, 0x1F21, 0x03B9, 0x0000 },
- { 0x2CAA, 0x2CAB, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_135[] = {
- { 0x0186, 0x0254, 0x0000, 0x0000 },
- { 0x1E99, 0x0079, 0x030A, 0x0000 },
- { 0x1F98, 0x1F20, 0x03B9, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_136[] = {
- { 0x0189, 0x0256, 0x0000, 0x0000 },
- { 0x048C, 0x048D, 0x0000, 0x0000 },
- { 0x1E96, 0x0068, 0x0331, 0x0000 },
- { 0x1F97, 0x1F27, 0x03B9, 0x0000 },
- { 0x2CA4, 0x2CA5, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_137[] = {
- { 0x038A, 0x03AF, 0x0000, 0x0000 },
- { 0x1E97, 0x0074, 0x0308, 0x0000 },
- { 0x1F96, 0x1F26, 0x03B9, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_138[] = {
- { 0x018B, 0x018C, 0x0000, 0x0000 },
- { 0x0389, 0x03AE, 0x0000, 0x0000 },
- { 0x048E, 0x048F, 0x0000, 0x0000 },
- { 0x1E94, 0x1E95, 0x0000, 0x0000 },
- { 0x1F95, 0x1F25, 0x03B9, 0x0000 },
- { 0x2CA6, 0x2CA7, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_139[] = {
- { 0x018A, 0x0257, 0x0000, 0x0000 },
- { 0x0388, 0x03AD, 0x0000, 0x0000 },
- { 0x1F94, 0x1F24, 0x03B9, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_140[] = {
- { 0x038F, 0x03CE, 0x0000, 0x0000 },
- { 0x1E92, 0x1E93, 0x0000, 0x0000 },
- { 0x1F93, 0x1F23, 0x03B9, 0x0000 },
- { 0x2CA0, 0x2CA1, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_141[] = {
- { 0x038E, 0x03CD, 0x0000, 0x0000 },
- { 0x1F92, 0x1F22, 0x03B9, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_142[] = {
- { 0x018F, 0x0259, 0x0000, 0x0000 },
- { 0x048A, 0x048B, 0x0000, 0x0000 },
- { 0x1E90, 0x1E91, 0x0000, 0x0000 },
- { 0x1F91, 0x1F21, 0x03B9, 0x0000 },
- { 0x2CA2, 0x2CA3, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_143[] = {
- { 0x018E, 0x01DD, 0x0000, 0x0000 },
- { 0x038C, 0x03CC, 0x0000, 0x0000 },
- { 0x1F90, 0x1F20, 0x03B9, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_144[] = {
- { 0x0191, 0x0192, 0x0000, 0x0000 },
- { 0x0393, 0x03B3, 0x0000, 0x0000 },
- { 0x0494, 0x0495, 0x0000, 0x0000 },
- { 0x1E8E, 0x1E8F, 0x0000, 0x0000 },
- { 0x1F8F, 0x1F07, 0x03B9, 0x0000 },
- { 0x2CBC, 0x2CBD, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_145[] = {
- { 0x0190, 0x025B, 0x0000, 0x0000 },
- { 0x0392, 0x03B2, 0x0000, 0x0000 },
- { 0x1F8E, 0x1F06, 0x03B9, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_146[] = {
- { 0x0193, 0x0260, 0x0000, 0x0000 },
- { 0x0391, 0x03B1, 0x0000, 0x0000 },
- { 0x0496, 0x0497, 0x0000, 0x0000 },
- { 0x1E8C, 0x1E8D, 0x0000, 0x0000 },
- { 0x1F8D, 0x1F05, 0x03B9, 0x0000 },
- { 0x24B6, 0x24D0, 0x0000, 0x0000 },
- { 0x2CBE, 0x2CBF, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_147[] = {
- { 0x0390, 0x03B9, 0x0308, 0x0301 },
- { 0x1F8C, 0x1F04, 0x03B9, 0x0000 },
- { 0x24B7, 0x24D1, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_148[] = {
- { 0x0397, 0x03B7, 0x0000, 0x0000 },
- { 0x0490, 0x0491, 0x0000, 0x0000 },
- { 0x1E8A, 0x1E8B, 0x0000, 0x0000 },
- { 0x1F8B, 0x1F03, 0x03B9, 0x0000 },
- { 0x2CB8, 0x2CB9, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_149[] = {
- { 0x0194, 0x0263, 0x0000, 0x0000 },
- { 0x0396, 0x03B6, 0x0000, 0x0000 },
- { 0x1F8A, 0x1F02, 0x03B9, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_150[] = {
- { 0x0197, 0x0268, 0x0000, 0x0000 },
- { 0x0395, 0x03B5, 0x0000, 0x0000 },
- { 0x0492, 0x0493, 0x0000, 0x0000 },
- { 0x1E88, 0x1E89, 0x0000, 0x0000 },
- { 0x1F89, 0x1F01, 0x03B9, 0x0000 },
- { 0x2CBA, 0x2CBB, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_151[] = {
- { 0x0196, 0x0269, 0x0000, 0x0000 },
- { 0x0394, 0x03B4, 0x0000, 0x0000 },
- { 0x1F88, 0x1F00, 0x03B9, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_152[] = {
- { 0x039B, 0x03BB, 0x0000, 0x0000 },
- { 0x049C, 0x049D, 0x0000, 0x0000 },
- { 0x1E86, 0x1E87, 0x0000, 0x0000 },
- { 0x1F87, 0x1F07, 0x03B9, 0x0000 },
- { 0x24BC, 0x24D6, 0x0000, 0x0000 },
- { 0x2CB4, 0x2CB5, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_153[] = {
- { 0x0198, 0x0199, 0x0000, 0x0000 },
- { 0x039A, 0x03BA, 0x0000, 0x0000 },
- { 0x1F86, 0x1F06, 0x03B9, 0x0000 },
- { 0x24BD, 0x24D7, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_154[] = {
- { 0x0399, 0x03B9, 0x0000, 0x0000 },
- { 0x049E, 0x049F, 0x0000, 0x0000 },
- { 0x1E84, 0x1E85, 0x0000, 0x0000 },
- { 0x1F85, 0x1F05, 0x03B9, 0x0000 },
- { 0x24BE, 0x24D8, 0x0000, 0x0000 },
- { 0x2CB6, 0x2CB7, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_155[] = {
- { 0x0398, 0x03B8, 0x0000, 0x0000 },
- { 0x1F84, 0x1F04, 0x03B9, 0x0000 },
- { 0x24BF, 0x24D9, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_156[] = {
- { 0x019D, 0x0272, 0x0000, 0x0000 },
- { 0x039F, 0x03BF, 0x0000, 0x0000 },
- { 0x0498, 0x0499, 0x0000, 0x0000 },
- { 0x1E82, 0x1E83, 0x0000, 0x0000 },
- { 0x1F83, 0x1F03, 0x03B9, 0x0000 },
- { 0x24B8, 0x24D2, 0x0000, 0x0000 },
- { 0x2CB0, 0x2CB1, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_157[] = {
- { 0x019C, 0x026F, 0x0000, 0x0000 },
- { 0x039E, 0x03BE, 0x0000, 0x0000 },
- { 0x1F82, 0x1F02, 0x03B9, 0x0000 },
- { 0x24B9, 0x24D3, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_158[] = {
- { 0x019F, 0x0275, 0x0000, 0x0000 },
- { 0x039D, 0x03BD, 0x0000, 0x0000 },
- { 0x049A, 0x049B, 0x0000, 0x0000 },
- { 0x1E80, 0x1E81, 0x0000, 0x0000 },
- { 0x1F81, 0x1F01, 0x03B9, 0x0000 },
- { 0x24BA, 0x24D4, 0x0000, 0x0000 },
- { 0x2CB2, 0x2CB3, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_159[] = {
- { 0x039C, 0x03BC, 0x0000, 0x0000 },
- { 0x1F80, 0x1F00, 0x03B9, 0x0000 },
- { 0x24BB, 0x24D5, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_160[] = {
- { 0x03A3, 0x03C3, 0x0000, 0x0000 },
- { 0x04A4, 0x04A5, 0x0000, 0x0000 },
- { 0x10B0, 0x2D10, 0x0000, 0x0000 },
- { 0x1EBE, 0x1EBF, 0x0000, 0x0000 },
- { 0x2C8C, 0x2C8D, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_161[] = {
- { 0x01A0, 0x01A1, 0x0000, 0x0000 },
- { 0x10B1, 0x2D11, 0x0000, 0x0000 },
- { 0x1FBE, 0x03B9, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_162[] = {
- { 0x03A1, 0x03C1, 0x0000, 0x0000 },
- { 0x04A6, 0x04A7, 0x0000, 0x0000 },
- { 0x10B2, 0x2D12, 0x0000, 0x0000 },
- { 0x1EBC, 0x1EBD, 0x0000, 0x0000 },
- { 0x2C8E, 0x2C8F, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_163[] = {
- { 0x01A2, 0x01A3, 0x0000, 0x0000 },
- { 0x03A0, 0x03C0, 0x0000, 0x0000 },
- { 0x10B3, 0x2D13, 0x0000, 0x0000 },
- { 0x1FBC, 0x03B1, 0x03B9, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_164[] = {
- { 0x03A7, 0x03C7, 0x0000, 0x0000 },
- { 0x04A0, 0x04A1, 0x0000, 0x0000 },
- { 0x10B4, 0x2D14, 0x0000, 0x0000 },
- { 0x1EBA, 0x1EBB, 0x0000, 0x0000 },
- { 0x1FBB, 0x1F71, 0x0000, 0x0000 },
- { 0x2C88, 0x2C89, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_165[] = {
- { 0x01A4, 0x01A5, 0x0000, 0x0000 },
- { 0x03A6, 0x03C6, 0x0000, 0x0000 },
- { 0x10B5, 0x2D15, 0x0000, 0x0000 },
- { 0x1FBA, 0x1F70, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_166[] = {
- { 0x01A7, 0x01A8, 0x0000, 0x0000 },
- { 0x03A5, 0x03C5, 0x0000, 0x0000 },
- { 0x04A2, 0x04A3, 0x0000, 0x0000 },
- { 0x10B6, 0x2D16, 0x0000, 0x0000 },
- { 0x1EB8, 0x1EB9, 0x0000, 0x0000 },
- { 0x1FB9, 0x1FB1, 0x0000, 0x0000 },
- { 0x2C8A, 0x2C8B, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_167[] = {
- { 0x01A6, 0x0280, 0x0000, 0x0000 },
- { 0x03A4, 0x03C4, 0x0000, 0x0000 },
- { 0x10B7, 0x2D17, 0x0000, 0x0000 },
- { 0x1FB8, 0x1FB0, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_168[] = {
- { 0x01A9, 0x0283, 0x0000, 0x0000 },
- { 0x03AB, 0x03CB, 0x0000, 0x0000 },
- { 0x04AC, 0x04AD, 0x0000, 0x0000 },
- { 0x10B8, 0x2D18, 0x0000, 0x0000 },
- { 0x1EB6, 0x1EB7, 0x0000, 0x0000 },
- { 0x1FB7, 0x03B1, 0x0342, 0x03B9 },
- { 0x2C84, 0x2C85, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_169[] = {
- { 0x03AA, 0x03CA, 0x0000, 0x0000 },
- { 0x10B9, 0x2D19, 0x0000, 0x0000 },
- { 0x1FB6, 0x03B1, 0x0342, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_170[] = {
- { 0x03A9, 0x03C9, 0x0000, 0x0000 },
- { 0x04AE, 0x04AF, 0x0000, 0x0000 },
- { 0x10BA, 0x2D1A, 0x0000, 0x0000 },
- { 0x1EB4, 0x1EB5, 0x0000, 0x0000 },
- { 0x2C86, 0x2C87, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_171[] = {
- { 0x03A8, 0x03C8, 0x0000, 0x0000 },
- { 0x10BB, 0x2D1B, 0x0000, 0x0000 },
- { 0x1FB4, 0x03AC, 0x03B9, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_172[] = {
- { 0x04A8, 0x04A9, 0x0000, 0x0000 },
- { 0x10BC, 0x2D1C, 0x0000, 0x0000 },
- { 0x1EB2, 0x1EB3, 0x0000, 0x0000 },
- { 0x1FB3, 0x03B1, 0x03B9, 0x0000 },
- { 0x2C80, 0x2C81, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_173[] = {
- { 0x01AC, 0x01AD, 0x0000, 0x0000 },
- { 0x10BD, 0x2D1D, 0x0000, 0x0000 },
- { 0x1FB2, 0x1F70, 0x03B9, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_174[] = {
- { 0x01AF, 0x01B0, 0x0000, 0x0000 },
- { 0x04AA, 0x04AB, 0x0000, 0x0000 },
- { 0x10BE, 0x2D1E, 0x0000, 0x0000 },
- { 0x1EB0, 0x1EB1, 0x0000, 0x0000 },
- { 0x2C82, 0x2C83, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_175[] = {
- { 0x01AE, 0x0288, 0x0000, 0x0000 },
- { 0x10BF, 0x2D1F, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_176[] = {
- { 0x01B1, 0x028A, 0x0000, 0x0000 },
- { 0x04B4, 0x04B5, 0x0000, 0x0000 },
- { 0x10A0, 0x2D00, 0x0000, 0x0000 },
- { 0x1EAE, 0x1EAF, 0x0000, 0x0000 },
- { 0x1FAF, 0x1F67, 0x03B9, 0x0000 },
- { 0x2C9C, 0x2C9D, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_177[] = {
- { 0x10A1, 0x2D01, 0x0000, 0x0000 },
- { 0x1FAE, 0x1F66, 0x03B9, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_178[] = {
- { 0x01B3, 0x01B4, 0x0000, 0x0000 },
- { 0x04B6, 0x04B7, 0x0000, 0x0000 },
- { 0x10A2, 0x2D02, 0x0000, 0x0000 },
- { 0x1EAC, 0x1EAD, 0x0000, 0x0000 },
- { 0x1FAD, 0x1F65, 0x03B9, 0x0000 },
- { 0x2C9E, 0x2C9F, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_179[] = {
- { 0x01B2, 0x028B, 0x0000, 0x0000 },
- { 0x03B0, 0x03C5, 0x0308, 0x0301 },
- { 0x10A3, 0x2D03, 0x0000, 0x0000 },
- { 0x1FAC, 0x1F64, 0x03B9, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_180[] = {
- { 0x01B5, 0x01B6, 0x0000, 0x0000 },
- { 0x04B0, 0x04B1, 0x0000, 0x0000 },
- { 0x10A4, 0x2D04, 0x0000, 0x0000 },
- { 0x1EAA, 0x1EAB, 0x0000, 0x0000 },
- { 0x1FAB, 0x1F63, 0x03B9, 0x0000 },
- { 0x2C98, 0x2C99, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_181[] = {
- { 0x00B5, 0x03BC, 0x0000, 0x0000 },
- { 0x10A5, 0x2D05, 0x0000, 0x0000 },
- { 0x1FAA, 0x1F62, 0x03B9, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_182[] = {
- { 0x01B7, 0x0292, 0x0000, 0x0000 },
- { 0x04B2, 0x04B3, 0x0000, 0x0000 },
- { 0x10A6, 0x2D06, 0x0000, 0x0000 },
- { 0x1EA8, 0x1EA9, 0x0000, 0x0000 },
- { 0x1FA9, 0x1F61, 0x03B9, 0x0000 },
- { 0x2C9A, 0x2C9B, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_183[] = {
- { 0x10A7, 0x2D07, 0x0000, 0x0000 },
- { 0x1FA8, 0x1F60, 0x03B9, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_184[] = {
- { 0x04BC, 0x04BD, 0x0000, 0x0000 },
- { 0x10A8, 0x2D08, 0x0000, 0x0000 },
- { 0x1EA6, 0x1EA7, 0x0000, 0x0000 },
- { 0x1FA7, 0x1F67, 0x03B9, 0x0000 },
- { 0x2C94, 0x2C95, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_185[] = {
- { 0x01B8, 0x01B9, 0x0000, 0x0000 },
- { 0x10A9, 0x2D09, 0x0000, 0x0000 },
- { 0x1FA6, 0x1F66, 0x03B9, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_186[] = {
- { 0x04BE, 0x04BF, 0x0000, 0x0000 },
- { 0x10AA, 0x2D0A, 0x0000, 0x0000 },
- { 0x1EA4, 0x1EA5, 0x0000, 0x0000 },
- { 0x1FA5, 0x1F65, 0x03B9, 0x0000 },
- { 0x2C96, 0x2C97, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_187[] = {
- { 0x10AB, 0x2D0B, 0x0000, 0x0000 },
- { 0x1FA4, 0x1F64, 0x03B9, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_188[] = {
- { 0x04B8, 0x04B9, 0x0000, 0x0000 },
- { 0x10AC, 0x2D0C, 0x0000, 0x0000 },
- { 0x1EA2, 0x1EA3, 0x0000, 0x0000 },
- { 0x1FA3, 0x1F63, 0x03B9, 0x0000 },
- { 0x2C90, 0x2C91, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_189[] = {
- { 0x01BC, 0x01BD, 0x0000, 0x0000 },
- { 0x10AD, 0x2D0D, 0x0000, 0x0000 },
- { 0x1FA2, 0x1F62, 0x03B9, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_190[] = {
- { 0x04BA, 0x04BB, 0x0000, 0x0000 },
- { 0x10AE, 0x2D0E, 0x0000, 0x0000 },
- { 0x1EA0, 0x1EA1, 0x0000, 0x0000 },
- { 0x1FA1, 0x1F61, 0x03B9, 0x0000 },
- { 0x2C92, 0x2C93, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_191[] = {
- { 0x10AF, 0x2D0F, 0x0000, 0x0000 },
- { 0x1FA0, 0x1F60, 0x03B9, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_192[] = {
- { 0x00C0, 0x00E0, 0x0000, 0x0000 },
- { 0x1EDE, 0x1EDF, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_193[] = {
- { 0x00C1, 0x00E1, 0x0000, 0x0000 },
- { 0x03C2, 0x03C3, 0x0000, 0x0000 },
- { 0x04C5, 0x04C6, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_194[] = {
- { 0x00C2, 0x00E2, 0x0000, 0x0000 },
- { 0x1EDC, 0x1EDD, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_195[] = {
- { 0x00C3, 0x00E3, 0x0000, 0x0000 },
- { 0x04C7, 0x04C8, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_196[] = {
- { 0x00C4, 0x00E4, 0x0000, 0x0000 },
- { 0x01C5, 0x01C6, 0x0000, 0x0000 },
- { 0x1EDA, 0x1EDB, 0x0000, 0x0000 },
- { 0x1FDB, 0x1F77, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_197[] = {
- { 0x00C5, 0x00E5, 0x0000, 0x0000 },
- { 0x01C4, 0x01C6, 0x0000, 0x0000 },
- { 0x04C1, 0x04C2, 0x0000, 0x0000 },
- { 0x1FDA, 0x1F76, 0x0000, 0x0000 },
- { 0xFF3A, 0xFF5A, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_198[] = {
- { 0x00C6, 0x00E6, 0x0000, 0x0000 },
- { 0x01C7, 0x01C9, 0x0000, 0x0000 },
- { 0x1ED8, 0x1ED9, 0x0000, 0x0000 },
- { 0x1FD9, 0x1FD1, 0x0000, 0x0000 },
- { 0xFF39, 0xFF59, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_199[] = {
- { 0x00C7, 0x00E7, 0x0000, 0x0000 },
- { 0x04C3, 0x04C4, 0x0000, 0x0000 },
- { 0x1FD8, 0x1FD0, 0x0000, 0x0000 },
- { 0xFF38, 0xFF58, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_200[] = {
- { 0x00C8, 0x00E8, 0x0000, 0x0000 },
- { 0x1ED6, 0x1ED7, 0x0000, 0x0000 },
- { 0x1FD7, 0x03B9, 0x0308, 0x0342 },
- { 0xFF37, 0xFF57, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_201[] = {
- { 0x00C9, 0x00E9, 0x0000, 0x0000 },
- { 0x01C8, 0x01C9, 0x0000, 0x0000 },
- { 0x04CD, 0x04CE, 0x0000, 0x0000 },
- { 0x1FD6, 0x03B9, 0x0342, 0x0000 },
- { 0xFF36, 0xFF56, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_202[] = {
- { 0x00CA, 0x00EA, 0x0000, 0x0000 },
- { 0x01CB, 0x01CC, 0x0000, 0x0000 },
- { 0x1ED4, 0x1ED5, 0x0000, 0x0000 },
- { 0xFF35, 0xFF55, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_203[] = {
- { 0x00CB, 0x00EB, 0x0000, 0x0000 },
- { 0x01CA, 0x01CC, 0x0000, 0x0000 },
- { 0xFF34, 0xFF54, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_204[] = {
- { 0x00CC, 0x00EC, 0x0000, 0x0000 },
- { 0x01CD, 0x01CE, 0x0000, 0x0000 },
- { 0x1ED2, 0x1ED3, 0x0000, 0x0000 },
- { 0x1FD3, 0x03B9, 0x0308, 0x0301 },
- { 0x2CE0, 0x2CE1, 0x0000, 0x0000 },
- { 0xFF33, 0xFF53, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_205[] = {
- { 0x00CD, 0x00ED, 0x0000, 0x0000 },
- { 0x04C9, 0x04CA, 0x0000, 0x0000 },
- { 0x1FD2, 0x03B9, 0x0308, 0x0300 },
- { 0xFF32, 0xFF52, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_206[] = {
- { 0x00CE, 0x00EE, 0x0000, 0x0000 },
- { 0x01CF, 0x01D0, 0x0000, 0x0000 },
- { 0x1ED0, 0x1ED1, 0x0000, 0x0000 },
- { 0x2CE2, 0x2CE3, 0x0000, 0x0000 },
- { 0xFF31, 0xFF51, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_207[] = {
- { 0x00CF, 0x00EF, 0x0000, 0x0000 },
- { 0x04CB, 0x04CC, 0x0000, 0x0000 },
- { 0xFF30, 0xFF50, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_208[] = {
- { 0x00D0, 0x00F0, 0x0000, 0x0000 },
- { 0x01D1, 0x01D2, 0x0000, 0x0000 },
- { 0x04D4, 0x04D5, 0x0000, 0x0000 },
- { 0x10C0, 0x2D20, 0x0000, 0x0000 },
- { 0x1ECE, 0x1ECF, 0x0000, 0x0000 },
- { 0xFF2F, 0xFF4F, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_209[] = {
- { 0x00D1, 0x00F1, 0x0000, 0x0000 },
- { 0x10C1, 0x2D21, 0x0000, 0x0000 },
- { 0xFF2E, 0xFF4E, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_210[] = {
- { 0x00D2, 0x00F2, 0x0000, 0x0000 },
- { 0x01D3, 0x01D4, 0x0000, 0x0000 },
- { 0x03D1, 0x03B8, 0x0000, 0x0000 },
- { 0x04D6, 0x04D7, 0x0000, 0x0000 },
- { 0x10C2, 0x2D22, 0x0000, 0x0000 },
- { 0x1ECC, 0x1ECD, 0x0000, 0x0000 },
- { 0xFF2D, 0xFF4D, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_211[] = {
- { 0x00D3, 0x00F3, 0x0000, 0x0000 },
- { 0x03D0, 0x03B2, 0x0000, 0x0000 },
- { 0x10C3, 0x2D23, 0x0000, 0x0000 },
- { 0x1FCC, 0x03B7, 0x03B9, 0x0000 },
- { 0xFF2C, 0xFF4C, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_212[] = {
- { 0x00D4, 0x00F4, 0x0000, 0x0000 },
- { 0x01D5, 0x01D6, 0x0000, 0x0000 },
- { 0x04D0, 0x04D1, 0x0000, 0x0000 },
- { 0x10C4, 0x2D24, 0x0000, 0x0000 },
- { 0x1ECA, 0x1ECB, 0x0000, 0x0000 },
- { 0x1FCB, 0x1F75, 0x0000, 0x0000 },
- { 0xFF2B, 0xFF4B, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_213[] = {
- { 0x00D5, 0x00F5, 0x0000, 0x0000 },
- { 0x03D6, 0x03C0, 0x0000, 0x0000 },
- { 0x10C5, 0x2D25, 0x0000, 0x0000 },
- { 0x1FCA, 0x1F74, 0x0000, 0x0000 },
- { 0xFF2A, 0xFF4A, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_214[] = {
- { 0x00D6, 0x00F6, 0x0000, 0x0000 },
- { 0x01D7, 0x01D8, 0x0000, 0x0000 },
- { 0x03D5, 0x03C6, 0x0000, 0x0000 },
- { 0x04D2, 0x04D3, 0x0000, 0x0000 },
- { 0x1EC8, 0x1EC9, 0x0000, 0x0000 },
- { 0x1FC9, 0x1F73, 0x0000, 0x0000 },
- { 0xFF29, 0xFF49, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_215[] = {
- { 0x1FC8, 0x1F72, 0x0000, 0x0000 },
- { 0xFF28, 0xFF48, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_216[] = {
- { 0x00D8, 0x00F8, 0x0000, 0x0000 },
- { 0x01D9, 0x01DA, 0x0000, 0x0000 },
- { 0x04DC, 0x04DD, 0x0000, 0x0000 },
- { 0x1EC6, 0x1EC7, 0x0000, 0x0000 },
- { 0x1FC7, 0x03B7, 0x0342, 0x03B9 },
- { 0xFF27, 0xFF47, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_217[] = {
- { 0x00D9, 0x00F9, 0x0000, 0x0000 },
- { 0x03DA, 0x03DB, 0x0000, 0x0000 },
- { 0x1FC6, 0x03B7, 0x0342, 0x0000 },
- { 0xFF26, 0xFF46, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_218[] = {
- { 0x00DA, 0x00FA, 0x0000, 0x0000 },
- { 0x01DB, 0x01DC, 0x0000, 0x0000 },
- { 0x04DE, 0x04DF, 0x0000, 0x0000 },
- { 0x1EC4, 0x1EC5, 0x0000, 0x0000 },
- { 0xFF25, 0xFF45, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_219[] = {
- { 0x00DB, 0x00FB, 0x0000, 0x0000 },
- { 0x03D8, 0x03D9, 0x0000, 0x0000 },
- { 0x1FC4, 0x03AE, 0x03B9, 0x0000 },
- { 0xFF24, 0xFF44, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_220[] = {
- { 0x00DC, 0x00FC, 0x0000, 0x0000 },
- { 0x04D8, 0x04D9, 0x0000, 0x0000 },
- { 0x1EC2, 0x1EC3, 0x0000, 0x0000 },
- { 0x1FC3, 0x03B7, 0x03B9, 0x0000 },
- { 0xFF23, 0xFF43, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_221[] = {
- { 0x00DD, 0x00FD, 0x0000, 0x0000 },
- { 0x03DE, 0x03DF, 0x0000, 0x0000 },
- { 0x1FC2, 0x1F74, 0x03B9, 0x0000 },
- { 0xFF22, 0xFF42, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_222[] = {
- { 0x00DE, 0x00FE, 0x0000, 0x0000 },
- { 0x04DA, 0x04DB, 0x0000, 0x0000 },
- { 0x1EC0, 0x1EC1, 0x0000, 0x0000 },
- { 0xFF21, 0xFF41, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_223[] = {
- { 0x00DF, 0x0073, 0x0073, 0x0000 },
- { 0x01DE, 0x01DF, 0x0000, 0x0000 },
- { 0x03DC, 0x03DD, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_224[] = {
- { 0x04E4, 0x04E5, 0x0000, 0x0000 },
- { 0x24C4, 0x24DE, 0x0000, 0x0000 },
- { 0x2CCC, 0x2CCD, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_225[] = {
- { 0x01E0, 0x01E1, 0x0000, 0x0000 },
- { 0x03E2, 0x03E3, 0x0000, 0x0000 },
- { 0x24C5, 0x24DF, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_226[] = {
- { 0x04E6, 0x04E7, 0x0000, 0x0000 },
- { 0x24C6, 0x24E0, 0x0000, 0x0000 },
- { 0x2CCE, 0x2CCF, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_227[] = {
- { 0x01E2, 0x01E3, 0x0000, 0x0000 },
- { 0x03E0, 0x03E1, 0x0000, 0x0000 },
- { 0x1FFC, 0x03C9, 0x03B9, 0x0000 },
- { 0x24C7, 0x24E1, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_228[] = {
- { 0x04E0, 0x04E1, 0x0000, 0x0000 },
- { 0x1FFB, 0x1F7D, 0x0000, 0x0000 },
- { 0x24C0, 0x24DA, 0x0000, 0x0000 },
- { 0x2CC8, 0x2CC9, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_229[] = {
- { 0x01E4, 0x01E5, 0x0000, 0x0000 },
- { 0x03E6, 0x03E7, 0x0000, 0x0000 },
- { 0x1FFA, 0x1F7C, 0x0000, 0x0000 },
- { 0x24C1, 0x24DB, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_230[] = {
- { 0x04E2, 0x04E3, 0x0000, 0x0000 },
- { 0x1EF8, 0x1EF9, 0x0000, 0x0000 },
- { 0x1FF9, 0x1F79, 0x0000, 0x0000 },
- { 0x24C2, 0x24DC, 0x0000, 0x0000 },
- { 0x2CCA, 0x2CCB, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_231[] = {
- { 0x01E6, 0x01E7, 0x0000, 0x0000 },
- { 0x03E4, 0x03E5, 0x0000, 0x0000 },
- { 0x1FF8, 0x1F78, 0x0000, 0x0000 },
- { 0x24C3, 0x24DD, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_232[] = {
- { 0x04EC, 0x04ED, 0x0000, 0x0000 },
- { 0x1EF6, 0x1EF7, 0x0000, 0x0000 },
- { 0x1FF7, 0x03C9, 0x0342, 0x03B9 },
- { 0x24CC, 0x24E6, 0x0000, 0x0000 },
- { 0x2CC4, 0x2CC5, 0x0000, 0x0000 },
- { 0xFB13, 0x0574, 0x0576, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_233[] = {
- { 0x01E8, 0x01E9, 0x0000, 0x0000 },
- { 0x03EA, 0x03EB, 0x0000, 0x0000 },
- { 0x1FF6, 0x03C9, 0x0342, 0x0000 },
- { 0x24CD, 0x24E7, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_234[] = {
- { 0x04EE, 0x04EF, 0x0000, 0x0000 },
- { 0x1EF4, 0x1EF5, 0x0000, 0x0000 },
- { 0x24CE, 0x24E8, 0x0000, 0x0000 },
- { 0x2CC6, 0x2CC7, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_235[] = {
- { 0x01EA, 0x01EB, 0x0000, 0x0000 },
- { 0x03E8, 0x03E9, 0x0000, 0x0000 },
- { 0x1FF4, 0x03CE, 0x03B9, 0x0000 },
- { 0x24CF, 0x24E9, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_236[] = {
- { 0x04E8, 0x04E9, 0x0000, 0x0000 },
- { 0x1EF2, 0x1EF3, 0x0000, 0x0000 },
- { 0x1FF3, 0x03C9, 0x03B9, 0x0000 },
- { 0x24C8, 0x24E2, 0x0000, 0x0000 },
- { 0x2CC0, 0x2CC1, 0x0000, 0x0000 },
- { 0xFB17, 0x0574, 0x056D, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_237[] = {
- { 0x01EC, 0x01ED, 0x0000, 0x0000 },
- { 0x03EE, 0x03EF, 0x0000, 0x0000 },
- { 0x1FF2, 0x1F7C, 0x03B9, 0x0000 },
- { 0x24C9, 0x24E3, 0x0000, 0x0000 },
- { 0xFB16, 0x057E, 0x0576, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_238[] = {
- { 0x04EA, 0x04EB, 0x0000, 0x0000 },
- { 0x1EF0, 0x1EF1, 0x0000, 0x0000 },
- { 0x24CA, 0x24E4, 0x0000, 0x0000 },
- { 0x2CC2, 0x2CC3, 0x0000, 0x0000 },
- { 0xFB15, 0x0574, 0x056B, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_239[] = {
- { 0x01EE, 0x01EF, 0x0000, 0x0000 },
- { 0x03EC, 0x03ED, 0x0000, 0x0000 },
- { 0x24CB, 0x24E5, 0x0000, 0x0000 },
- { 0xFB14, 0x0574, 0x0565, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_240[] = {
- { 0x01F1, 0x01F3, 0x0000, 0x0000 },
- { 0x04F4, 0x04F5, 0x0000, 0x0000 },
- { 0x1EEE, 0x1EEF, 0x0000, 0x0000 },
- { 0x2CDC, 0x2CDD, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_241[] = {
- { 0x01F0, 0x006A, 0x030C, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_242[] = {
- { 0x03F1, 0x03C1, 0x0000, 0x0000 },
- { 0x04F6, 0x04F7, 0x0000, 0x0000 },
- { 0x1EEC, 0x1EED, 0x0000, 0x0000 },
- { 0x2CDE, 0x2CDF, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_243[] = {
- { 0x01F2, 0x01F3, 0x0000, 0x0000 },
- { 0x03F0, 0x03BA, 0x0000, 0x0000 },
- { 0x1FEC, 0x1FE5, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_244[] = {
- { 0x03F7, 0x03F8, 0x0000, 0x0000 },
- { 0x04F0, 0x04F1, 0x0000, 0x0000 },
- { 0x1EEA, 0x1EEB, 0x0000, 0x0000 },
- { 0x1FEB, 0x1F7B, 0x0000, 0x0000 },
- { 0x2CD8, 0x2CD9, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_245[] = {
- { 0x01F4, 0x01F5, 0x0000, 0x0000 },
- { 0x1FEA, 0x1F7A, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_246[] = {
- { 0x01F7, 0x01BF, 0x0000, 0x0000 },
- { 0x03F5, 0x03B5, 0x0000, 0x0000 },
- { 0x04F2, 0x04F3, 0x0000, 0x0000 },
- { 0x1EE8, 0x1EE9, 0x0000, 0x0000 },
- { 0x1FE9, 0x1FE1, 0x0000, 0x0000 },
- { 0x2CDA, 0x2CDB, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_247[] = {
- { 0x01F6, 0x0195, 0x0000, 0x0000 },
- { 0x03F4, 0x03B8, 0x0000, 0x0000 },
- { 0x1FE8, 0x1FE0, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_248[] = {
- { 0x1EE6, 0x1EE7, 0x0000, 0x0000 },
- { 0x1FE7, 0x03C5, 0x0308, 0x0342 },
- { 0x2CD4, 0x2CD5, 0x0000, 0x0000 },
- { 0xFB03, 0x0066, 0x0066, 0x0069 }
-};
-
-static const CaseFoldMapping case_fold_249[] = {
- { 0x01F8, 0x01F9, 0x0000, 0x0000 },
- { 0x03FA, 0x03FB, 0x0000, 0x0000 },
- { 0x1FE6, 0x03C5, 0x0342, 0x0000 },
- { 0xFB02, 0x0066, 0x006C, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_250[] = {
- { 0x03F9, 0x03F2, 0x0000, 0x0000 },
- { 0x1EE4, 0x1EE5, 0x0000, 0x0000 },
- { 0x2CD6, 0x2CD7, 0x0000, 0x0000 },
- { 0xFB01, 0x0066, 0x0069, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_251[] = {
- { 0x01FA, 0x01FB, 0x0000, 0x0000 },
- { 0x1FE4, 0x03C1, 0x0313, 0x0000 },
- { 0xFB00, 0x0066, 0x0066, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_252[] = {
- { 0x04F8, 0x04F9, 0x0000, 0x0000 },
- { 0x1EE2, 0x1EE3, 0x0000, 0x0000 },
- { 0x1FE3, 0x03C5, 0x0308, 0x0301 },
- { 0x2CD0, 0x2CD1, 0x0000, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_253[] = {
- { 0x01FC, 0x01FD, 0x0000, 0x0000 },
- { 0x1FE2, 0x03C5, 0x0308, 0x0300 },
- { 0xFB06, 0x0073, 0x0074, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_254[] = {
- { 0x1EE0, 0x1EE1, 0x0000, 0x0000 },
- { 0x2CD2, 0x2CD3, 0x0000, 0x0000 },
- { 0xFB05, 0x0073, 0x0074, 0x0000 }
-};
-
-static const CaseFoldMapping case_fold_255[] = {
- { 0x01FE, 0x01FF, 0x0000, 0x0000 },
- { 0xFB04, 0x0066, 0x0066, 0x006C }
-};
-
-
-static const CaseFoldHashBucket case_fold_hash[256] = {
- { __PHYSFS_ARRAYLEN(case_fold_000), case_fold_000 },
- { __PHYSFS_ARRAYLEN(case_fold_001), case_fold_001 },
- { __PHYSFS_ARRAYLEN(case_fold_002), case_fold_002 },
- { __PHYSFS_ARRAYLEN(case_fold_003), case_fold_003 },
- { __PHYSFS_ARRAYLEN(case_fold_004), case_fold_004 },
- { __PHYSFS_ARRAYLEN(case_fold_005), case_fold_005 },
- { __PHYSFS_ARRAYLEN(case_fold_006), case_fold_006 },
- { __PHYSFS_ARRAYLEN(case_fold_007), case_fold_007 },
- { __PHYSFS_ARRAYLEN(case_fold_008), case_fold_008 },
- { __PHYSFS_ARRAYLEN(case_fold_009), case_fold_009 },
- { __PHYSFS_ARRAYLEN(case_fold_010), case_fold_010 },
- { __PHYSFS_ARRAYLEN(case_fold_011), case_fold_011 },
- { __PHYSFS_ARRAYLEN(case_fold_012), case_fold_012 },
- { __PHYSFS_ARRAYLEN(case_fold_013), case_fold_013 },
- { __PHYSFS_ARRAYLEN(case_fold_014), case_fold_014 },
- { __PHYSFS_ARRAYLEN(case_fold_015), case_fold_015 },
- { __PHYSFS_ARRAYLEN(case_fold_016), case_fold_016 },
- { __PHYSFS_ARRAYLEN(case_fold_017), case_fold_017 },
- { __PHYSFS_ARRAYLEN(case_fold_018), case_fold_018 },
- { __PHYSFS_ARRAYLEN(case_fold_019), case_fold_019 },
- { __PHYSFS_ARRAYLEN(case_fold_020), case_fold_020 },
- { __PHYSFS_ARRAYLEN(case_fold_021), case_fold_021 },
- { __PHYSFS_ARRAYLEN(case_fold_022), case_fold_022 },
- { __PHYSFS_ARRAYLEN(case_fold_023), case_fold_023 },
- { __PHYSFS_ARRAYLEN(case_fold_024), case_fold_024 },
- { __PHYSFS_ARRAYLEN(case_fold_025), case_fold_025 },
- { __PHYSFS_ARRAYLEN(case_fold_026), case_fold_026 },
- { __PHYSFS_ARRAYLEN(case_fold_027), case_fold_027 },
- { __PHYSFS_ARRAYLEN(case_fold_028), case_fold_028 },
- { __PHYSFS_ARRAYLEN(case_fold_029), case_fold_029 },
- { __PHYSFS_ARRAYLEN(case_fold_030), case_fold_030 },
- { __PHYSFS_ARRAYLEN(case_fold_031), case_fold_031 },
- { __PHYSFS_ARRAYLEN(case_fold_032), case_fold_032 },
- { __PHYSFS_ARRAYLEN(case_fold_033), case_fold_033 },
- { __PHYSFS_ARRAYLEN(case_fold_034), case_fold_034 },
- { __PHYSFS_ARRAYLEN(case_fold_035), case_fold_035 },
- { __PHYSFS_ARRAYLEN(case_fold_036), case_fold_036 },
- { __PHYSFS_ARRAYLEN(case_fold_037), case_fold_037 },
- { __PHYSFS_ARRAYLEN(case_fold_038), case_fold_038 },
- { __PHYSFS_ARRAYLEN(case_fold_039), case_fold_039 },
- { __PHYSFS_ARRAYLEN(case_fold_040), case_fold_040 },
- { __PHYSFS_ARRAYLEN(case_fold_041), case_fold_041 },
- { __PHYSFS_ARRAYLEN(case_fold_042), case_fold_042 },
- { __PHYSFS_ARRAYLEN(case_fold_043), case_fold_043 },
- { __PHYSFS_ARRAYLEN(case_fold_044), case_fold_044 },
- { __PHYSFS_ARRAYLEN(case_fold_045), case_fold_045 },
- { __PHYSFS_ARRAYLEN(case_fold_046), case_fold_046 },
- { __PHYSFS_ARRAYLEN(case_fold_047), case_fold_047 },
- { __PHYSFS_ARRAYLEN(case_fold_048), case_fold_048 },
- { __PHYSFS_ARRAYLEN(case_fold_049), case_fold_049 },
- { __PHYSFS_ARRAYLEN(case_fold_050), case_fold_050 },
- { __PHYSFS_ARRAYLEN(case_fold_051), case_fold_051 },
- { __PHYSFS_ARRAYLEN(case_fold_052), case_fold_052 },
- { __PHYSFS_ARRAYLEN(case_fold_053), case_fold_053 },
- { __PHYSFS_ARRAYLEN(case_fold_054), case_fold_054 },
- { __PHYSFS_ARRAYLEN(case_fold_055), case_fold_055 },
- { __PHYSFS_ARRAYLEN(case_fold_056), case_fold_056 },
- { __PHYSFS_ARRAYLEN(case_fold_057), case_fold_057 },
- { __PHYSFS_ARRAYLEN(case_fold_058), case_fold_058 },
- { __PHYSFS_ARRAYLEN(case_fold_059), case_fold_059 },
- { __PHYSFS_ARRAYLEN(case_fold_060), case_fold_060 },
- { __PHYSFS_ARRAYLEN(case_fold_061), case_fold_061 },
- { __PHYSFS_ARRAYLEN(case_fold_062), case_fold_062 },
- { __PHYSFS_ARRAYLEN(case_fold_063), case_fold_063 },
- { __PHYSFS_ARRAYLEN(case_fold_064), case_fold_064 },
- { __PHYSFS_ARRAYLEN(case_fold_065), case_fold_065 },
- { __PHYSFS_ARRAYLEN(case_fold_066), case_fold_066 },
- { __PHYSFS_ARRAYLEN(case_fold_067), case_fold_067 },
- { __PHYSFS_ARRAYLEN(case_fold_068), case_fold_068 },
- { __PHYSFS_ARRAYLEN(case_fold_069), case_fold_069 },
- { __PHYSFS_ARRAYLEN(case_fold_070), case_fold_070 },
- { __PHYSFS_ARRAYLEN(case_fold_071), case_fold_071 },
- { __PHYSFS_ARRAYLEN(case_fold_072), case_fold_072 },
- { __PHYSFS_ARRAYLEN(case_fold_073), case_fold_073 },
- { __PHYSFS_ARRAYLEN(case_fold_074), case_fold_074 },
- { __PHYSFS_ARRAYLEN(case_fold_075), case_fold_075 },
- { __PHYSFS_ARRAYLEN(case_fold_076), case_fold_076 },
- { __PHYSFS_ARRAYLEN(case_fold_077), case_fold_077 },
- { __PHYSFS_ARRAYLEN(case_fold_078), case_fold_078 },
- { __PHYSFS_ARRAYLEN(case_fold_079), case_fold_079 },
- { __PHYSFS_ARRAYLEN(case_fold_080), case_fold_080 },
- { __PHYSFS_ARRAYLEN(case_fold_081), case_fold_081 },
- { __PHYSFS_ARRAYLEN(case_fold_082), case_fold_082 },
- { __PHYSFS_ARRAYLEN(case_fold_083), case_fold_083 },
- { __PHYSFS_ARRAYLEN(case_fold_084), case_fold_084 },
- { __PHYSFS_ARRAYLEN(case_fold_085), case_fold_085 },
- { __PHYSFS_ARRAYLEN(case_fold_086), case_fold_086 },
- { __PHYSFS_ARRAYLEN(case_fold_087), case_fold_087 },
- { __PHYSFS_ARRAYLEN(case_fold_088), case_fold_088 },
- { __PHYSFS_ARRAYLEN(case_fold_089), case_fold_089 },
- { __PHYSFS_ARRAYLEN(case_fold_090), case_fold_090 },
- { __PHYSFS_ARRAYLEN(case_fold_091), case_fold_091 },
- { __PHYSFS_ARRAYLEN(case_fold_092), case_fold_092 },
- { __PHYSFS_ARRAYLEN(case_fold_093), case_fold_093 },
- { __PHYSFS_ARRAYLEN(case_fold_094), case_fold_094 },
- { __PHYSFS_ARRAYLEN(case_fold_095), case_fold_095 },
- { __PHYSFS_ARRAYLEN(case_fold_096), case_fold_096 },
- { __PHYSFS_ARRAYLEN(case_fold_097), case_fold_097 },
- { __PHYSFS_ARRAYLEN(case_fold_098), case_fold_098 },
- { __PHYSFS_ARRAYLEN(case_fold_099), case_fold_099 },
- { __PHYSFS_ARRAYLEN(case_fold_100), case_fold_100 },
- { __PHYSFS_ARRAYLEN(case_fold_101), case_fold_101 },
- { __PHYSFS_ARRAYLEN(case_fold_102), case_fold_102 },
- { __PHYSFS_ARRAYLEN(case_fold_103), case_fold_103 },
- { __PHYSFS_ARRAYLEN(case_fold_104), case_fold_104 },
- { __PHYSFS_ARRAYLEN(case_fold_105), case_fold_105 },
- { __PHYSFS_ARRAYLEN(case_fold_106), case_fold_106 },
- { __PHYSFS_ARRAYLEN(case_fold_107), case_fold_107 },
- { __PHYSFS_ARRAYLEN(case_fold_108), case_fold_108 },
- { __PHYSFS_ARRAYLEN(case_fold_109), case_fold_109 },
- { __PHYSFS_ARRAYLEN(case_fold_110), case_fold_110 },
- { __PHYSFS_ARRAYLEN(case_fold_111), case_fold_111 },
- { __PHYSFS_ARRAYLEN(case_fold_112), case_fold_112 },
- { __PHYSFS_ARRAYLEN(case_fold_113), case_fold_113 },
- { __PHYSFS_ARRAYLEN(case_fold_114), case_fold_114 },
- { __PHYSFS_ARRAYLEN(case_fold_115), case_fold_115 },
- { __PHYSFS_ARRAYLEN(case_fold_116), case_fold_116 },
- { __PHYSFS_ARRAYLEN(case_fold_117), case_fold_117 },
- { __PHYSFS_ARRAYLEN(case_fold_118), case_fold_118 },
- { __PHYSFS_ARRAYLEN(case_fold_119), case_fold_119 },
- { __PHYSFS_ARRAYLEN(case_fold_120), case_fold_120 },
- { __PHYSFS_ARRAYLEN(case_fold_121), case_fold_121 },
- { __PHYSFS_ARRAYLEN(case_fold_122), case_fold_122 },
- { 0, NULL },
- { __PHYSFS_ARRAYLEN(case_fold_124), case_fold_124 },
- { 0, NULL },
- { __PHYSFS_ARRAYLEN(case_fold_126), case_fold_126 },
- { 0, NULL },
- { __PHYSFS_ARRAYLEN(case_fold_128), case_fold_128 },
- { __PHYSFS_ARRAYLEN(case_fold_129), case_fold_129 },
- { __PHYSFS_ARRAYLEN(case_fold_130), case_fold_130 },
- { __PHYSFS_ARRAYLEN(case_fold_131), case_fold_131 },
- { __PHYSFS_ARRAYLEN(case_fold_132), case_fold_132 },
- { __PHYSFS_ARRAYLEN(case_fold_133), case_fold_133 },
- { __PHYSFS_ARRAYLEN(case_fold_134), case_fold_134 },
- { __PHYSFS_ARRAYLEN(case_fold_135), case_fold_135 },
- { __PHYSFS_ARRAYLEN(case_fold_136), case_fold_136 },
- { __PHYSFS_ARRAYLEN(case_fold_137), case_fold_137 },
- { __PHYSFS_ARRAYLEN(case_fold_138), case_fold_138 },
- { __PHYSFS_ARRAYLEN(case_fold_139), case_fold_139 },
- { __PHYSFS_ARRAYLEN(case_fold_140), case_fold_140 },
- { __PHYSFS_ARRAYLEN(case_fold_141), case_fold_141 },
- { __PHYSFS_ARRAYLEN(case_fold_142), case_fold_142 },
- { __PHYSFS_ARRAYLEN(case_fold_143), case_fold_143 },
- { __PHYSFS_ARRAYLEN(case_fold_144), case_fold_144 },
- { __PHYSFS_ARRAYLEN(case_fold_145), case_fold_145 },
- { __PHYSFS_ARRAYLEN(case_fold_146), case_fold_146 },
- { __PHYSFS_ARRAYLEN(case_fold_147), case_fold_147 },
- { __PHYSFS_ARRAYLEN(case_fold_148), case_fold_148 },
- { __PHYSFS_ARRAYLEN(case_fold_149), case_fold_149 },
- { __PHYSFS_ARRAYLEN(case_fold_150), case_fold_150 },
- { __PHYSFS_ARRAYLEN(case_fold_151), case_fold_151 },
- { __PHYSFS_ARRAYLEN(case_fold_152), case_fold_152 },
- { __PHYSFS_ARRAYLEN(case_fold_153), case_fold_153 },
- { __PHYSFS_ARRAYLEN(case_fold_154), case_fold_154 },
- { __PHYSFS_ARRAYLEN(case_fold_155), case_fold_155 },
- { __PHYSFS_ARRAYLEN(case_fold_156), case_fold_156 },
- { __PHYSFS_ARRAYLEN(case_fold_157), case_fold_157 },
- { __PHYSFS_ARRAYLEN(case_fold_158), case_fold_158 },
- { __PHYSFS_ARRAYLEN(case_fold_159), case_fold_159 },
- { __PHYSFS_ARRAYLEN(case_fold_160), case_fold_160 },
- { __PHYSFS_ARRAYLEN(case_fold_161), case_fold_161 },
- { __PHYSFS_ARRAYLEN(case_fold_162), case_fold_162 },
- { __PHYSFS_ARRAYLEN(case_fold_163), case_fold_163 },
- { __PHYSFS_ARRAYLEN(case_fold_164), case_fold_164 },
- { __PHYSFS_ARRAYLEN(case_fold_165), case_fold_165 },
- { __PHYSFS_ARRAYLEN(case_fold_166), case_fold_166 },
- { __PHYSFS_ARRAYLEN(case_fold_167), case_fold_167 },
- { __PHYSFS_ARRAYLEN(case_fold_168), case_fold_168 },
- { __PHYSFS_ARRAYLEN(case_fold_169), case_fold_169 },
- { __PHYSFS_ARRAYLEN(case_fold_170), case_fold_170 },
- { __PHYSFS_ARRAYLEN(case_fold_171), case_fold_171 },
- { __PHYSFS_ARRAYLEN(case_fold_172), case_fold_172 },
- { __PHYSFS_ARRAYLEN(case_fold_173), case_fold_173 },
- { __PHYSFS_ARRAYLEN(case_fold_174), case_fold_174 },
- { __PHYSFS_ARRAYLEN(case_fold_175), case_fold_175 },
- { __PHYSFS_ARRAYLEN(case_fold_176), case_fold_176 },
- { __PHYSFS_ARRAYLEN(case_fold_177), case_fold_177 },
- { __PHYSFS_ARRAYLEN(case_fold_178), case_fold_178 },
- { __PHYSFS_ARRAYLEN(case_fold_179), case_fold_179 },
- { __PHYSFS_ARRAYLEN(case_fold_180), case_fold_180 },
- { __PHYSFS_ARRAYLEN(case_fold_181), case_fold_181 },
- { __PHYSFS_ARRAYLEN(case_fold_182), case_fold_182 },
- { __PHYSFS_ARRAYLEN(case_fold_183), case_fold_183 },
- { __PHYSFS_ARRAYLEN(case_fold_184), case_fold_184 },
- { __PHYSFS_ARRAYLEN(case_fold_185), case_fold_185 },
- { __PHYSFS_ARRAYLEN(case_fold_186), case_fold_186 },
- { __PHYSFS_ARRAYLEN(case_fold_187), case_fold_187 },
- { __PHYSFS_ARRAYLEN(case_fold_188), case_fold_188 },
- { __PHYSFS_ARRAYLEN(case_fold_189), case_fold_189 },
- { __PHYSFS_ARRAYLEN(case_fold_190), case_fold_190 },
- { __PHYSFS_ARRAYLEN(case_fold_191), case_fold_191 },
- { __PHYSFS_ARRAYLEN(case_fold_192), case_fold_192 },
- { __PHYSFS_ARRAYLEN(case_fold_193), case_fold_193 },
- { __PHYSFS_ARRAYLEN(case_fold_194), case_fold_194 },
- { __PHYSFS_ARRAYLEN(case_fold_195), case_fold_195 },
- { __PHYSFS_ARRAYLEN(case_fold_196), case_fold_196 },
- { __PHYSFS_ARRAYLEN(case_fold_197), case_fold_197 },
- { __PHYSFS_ARRAYLEN(case_fold_198), case_fold_198 },
- { __PHYSFS_ARRAYLEN(case_fold_199), case_fold_199 },
- { __PHYSFS_ARRAYLEN(case_fold_200), case_fold_200 },
- { __PHYSFS_ARRAYLEN(case_fold_201), case_fold_201 },
- { __PHYSFS_ARRAYLEN(case_fold_202), case_fold_202 },
- { __PHYSFS_ARRAYLEN(case_fold_203), case_fold_203 },
- { __PHYSFS_ARRAYLEN(case_fold_204), case_fold_204 },
- { __PHYSFS_ARRAYLEN(case_fold_205), case_fold_205 },
- { __PHYSFS_ARRAYLEN(case_fold_206), case_fold_206 },
- { __PHYSFS_ARRAYLEN(case_fold_207), case_fold_207 },
- { __PHYSFS_ARRAYLEN(case_fold_208), case_fold_208 },
- { __PHYSFS_ARRAYLEN(case_fold_209), case_fold_209 },
- { __PHYSFS_ARRAYLEN(case_fold_210), case_fold_210 },
- { __PHYSFS_ARRAYLEN(case_fold_211), case_fold_211 },
- { __PHYSFS_ARRAYLEN(case_fold_212), case_fold_212 },
- { __PHYSFS_ARRAYLEN(case_fold_213), case_fold_213 },
- { __PHYSFS_ARRAYLEN(case_fold_214), case_fold_214 },
- { __PHYSFS_ARRAYLEN(case_fold_215), case_fold_215 },
- { __PHYSFS_ARRAYLEN(case_fold_216), case_fold_216 },
- { __PHYSFS_ARRAYLEN(case_fold_217), case_fold_217 },
- { __PHYSFS_ARRAYLEN(case_fold_218), case_fold_218 },
- { __PHYSFS_ARRAYLEN(case_fold_219), case_fold_219 },
- { __PHYSFS_ARRAYLEN(case_fold_220), case_fold_220 },
- { __PHYSFS_ARRAYLEN(case_fold_221), case_fold_221 },
- { __PHYSFS_ARRAYLEN(case_fold_222), case_fold_222 },
- { __PHYSFS_ARRAYLEN(case_fold_223), case_fold_223 },
- { __PHYSFS_ARRAYLEN(case_fold_224), case_fold_224 },
- { __PHYSFS_ARRAYLEN(case_fold_225), case_fold_225 },
- { __PHYSFS_ARRAYLEN(case_fold_226), case_fold_226 },
- { __PHYSFS_ARRAYLEN(case_fold_227), case_fold_227 },
- { __PHYSFS_ARRAYLEN(case_fold_228), case_fold_228 },
- { __PHYSFS_ARRAYLEN(case_fold_229), case_fold_229 },
- { __PHYSFS_ARRAYLEN(case_fold_230), case_fold_230 },
- { __PHYSFS_ARRAYLEN(case_fold_231), case_fold_231 },
- { __PHYSFS_ARRAYLEN(case_fold_232), case_fold_232 },
- { __PHYSFS_ARRAYLEN(case_fold_233), case_fold_233 },
- { __PHYSFS_ARRAYLEN(case_fold_234), case_fold_234 },
- { __PHYSFS_ARRAYLEN(case_fold_235), case_fold_235 },
- { __PHYSFS_ARRAYLEN(case_fold_236), case_fold_236 },
- { __PHYSFS_ARRAYLEN(case_fold_237), case_fold_237 },
- { __PHYSFS_ARRAYLEN(case_fold_238), case_fold_238 },
- { __PHYSFS_ARRAYLEN(case_fold_239), case_fold_239 },
- { __PHYSFS_ARRAYLEN(case_fold_240), case_fold_240 },
- { __PHYSFS_ARRAYLEN(case_fold_241), case_fold_241 },
- { __PHYSFS_ARRAYLEN(case_fold_242), case_fold_242 },
- { __PHYSFS_ARRAYLEN(case_fold_243), case_fold_243 },
- { __PHYSFS_ARRAYLEN(case_fold_244), case_fold_244 },
- { __PHYSFS_ARRAYLEN(case_fold_245), case_fold_245 },
- { __PHYSFS_ARRAYLEN(case_fold_246), case_fold_246 },
- { __PHYSFS_ARRAYLEN(case_fold_247), case_fold_247 },
- { __PHYSFS_ARRAYLEN(case_fold_248), case_fold_248 },
- { __PHYSFS_ARRAYLEN(case_fold_249), case_fold_249 },
- { __PHYSFS_ARRAYLEN(case_fold_250), case_fold_250 },
- { __PHYSFS_ARRAYLEN(case_fold_251), case_fold_251 },
- { __PHYSFS_ARRAYLEN(case_fold_252), case_fold_252 },
- { __PHYSFS_ARRAYLEN(case_fold_253), case_fold_253 },
- { __PHYSFS_ARRAYLEN(case_fold_254), case_fold_254 },
- { __PHYSFS_ARRAYLEN(case_fold_255), case_fold_255 },
-};
-
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/src/physfs_internal.h
--- a/misc/physfs/src/physfs_internal.h Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,776 +0,0 @@
-/*
- * Internal function/structure declaration. Do NOT include in your
- * application.
- *
- * Please see the file LICENSE.txt in the source's root directory.
- *
- * This file written by Ryan C. Gordon.
- */
-
-#ifndef _INCLUDE_PHYSFS_INTERNAL_H_
-#define _INCLUDE_PHYSFS_INTERNAL_H_
-
-#ifndef __PHYSICSFS_INTERNAL__
-#error Do not include this header from your applications.
-#endif
-
-#include "physfs.h"
-
-/* The holy trinity. */
-#include
-#include
-#include
-
-#include "physfs_platforms.h"
-
-#include
-
-/* !!! FIXME: remove this when revamping stack allocation code... */
-#if defined(_MSC_VER) || defined(__MINGW32__)
-#include
-#endif
-
-#if PHYSFS_PLATFORM_SOLARIS
-#include
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __GNUC__
-#define PHYSFS_MINIMUM_GCC_VERSION(major, minor) \
- ( ((__GNUC__ << 16) + __GNUC_MINOR__) >= (((major) << 16) + (minor)) )
-#else
-#define PHYSFS_MINIMUM_GCC_VERSION(major, minor) (0)
-#endif
-
-#ifdef __cplusplus
- /* C++ always has a real inline keyword. */
-#elif (defined macintosh) && !(defined __MWERKS__)
-# define inline
-#elif (defined _MSC_VER)
-# define inline __inline
-#endif
-
-#if PHYSFS_PLATFORM_LINUX && !defined(_FILE_OFFSET_BITS)
-#define _FILE_OFFSET_BITS 64
-#endif
-
-/*
- * Interface for small allocations. If you need a little scratch space for
- * a throwaway buffer or string, use this. It will make small allocations
- * on the stack if possible, and use allocator.Malloc() if they are too
- * large. This helps reduce malloc pressure.
- * There are some rules, though:
- * NEVER return a pointer from this, as stack-allocated buffers go away
- * when your function returns.
- * NEVER allocate in a loop, as stack-allocated pointers will pile up. Call
- * a function that uses smallAlloc from your loop, so the allocation can
- * free each time.
- * NEVER call smallAlloc with any complex expression (it's a macro that WILL
- * have side effects...it references the argument multiple times). Use a
- * variable or a literal.
- * NEVER free a pointer from this with anything but smallFree. It will not
- * be a valid pointer to the allocator, regardless of where the memory came
- * from.
- * NEVER realloc a pointer from this.
- * NEVER forget to use smallFree: it may not be a pointer from the stack.
- * NEVER forget to check for NULL...allocation can fail here, of course!
- */
-#define __PHYSFS_SMALLALLOCTHRESHOLD 256
-void *__PHYSFS_initSmallAlloc(void *ptr, PHYSFS_uint64 len);
-
-#define __PHYSFS_smallAlloc(bytes) ( \
- __PHYSFS_initSmallAlloc( \
- (((bytes) < __PHYSFS_SMALLALLOCTHRESHOLD) ? \
- alloca((size_t)((bytes)+sizeof(void*))) : NULL), (bytes)) \
-)
-
-void __PHYSFS_smallFree(void *ptr);
-
-
-/* Use the allocation hooks. */
-#define malloc(x) Do not use malloc() directly.
-#define realloc(x, y) Do not use realloc() directly.
-#define free(x) Do not use free() directly.
-/* !!! FIXME: add alloca check here. */
-
-#ifndef PHYSFS_SUPPORTS_ZIP
-#define PHYSFS_SUPPORTS_ZIP 1
-#endif
-#ifndef PHYSFS_SUPPORTS_7Z
-#define PHYSFS_SUPPORTS_7Z 0
-#endif
-#ifndef PHYSFS_SUPPORTS_GRP
-#define PHYSFS_SUPPORTS_GRP 0
-#endif
-#ifndef PHYSFS_SUPPORTS_HOG
-#define PHYSFS_SUPPORTS_HOG 0
-#endif
-#ifndef PHYSFS_SUPPORTS_MVL
-#define PHYSFS_SUPPORTS_MVL 0
-#endif
-#ifndef PHYSFS_SUPPORTS_WAD
-#define PHYSFS_SUPPORTS_WAD 0
-#endif
-#ifndef PHYSFS_SUPPORTS_ISO9660
-#define PHYSFS_SUPPORTS_ISO9660 0
-#endif
-
-/* The latest supported PHYSFS_Io::version value. */
-#define CURRENT_PHYSFS_IO_API_VERSION 0
-
-/* Opaque data for file and dir handlers... */
-typedef void PHYSFS_Dir;
-
-typedef struct
-{
- /*
- * Basic info about this archiver...
- */
- const PHYSFS_ArchiveInfo info;
-
-
- /*
- * DIRECTORY ROUTINES:
- * These functions are for dir handles. Generate a handle with the
- * openArchive() method, then pass it as the "opaque" PHYSFS_Dir to the
- * others.
- *
- * Symlinks should always be followed (except in stat()); PhysicsFS will
- * use the stat() method to check for symlinks and make a judgement on
- * whether to continue to call other methods based on that.
- */
-
- /*
- * Open a dirhandle for dir/archive data provided by (io).
- * (name) is a filename associated with (io), but doesn't necessarily
- * map to anything, let alone a real filename. This possibly-
- * meaningless name is in platform-dependent notation.
- * (forWrite) is non-zero if this is to be used for
- * the write directory, and zero if this is to be used for an
- * element of the search path.
- * Returns NULL on failure. We ignore any error code you set here.
- * Returns non-NULL on success. The pointer returned will be
- * passed as the "opaque" parameter for later calls.
- */
- PHYSFS_Dir *(*openArchive)(PHYSFS_Io *io, const char *name, int forWrite);
-
- /*
- * List all files in (dirname). Each file is passed to (cb),
- * where a copy is made if appropriate, so you should dispose of
- * it properly upon return from the callback.
- * You should omit symlinks if (omitSymLinks) is non-zero.
- * If you have a failure, report as much as you can.
- * (dirname) is in platform-independent notation.
- */
- void (*enumerateFiles)(PHYSFS_Dir *opaque, const char *dirname,
- int omitSymLinks, PHYSFS_EnumFilesCallback cb,
- const char *origdir, void *callbackdata);
-
- /*
- * Open file for reading.
- * This filename, (fnm), is in platform-independent notation.
- * If you can't handle multiple opens of the same file,
- * you can opt to fail for the second call.
- * Fail if the file does not exist.
- * Returns NULL on failure, and calls __PHYSFS_setError().
- * Returns non-NULL on success. The pointer returned will be
- * passed as the "opaque" parameter for later file calls.
- *
- * Regardless of success or failure, please set *exists to
- * non-zero if the file existed (even if it's a broken symlink!),
- * zero if it did not.
- */
- PHYSFS_Io *(*openRead)(PHYSFS_Dir *opaque, const char *fnm, int *exists);
-
- /*
- * Open file for writing.
- * If the file does not exist, it should be created. If it exists,
- * it should be truncated to zero bytes. The writing
- * offset should be the start of the file.
- * This filename is in platform-independent notation.
- * If you can't handle multiple opens of the same file,
- * you can opt to fail for the second call.
- * Returns NULL on failure, and calls __PHYSFS_setError().
- * Returns non-NULL on success. The pointer returned will be
- * passed as the "opaque" parameter for later file calls.
- */
- PHYSFS_Io *(*openWrite)(PHYSFS_Dir *opaque, const char *filename);
-
- /*
- * Open file for appending.
- * If the file does not exist, it should be created. The writing
- * offset should be the end of the file.
- * This filename is in platform-independent notation.
- * If you can't handle multiple opens of the same file,
- * you can opt to fail for the second call.
- * Returns NULL on failure, and calls __PHYSFS_setError().
- * Returns non-NULL on success. The pointer returned will be
- * passed as the "opaque" parameter for later file calls.
- */
- PHYSFS_Io *(*openAppend)(PHYSFS_Dir *opaque, const char *filename);
-
- /*
- * Delete a file in the archive/directory.
- * Return non-zero on success, zero on failure.
- * This filename is in platform-independent notation.
- * This method may be NULL.
- * On failure, call __PHYSFS_setError().
- */
- int (*remove)(PHYSFS_Dir *opaque, const char *filename);
-
- /*
- * Create a directory in the archive/directory.
- * If the application is trying to make multiple dirs, PhysicsFS
- * will split them up into multiple calls before passing them to
- * your driver.
- * Return non-zero on success, zero on failure.
- * This filename is in platform-independent notation.
- * This method may be NULL.
- * On failure, call __PHYSFS_setError().
- */
- int (*mkdir)(PHYSFS_Dir *opaque, const char *filename);
-
- /*
- * Close directories/archives, and free any associated memory,
- * including the original PHYSFS_Io and (opaque) itself, if
- * applicable. Implementation can assume that it won't be called if
- * there are still files open from this archive.
- */
- void (*closeArchive)(PHYSFS_Dir *opaque);
-
- /*
- * Obtain basic file metadata.
- * Returns non-zero on success, zero on failure.
- * On failure, call __PHYSFS_setError().
- */
- int (*stat)(PHYSFS_Dir *opaque, const char *fn,
- int *exists, PHYSFS_Stat *stat);
-} PHYSFS_Archiver;
-
-
-/*
- * Call this to set the message returned by PHYSFS_getLastError().
- * Please only use the ERR_* constants above, or add new constants to the
- * above group, but I want these all in one place.
- *
- * Calling this with a NULL argument is a safe no-op.
- */
-void __PHYSFS_setError(const PHYSFS_ErrorCode err);
-
-
-/* This byteorder stuff was lifted from SDL. http://www.libsdl.org/ */
-#define PHYSFS_LIL_ENDIAN 1234
-#define PHYSFS_BIG_ENDIAN 4321
-
-#if defined(__i386__) || defined(__ia64__) || \
- defined(_M_IX86) || defined(_M_IA64) || defined(_M_X64) || \
- (defined(__alpha__) || defined(__alpha)) || \
- defined(__arm__) || defined(ARM) || \
- (defined(__mips__) && defined(__MIPSEL__)) || \
- defined(__SYMBIAN32__) || \
- defined(__x86_64__) || \
- defined(__LITTLE_ENDIAN__)
-#define PHYSFS_BYTEORDER PHYSFS_LIL_ENDIAN
-#else
-#define PHYSFS_BYTEORDER PHYSFS_BIG_ENDIAN
-#endif
-
-
-/*
- * When sorting the entries in an archive, we use a modified QuickSort.
- * When there are less then PHYSFS_QUICKSORT_THRESHOLD entries left to sort,
- * we switch over to a BubbleSort for the remainder. Tweak to taste.
- *
- * You can override this setting by defining PHYSFS_QUICKSORT_THRESHOLD
- * before #including "physfs_internal.h".
- */
-#ifndef PHYSFS_QUICKSORT_THRESHOLD
-#define PHYSFS_QUICKSORT_THRESHOLD 4
-#endif
-
-/*
- * Sort an array (or whatever) of (max) elements. This uses a mixture of
- * a QuickSort and BubbleSort internally.
- * (cmpfn) is used to determine ordering, and (swapfn) does the actual
- * swapping of elements in the list.
- *
- * See zip.c for an example.
- */
-void __PHYSFS_sort(void *entries, size_t max,
- int (*cmpfn)(void *, size_t, size_t),
- void (*swapfn)(void *, size_t, size_t));
-
-/*
- * This isn't a formal error code, it's just for BAIL_MACRO.
- * It means: there was an error, but someone else already set it for us.
- */
-#define ERRPASS PHYSFS_ERR_OK
-
-/* These get used all over for lessening code clutter. */
-#define BAIL_MACRO(e, r) do { if (e) __PHYSFS_setError(e); return r; } while (0)
-#define BAIL_IF_MACRO(c, e, r) do { if (c) { if (e) __PHYSFS_setError(e); return r; } } while (0)
-#define BAIL_MACRO_MUTEX(e, m, r) do { if (e) __PHYSFS_setError(e); __PHYSFS_platformReleaseMutex(m); return r; } while (0)
-#define BAIL_IF_MACRO_MUTEX(c, e, m, r) do { if (c) { if (e) __PHYSFS_setError(e); __PHYSFS_platformReleaseMutex(m); return r; } } while (0)
-#define GOTO_MACRO(e, g) do { if (e) __PHYSFS_setError(e); goto g; } while (0)
-#define GOTO_IF_MACRO(c, e, g) do { if (c) { if (e) __PHYSFS_setError(e); goto g; } } while (0)
-#define GOTO_MACRO_MUTEX(e, m, g) do { if (e) __PHYSFS_setError(e); __PHYSFS_platformReleaseMutex(m); goto g; } while (0)
-#define GOTO_IF_MACRO_MUTEX(c, e, m, g) do { if (c) { if (e) __PHYSFS_setError(e); __PHYSFS_platformReleaseMutex(m); goto g; } } while (0)
-
-#define __PHYSFS_ARRAYLEN(x) ( (sizeof (x)) / (sizeof (x[0])) )
-
-#ifdef PHYSFS_NO_64BIT_SUPPORT
-#define __PHYSFS_SI64(x) ((PHYSFS_sint64) (x))
-#define __PHYSFS_UI64(x) ((PHYSFS_uint64) (x))
-#elif (defined __GNUC__)
-#define __PHYSFS_SI64(x) x##LL
-#define __PHYSFS_UI64(x) x##ULL
-#elif (defined _MSC_VER)
-#define __PHYSFS_SI64(x) x##i64
-#define __PHYSFS_UI64(x) x##ui64
-#else
-#define __PHYSFS_SI64(x) ((PHYSFS_sint64) (x))
-#define __PHYSFS_UI64(x) ((PHYSFS_uint64) (x))
-#endif
-
-
-/*
- * Check if a ui64 will fit in the platform's address space.
- * The initial sizeof check will optimize this macro out entirely on
- * 64-bit (and larger?!) platforms, and the other condition will
- * return zero or non-zero if the variable will fit in the platform's
- * size_t, suitable to pass to malloc. This is kinda messy, but effective.
- */
-#define __PHYSFS_ui64FitsAddressSpace(s) ( \
- (sizeof (PHYSFS_uint64) <= sizeof (size_t)) || \
- ((s) < (__PHYSFS_UI64(0xFFFFFFFFFFFFFFFF) >> (64-(sizeof(size_t)*8)))) \
-)
-
-
-/*
- * This is a strcasecmp() or stricmp() replacement that expects both strings
- * to be in UTF-8 encoding. It will do "case folding" to decide if the
- * Unicode codepoints in the strings match.
- *
- * It will report which string is "greater than" the other, but be aware that
- * this doesn't necessarily mean anything: 'a' may be "less than" 'b', but
- * a random Kanji codepoint has no meaningful alphabetically relationship to
- * a Greek Lambda, but being able to assign a reliable "value" makes sorting
- * algorithms possible, if not entirely sane. Most cases should treat the
- * return value as "equal" or "not equal".
- */
-int __PHYSFS_utf8stricmp(const char *s1, const char *s2);
-
-/*
- * This works like __PHYSFS_utf8stricmp(), but takes a character (NOT BYTE
- * COUNT) argument, like strcasencmp().
- */
-int __PHYSFS_utf8strnicmp(const char *s1, const char *s2, PHYSFS_uint32 l);
-
-/*
- * stricmp() that guarantees to only work with low ASCII. The C runtime
- * stricmp() might try to apply a locale/codepage/etc, which we don't want.
- */
-int __PHYSFS_stricmpASCII(const char *s1, const char *s2);
-
-/*
- * strnicmp() that guarantees to only work with low ASCII. The C runtime
- * strnicmp() might try to apply a locale/codepage/etc, which we don't want.
- */
-int __PHYSFS_strnicmpASCII(const char *s1, const char *s2, PHYSFS_uint32 l);
-
-
-/*
- * The current allocator. Not valid before PHYSFS_init is called!
- */
-extern PHYSFS_Allocator __PHYSFS_AllocatorHooks;
-
-/* convenience macro to make this less cumbersome internally... */
-#define allocator __PHYSFS_AllocatorHooks
-
-/*
- * Create a PHYSFS_Io for a file in the physical filesystem.
- * This path is in platform-dependent notation. (mode) must be 'r', 'w', or
- * 'a' for Read, Write, or Append.
- */
-PHYSFS_Io *__PHYSFS_createNativeIo(const char *path, const int mode);
-
-/*
- * Create a PHYSFS_Io for a buffer of memory (READ-ONLY). If you already
- * have one of these, just use its duplicate() method, and it'll increment
- * its refcount without allocating a copy of the buffer.
- */
-PHYSFS_Io *__PHYSFS_createMemoryIo(const void *buf, PHYSFS_uint64 len,
- void (*destruct)(void *));
-
-
-/*
- * Read (len) bytes from (io) into (buf). Returns non-zero on success,
- * zero on i/o error. Literally: "return (io->read(io, buf, len) == len);"
- */
-int __PHYSFS_readAll(PHYSFS_Io *io, void *buf, const PHYSFS_uint64 len);
-
-
-/* These are shared between some archivers. */
-
-typedef struct
-{
- char name[56];
- PHYSFS_uint32 startPos;
- PHYSFS_uint32 size;
-} UNPKentry;
-
-void UNPK_closeArchive(PHYSFS_Dir *opaque);
-PHYSFS_Dir *UNPK_openArchive(PHYSFS_Io *io,UNPKentry *e,const PHYSFS_uint32 n);
-void UNPK_enumerateFiles(PHYSFS_Dir *opaque, const char *dname,
- int omitSymLinks, PHYSFS_EnumFilesCallback cb,
- const char *origdir, void *callbackdata);
-PHYSFS_Io *UNPK_openRead(PHYSFS_Dir *opaque, const char *fnm, int *fileExists);
-PHYSFS_Io *UNPK_openWrite(PHYSFS_Dir *opaque, const char *name);
-PHYSFS_Io *UNPK_openAppend(PHYSFS_Dir *opaque, const char *name);
-int UNPK_remove(PHYSFS_Dir *opaque, const char *name);
-int UNPK_mkdir(PHYSFS_Dir *opaque, const char *name);
-int UNPK_stat(PHYSFS_Dir *opaque, const char *fn, int *exist, PHYSFS_Stat *st);
-
-
-/*--------------------------------------------------------------------------*/
-/*--------------------------------------------------------------------------*/
-/*------------ ----------------*/
-/*------------ You MUST implement the following functions ----------------*/
-/*------------ if porting to a new platform. ----------------*/
-/*------------ (see platform/unix.c for an example) ----------------*/
-/*------------ ----------------*/
-/*--------------------------------------------------------------------------*/
-/*--------------------------------------------------------------------------*/
-
-
-/*
- * The dir separator; '/' on unix, '\\' on win32, ":" on MacOS, etc...
- * Obviously, this isn't a function. If you need more than one char for this,
- * you'll need to pull some old pieces of PhysicsFS out of revision control.
- */
-#if PHYSFS_PLATFORM_WINDOWS
-#define __PHYSFS_platformDirSeparator '\\'
-#else
-#define __PHYSFS_platformDirSeparator '/'
-#endif
-
-/*
- * Initialize the platform. This is called when PHYSFS_init() is called from
- * the application.
- *
- * Return zero if there was a catastrophic failure (which prevents you from
- * functioning at all), and non-zero otherwise.
- */
-int __PHYSFS_platformInit(void);
-
-
-/*
- * Deinitialize the platform. This is called when PHYSFS_deinit() is called
- * from the application. You can use this to clean up anything you've
- * allocated in your platform driver.
- *
- * Return zero if there was a catastrophic failure (which prevents you from
- * functioning at all), and non-zero otherwise.
- */
-int __PHYSFS_platformDeinit(void);
-
-
-/*
- * Open a file for reading. (filename) is in platform-dependent notation. The
- * file pointer should be positioned on the first byte of the file.
- *
- * The return value will be some platform-specific datatype that is opaque to
- * the caller; it could be a (FILE *) under Unix, or a (HANDLE *) under win32.
- *
- * The same file can be opened for read multiple times, and each should have
- * a unique file handle; this is frequently employed to prevent race
- * conditions in the archivers.
- *
- * Call __PHYSFS_setError() and return (NULL) if the file can't be opened.
- */
-void *__PHYSFS_platformOpenRead(const char *filename);
-
-
-/*
- * Open a file for writing. (filename) is in platform-dependent notation. If
- * the file exists, it should be truncated to zero bytes, and if it doesn't
- * exist, it should be created as a zero-byte file. The file pointer should
- * be positioned on the first byte of the file.
- *
- * The return value will be some platform-specific datatype that is opaque to
- * the caller; it could be a (FILE *) under Unix, or a (HANDLE *) under win32,
- * etc.
- *
- * Opening a file for write multiple times has undefined results.
- *
- * Call __PHYSFS_setError() and return (NULL) if the file can't be opened.
- */
-void *__PHYSFS_platformOpenWrite(const char *filename);
-
-
-/*
- * Open a file for appending. (filename) is in platform-dependent notation. If
- * the file exists, the file pointer should be place just past the end of the
- * file, so that the first write will be one byte after the current end of
- * the file. If the file doesn't exist, it should be created as a zero-byte
- * file. The file pointer should be positioned on the first byte of the file.
- *
- * The return value will be some platform-specific datatype that is opaque to
- * the caller; it could be a (FILE *) under Unix, or a (HANDLE *) under win32,
- * etc.
- *
- * Opening a file for append multiple times has undefined results.
- *
- * Call __PHYSFS_setError() and return (NULL) if the file can't be opened.
- */
-void *__PHYSFS_platformOpenAppend(const char *filename);
-
-/*
- * Read more data from a platform-specific file handle. (opaque) should be
- * cast to whatever data type your platform uses. Read a maximum of (len)
- * 8-bit bytes to the area pointed to by (buf). If there isn't enough data
- * available, return the number of bytes read, and position the file pointer
- * immediately after those bytes.
- * On success, return (len) and position the file pointer immediately past
- * the end of the last read byte. Return (-1) if there is a catastrophic
- * error, and call __PHYSFS_setError() to describe the problem; the file
- * pointer should not move in such a case. A partial read is success; only
- * return (-1) on total failure; presumably, the next read call after a
- * partial read will fail as such.
- */
-PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buf, PHYSFS_uint64 len);
-
-/*
- * Write more data to a platform-specific file handle. (opaque) should be
- * cast to whatever data type your platform uses. Write a maximum of (len)
- * 8-bit bytes from the area pointed to by (buffer). If there is a problem,
- * return the number of bytes written, and position the file pointer
- * immediately after those bytes. Return (-1) if there is a catastrophic
- * error, and call __PHYSFS_setError() to describe the problem; the file
- * pointer should not move in such a case. A partial write is success; only
- * return (-1) on total failure; presumably, the next write call after a
- * partial write will fail as such.
- */
-PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
- PHYSFS_uint64 len);
-
-/*
- * Set the file pointer to a new position. (opaque) should be cast to
- * whatever data type your platform uses. (pos) specifies the number
- * of 8-bit bytes to seek to from the start of the file. Seeking past the
- * end of the file is an error condition, and you should check for it.
- *
- * Not all file types can seek; this is to be expected by the caller.
- *
- * On error, call __PHYSFS_setError() and return zero. On success, return
- * a non-zero value.
- */
-int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos);
-
-
-/*
- * Get the file pointer's position, in an 8-bit byte offset from the start of
- * the file. (opaque) should be cast to whatever data type your platform
- * uses.
- *
- * Not all file types can "tell"; this is to be expected by the caller.
- *
- * On error, call __PHYSFS_setError() and return -1. On success, return >= 0.
- */
-PHYSFS_sint64 __PHYSFS_platformTell(void *opaque);
-
-
-/*
- * Determine the current size of a file, in 8-bit bytes, from an open file.
- *
- * The caller expects that this information may not be available for all
- * file types on all platforms.
- *
- * Return -1 if you can't do it, and call __PHYSFS_setError(). Otherwise,
- * return the file length in 8-bit bytes.
- */
-PHYSFS_sint64 __PHYSFS_platformFileLength(void *handle);
-
-
-/*
- * !!! FIXME: comment me.
- */
-int __PHYSFS_platformStat(const char *fn, int *exists, PHYSFS_Stat *stat);
-
-/*
- * Flush any pending writes to disk. (opaque) should be cast to whatever data
- * type your platform uses. Be sure to check for errors; the caller expects
- * that this function can fail if there was a flushing error, etc.
- *
- * Return zero on failure, non-zero on success.
- */
-int __PHYSFS_platformFlush(void *opaque);
-
-/*
- * Close file and deallocate resources. (opaque) should be cast to whatever
- * data type your platform uses. This should close the file in any scenario:
- * flushing is a separate function call, and this function should never fail.
- *
- * You should clean up all resources associated with (opaque); the pointer
- * will be considered invalid after this call.
- */
-void __PHYSFS_platformClose(void *opaque);
-
-/*
- * Platform implementation of PHYSFS_getCdRomDirsCallback()...
- * CD directories are discovered and reported to the callback one at a time.
- * Pointers passed to the callback are assumed to be invalid to the
- * application after the callback returns, so you can free them or whatever.
- * Callback does not assume results will be sorted in any meaningful way.
- */
-void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data);
-
-/*
- * Calculate the base dir, if your platform needs special consideration.
- * Just return NULL if the standard routines will suffice. (see
- * calculateBaseDir() in physfs.c ...)
- * Your string must end with a dir separator if you don't return NULL.
- * Caller will allocator.Free() the retval if it's not NULL.
- */
-char *__PHYSFS_platformCalcBaseDir(const char *argv0);
-
-/*
- * Get the platform-specific user dir.
- * As of PhysicsFS 2.1, returning NULL means fatal error.
- * Your string must end with a dir separator if you don't return NULL.
- * Caller will allocator.Free() the retval if it's not NULL.
- */
-char *__PHYSFS_platformCalcUserDir(void);
-
-
-/* This is the cached version from PHYSFS_init(). This is a fast call. */
-const char *__PHYSFS_getUserDir(void); /* not deprecated internal version. */
-
-
-/*
- * Get the platform-specific pref dir.
- * Returning NULL means fatal error.
- * Your string must end with a dir separator if you don't return NULL.
- * Caller will allocator.Free() the retval if it's not NULL.
- * Caller will make missing directories if necessary; this just reports
- * the final path.
- */
-char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app);
-
-
-/*
- * Return a pointer that uniquely identifies the current thread.
- * On a platform without threading, (0x1) will suffice. These numbers are
- * arbitrary; the only requirement is that no two threads have the same
- * pointer.
- */
-void *__PHYSFS_platformGetThreadID(void);
-
-
-/*
- * Enumerate a directory of files. This follows the rules for the
- * PHYSFS_Archiver->enumerateFiles() method (see above), except that the
- * (dirName) that is passed to this function is converted to
- * platform-DEPENDENT notation by the caller. The PHYSFS_Archiver version
- * uses platform-independent notation. Note that ".", "..", and other
- * metaentries should always be ignored.
- */
-void __PHYSFS_platformEnumerateFiles(const char *dirname,
- int omitSymLinks,
- PHYSFS_EnumFilesCallback callback,
- const char *origdir,
- void *callbackdata);
-
-/*
- * Make a directory in the actual filesystem. (path) is specified in
- * platform-dependent notation. On error, return zero and set the error
- * message. Return non-zero on success.
- */
-int __PHYSFS_platformMkDir(const char *path);
-
-
-/*
- * Remove a file or directory entry in the actual filesystem. (path) is
- * specified in platform-dependent notation. Note that this deletes files
- * _and_ directories, so you might need to do some determination.
- * Non-empty directories should report an error and not delete themselves
- * or their contents.
- *
- * Deleting a symlink should remove the link, not what it points to.
- *
- * On error, return zero and set the error message. Return non-zero on success.
- */
-int __PHYSFS_platformDelete(const char *path);
-
-
-/*
- * Create a platform-specific mutex. This can be whatever datatype your
- * platform uses for mutexes, but it is cast to a (void *) for abstractness.
- *
- * Return (NULL) if you couldn't create one. Systems without threads can
- * return any arbitrary non-NULL value.
- */
-void *__PHYSFS_platformCreateMutex(void);
-
-/*
- * Destroy a platform-specific mutex, and clean up any resources associated
- * with it. (mutex) is a value previously returned by
- * __PHYSFS_platformCreateMutex(). This can be a no-op on single-threaded
- * platforms.
- */
-void __PHYSFS_platformDestroyMutex(void *mutex);
-
-/*
- * Grab possession of a platform-specific mutex. Mutexes should be recursive;
- * that is, the same thread should be able to call this function multiple
- * times in a row without causing a deadlock. This function should block
- * until a thread can gain possession of the mutex.
- *
- * Return non-zero if the mutex was grabbed, zero if there was an
- * unrecoverable problem grabbing it (this should not be a matter of
- * timing out! We're talking major system errors; block until the mutex
- * is available otherwise.)
- *
- * _DO NOT_ call __PHYSFS_setError() in here! Since setError calls this
- * function, you'll cause an infinite recursion. This means you can't
- * use the BAIL_*MACRO* macros, either.
- */
-int __PHYSFS_platformGrabMutex(void *mutex);
-
-/*
- * Relinquish possession of the mutex when this method has been called
- * once for each time that platformGrabMutex was called. Once possession has
- * been released, the next thread in line to grab the mutex (if any) may
- * proceed.
- *
- * _DO NOT_ call __PHYSFS_setError() in here! Since setError calls this
- * function, you'll cause an infinite recursion. This means you can't
- * use the BAIL_*MACRO* macros, either.
- */
-void __PHYSFS_platformReleaseMutex(void *mutex);
-
-/*
- * Called at the start of PHYSFS_init() to prepare the allocator, if the user
- * hasn't selected their own allocator via PHYSFS_setAllocator().
- * If the platform has a custom allocator, it should fill in the fields of
- * (a) with the proper function pointers and return non-zero.
- * If the platform just wants to use malloc()/free()/etc, return zero
- * immediately and the higher level will handle it. The Init and Deinit
- * fields of (a) are optional...set them to NULL if you don't need them.
- * Everything else must be implemented. All rules follow those for
- * PHYSFS_setAllocator(). If Init isn't NULL, it will be called shortly
- * after this function returns non-zero.
- */
-int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
-/* end of physfs_internal.h ... */
-
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/src/physfs_miniz.h
--- a/misc/physfs/src/physfs_miniz.h Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,698 +0,0 @@
-/* tinfl.c v1.11 - public domain inflate with zlib header parsing/adler32 checking (inflate-only subset of miniz.c)
- See "unlicense" statement at the end of this file.
- Rich Geldreich , last updated May 20, 2011
- Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt
-
- The entire decompressor coroutine is implemented in tinfl_decompress(). The other functions are optional high-level helpers.
-*/
-#ifndef TINFL_HEADER_INCLUDED
-#define TINFL_HEADER_INCLUDED
-
-typedef PHYSFS_uint8 mz_uint8;
-typedef PHYSFS_sint16 mz_int16;
-typedef PHYSFS_uint16 mz_uint16;
-typedef PHYSFS_uint32 mz_uint32;
-typedef unsigned int mz_uint;
-typedef PHYSFS_uint64 mz_uint64;
-
-/* For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. */
-typedef unsigned long mz_ulong;
-
-/* Heap allocation callbacks. */
-typedef void *(*mz_alloc_func)(void *opaque, unsigned int items, unsigned int size);
-typedef void (*mz_free_func)(void *opaque, void *address);
-
-#if defined(_M_IX86) || defined(_M_X64)
-/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 if integer loads and stores to unaligned addresses are acceptable on the target platform (slightly faster). */
-#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
-/* Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. */
-#define MINIZ_LITTLE_ENDIAN 1
-#endif
-
-#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__)
-/* Set MINIZ_HAS_64BIT_REGISTERS to 1 if the processor has 64-bit general purpose registers (enables 64-bit bitbuffer in inflator) */
-#define MINIZ_HAS_64BIT_REGISTERS 1
-#endif
-
-/* Works around MSVC's spammy "warning C4127: conditional expression is constant" message. */
-#ifdef _MSC_VER
-#define MZ_MACRO_END while (0, 0)
-#else
-#define MZ_MACRO_END while (0)
-#endif
-
-/* Decompression flags. */
-enum
-{
- TINFL_FLAG_PARSE_ZLIB_HEADER = 1,
- TINFL_FLAG_HAS_MORE_INPUT = 2,
- TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,
- TINFL_FLAG_COMPUTE_ADLER32 = 8
-};
-
-struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor;
-
-/* Max size of LZ dictionary. */
-#define TINFL_LZ_DICT_SIZE 32768
-
-/* Return status. */
-typedef enum
-{
- TINFL_STATUS_BAD_PARAM = -3,
- TINFL_STATUS_ADLER32_MISMATCH = -2,
- TINFL_STATUS_FAILED = -1,
- TINFL_STATUS_DONE = 0,
- TINFL_STATUS_NEEDS_MORE_INPUT = 1,
- TINFL_STATUS_HAS_MORE_OUTPUT = 2
-} tinfl_status;
-
-/* Initializes the decompressor to its initial state. */
-#define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END
-#define tinfl_get_adler32(r) (r)->m_check_adler32
-
-/* Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. */
-/* This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. */
-static tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags);
-
-/* Internal/private bits follow. */
-enum
-{
- TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19,
- TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS
-};
-
-typedef struct
-{
- mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0];
- mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2];
-} tinfl_huff_table;
-
-#if MINIZ_HAS_64BIT_REGISTERS
- #define TINFL_USE_64BIT_BITBUF 1
-#endif
-
-#if TINFL_USE_64BIT_BITBUF
- typedef mz_uint64 tinfl_bit_buf_t;
- #define TINFL_BITBUF_SIZE (64)
-#else
- typedef mz_uint32 tinfl_bit_buf_t;
- #define TINFL_BITBUF_SIZE (32)
-#endif
-
-struct tinfl_decompressor_tag
-{
- mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES];
- tinfl_bit_buf_t m_bit_buf;
- size_t m_dist_from_out_buf_start;
- tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES];
- mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137];
-};
-
-#endif /* #ifdef TINFL_HEADER_INCLUDED */
-
-/* ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.) */
-
-#ifndef TINFL_HEADER_FILE_ONLY
-
-#define MZ_MAX(a,b) (((a)>(b))?(a):(b))
-#define MZ_MIN(a,b) (((a)<(b))?(a):(b))
-#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj))
-
-#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
- #define MZ_READ_LE16(p) *((const mz_uint16 *)(p))
- #define MZ_READ_LE32(p) *((const mz_uint32 *)(p))
-#else
- #define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U))
- #define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
-#endif
-
-#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l)
-#define TINFL_MEMSET(p, c, l) memset(p, c, l)
-
-#define TINFL_CR_BEGIN switch(r->m_state) { case 0:
-#define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END
-#define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END
-#define TINFL_CR_FINISH }
-
-/* TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never */
-/* reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario. */
-#define TINFL_GET_BYTE(state_index, c) do { \
- if (pIn_buf_cur >= pIn_buf_end) { \
- for ( ; ; ) { \
- if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \
- TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \
- if (pIn_buf_cur < pIn_buf_end) { \
- c = *pIn_buf_cur++; \
- break; \
- } \
- } else { \
- c = 0; \
- break; \
- } \
- } \
- } else c = *pIn_buf_cur++; } MZ_MACRO_END
-
-#define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n))
-#define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END
-#define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END
-
-/* TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. */
-/* It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a */
-/* Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the */
-/* bit buffer contains >=15 bits (deflate's max. Huffman code size). */
-#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \
- do { \
- temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \
- if (temp >= 0) { \
- code_len = temp >> 9; \
- if ((code_len) && (num_bits >= code_len)) \
- break; \
- } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \
- code_len = TINFL_FAST_LOOKUP_BITS; \
- do { \
- temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \
- } while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \
- } TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \
- } while (num_bits < 15);
-
-/* TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read */
-/* beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully */
-/* decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. */
-/* The slow path is only executed at the very end of the input buffer. */
-#define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \
- int temp; mz_uint code_len, c; \
- if (num_bits < 15) { \
- if ((pIn_buf_end - pIn_buf_cur) < 2) { \
- TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \
- } else { \
- bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \
- } \
- } \
- if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \
- code_len = temp >> 9, temp &= 511; \
- else { \
- code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \
- } sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END
-
-static tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags)
-{
- static const int s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 };
- static const int s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
- static const int s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
- static const int s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
- static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
- static const int s_min_table_sizes[3] = { 257, 1, 4 };
-
- tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf;
- const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size;
- mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size;
- size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start;
-
- /* Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). */
- if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; }
-
- num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start;
- TINFL_CR_BEGIN
-
- bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1;
- if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
- {
- TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1);
- counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8));
- if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4)))));
- if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); }
- }
-
- do
- {
- TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1;
- if (r->m_type == 0)
- {
- TINFL_SKIP_BITS(5, num_bits & 7);
- for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); }
- if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); }
- while ((counter) && (num_bits))
- {
- TINFL_GET_BITS(51, dist, 8);
- while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); }
- *pOut_buf_cur++ = (mz_uint8)dist;
- counter--;
- }
- while (counter)
- {
- size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); }
- while (pIn_buf_cur >= pIn_buf_end)
- {
- if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT)
- {
- TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT);
- }
- else
- {
- TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED);
- }
- }
- n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter);
- TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n;
- }
- }
- else if (r->m_type == 3)
- {
- TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED);
- }
- else
- {
- if (r->m_type == 1)
- {
- mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i;
- r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32);
- for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8;
- }
- else
- {
- for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; }
- MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; }
- r->m_table_sizes[2] = 19;
- }
- for ( ; (int)r->m_type >= 0; r->m_type--)
- {
- int tree_next, tree_cur; tinfl_huff_table *pTable;
- mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree);
- for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++;
- used_syms = 0, total = 0; next_code[0] = next_code[1] = 0;
- for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); }
- if ((65536 != total) && (used_syms > 1))
- {
- TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED);
- }
- for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index)
- {
- mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue;
- cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1);
- if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; }
- if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; }
- rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1);
- for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--)
- {
- tree_cur -= ((rev_code >>= 1) & 1);
- if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1];
- }
- tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index;
- }
- if (r->m_type == 2)
- {
- for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); )
- {
- mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; }
- if ((dist == 16) && (!counter))
- {
- TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED);
- }
- num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16];
- TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s;
- }
- if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter)
- {
- TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED);
- }
- TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]);
- }
- }
- for ( ; ; )
- {
- mz_uint8 *pSrc;
- for ( ; ; )
- {
- if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2))
- {
- TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]);
- if (counter >= 256)
- break;
- while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); }
- *pOut_buf_cur++ = (mz_uint8)counter;
- }
- else
- {
- int sym2; mz_uint code_len;
-#if TINFL_USE_64BIT_BITBUF
- if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; }
-#else
- if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
-#endif
- if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
- code_len = sym2 >> 9;
- else
- {
- code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
- }
- counter = sym2; bit_buf >>= code_len; num_bits -= code_len;
- if (counter & 256)
- break;
-
-#if !TINFL_USE_64BIT_BITBUF
- if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
-#endif
- if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
- code_len = sym2 >> 9;
- else
- {
- code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
- }
- bit_buf >>= code_len; num_bits -= code_len;
-
- pOut_buf_cur[0] = (mz_uint8)counter;
- if (sym2 & 256)
- {
- pOut_buf_cur++;
- counter = sym2;
- break;
- }
- pOut_buf_cur[1] = (mz_uint8)sym2;
- pOut_buf_cur += 2;
- }
- }
- if ((counter &= 511) == 256) break;
-
- num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257];
- if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; }
-
- TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]);
- num_extra = s_dist_extra[dist]; dist = s_dist_base[dist];
- if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; }
-
- dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start;
- if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))
- {
- TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED);
- }
-
- pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask);
-
- if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end)
- {
- while (counter--)
- {
- while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); }
- *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask];
- }
- continue;
- }
-#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
- else if ((counter >= 9) && (counter <= dist))
- {
- const mz_uint8 *pSrc_end = pSrc + (counter & ~7);
- do
- {
- ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0];
- ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1];
- pOut_buf_cur += 8;
- } while ((pSrc += 8) < pSrc_end);
- if ((counter &= 7) < 3)
- {
- if (counter)
- {
- pOut_buf_cur[0] = pSrc[0];
- if (counter > 1)
- pOut_buf_cur[1] = pSrc[1];
- pOut_buf_cur += counter;
- }
- continue;
- }
- }
-#endif
- do
- {
- pOut_buf_cur[0] = pSrc[0];
- pOut_buf_cur[1] = pSrc[1];
- pOut_buf_cur[2] = pSrc[2];
- pOut_buf_cur += 3; pSrc += 3;
- } while ((int)(counter -= 3) > 2);
- if ((int)counter > 0)
- {
- pOut_buf_cur[0] = pSrc[0];
- if ((int)counter > 1)
- pOut_buf_cur[1] = pSrc[1];
- pOut_buf_cur += counter;
- }
- }
- }
- } while (!(r->m_final & 1));
- if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
- {
- TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; }
- }
- TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE);
- TINFL_CR_FINISH
-
-common_exit:
- r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start;
- *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next;
- if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0))
- {
- const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size;
- mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552;
- while (buf_len)
- {
- for (i = 0; i + 7 < block_len; i += 8, ptr += 8)
- {
- s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1;
- s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1;
- }
- for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1;
- s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552;
- }
- r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH;
- }
- return status;
-}
-
-/* Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other stuff is for advanced use. */
-enum { MZ_NO_FLUSH = 0, MZ_PARTIAL_FLUSH = 1, MZ_SYNC_FLUSH = 2, MZ_FULL_FLUSH = 3, MZ_FINISH = 4, MZ_BLOCK = 5 };
-
-/* Return status codes. MZ_PARAM_ERROR is non-standard. */
-enum { MZ_OK = 0, MZ_STREAM_END = 1, MZ_NEED_DICT = 2, MZ_ERRNO = -1, MZ_STREAM_ERROR = -2, MZ_DATA_ERROR = -3, MZ_MEM_ERROR = -4, MZ_BUF_ERROR = -5, MZ_VERSION_ERROR = -6, MZ_PARAM_ERROR = -10000 };
-
-/* Compression levels. */
-enum { MZ_NO_COMPRESSION = 0, MZ_BEST_SPEED = 1, MZ_BEST_COMPRESSION = 9, MZ_DEFAULT_COMPRESSION = -1 };
-
-/* Window bits */
-#define MZ_DEFAULT_WINDOW_BITS 15
-
-struct mz_internal_state;
-
-/* Compression/decompression stream struct. */
-typedef struct mz_stream_s
-{
- const unsigned char *next_in; /* pointer to next byte to read */
- unsigned int avail_in; /* number of bytes available at next_in */
- mz_ulong total_in; /* total number of bytes consumed so far */
-
- unsigned char *next_out; /* pointer to next byte to write */
- unsigned int avail_out; /* number of bytes that can be written to next_out */
- mz_ulong total_out; /* total number of bytes produced so far */
-
- char *msg; /* error msg (unused) */
- struct mz_internal_state *state; /* internal state, allocated by zalloc/zfree */
-
- mz_alloc_func zalloc; /* optional heap allocation function (defaults to malloc) */
- mz_free_func zfree; /* optional heap free function (defaults to free) */
- void *opaque; /* heap alloc function user pointer */
-
- int data_type; /* data_type (unused) */
- mz_ulong adler; /* adler32 of the source or uncompressed data */
- mz_ulong reserved; /* not used */
-} mz_stream;
-
-typedef mz_stream *mz_streamp;
-
-
-typedef struct
-{
- tinfl_decompressor m_decomp;
- mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; int m_window_bits;
- mz_uint8 m_dict[TINFL_LZ_DICT_SIZE];
- tinfl_status m_last_status;
-} inflate_state;
-
-static int mz_inflateInit2(mz_streamp pStream, int window_bits)
-{
- inflate_state *pDecomp;
- if (!pStream) return MZ_STREAM_ERROR;
- if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) return MZ_PARAM_ERROR;
-
- pStream->data_type = 0;
- pStream->adler = 0;
- pStream->msg = NULL;
- pStream->total_in = 0;
- pStream->total_out = 0;
- pStream->reserved = 0;
- /* if (!pStream->zalloc) pStream->zalloc = def_alloc_func; */
- /* if (!pStream->zfree) pStream->zfree = def_free_func; */
-
- pDecomp = (inflate_state*)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state));
- if (!pDecomp) return MZ_MEM_ERROR;
-
- pStream->state = (struct mz_internal_state *)pDecomp;
-
- tinfl_init(&pDecomp->m_decomp);
- pDecomp->m_dict_ofs = 0;
- pDecomp->m_dict_avail = 0;
- pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT;
- pDecomp->m_first_call = 1;
- pDecomp->m_has_flushed = 0;
- pDecomp->m_window_bits = window_bits;
-
- return MZ_OK;
-}
-
-static int mz_inflate(mz_streamp pStream, int flush)
-{
- inflate_state* pState;
- mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32;
- size_t in_bytes, out_bytes, orig_avail_in;
- tinfl_status status;
-
- if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR;
- if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH;
- if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) return MZ_STREAM_ERROR;
-
- pState = (inflate_state*)pStream->state;
- if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER;
- orig_avail_in = pStream->avail_in;
-
- first_call = pState->m_first_call; pState->m_first_call = 0;
- if (pState->m_last_status < 0) return MZ_DATA_ERROR;
-
- if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR;
- pState->m_has_flushed |= (flush == MZ_FINISH);
-
- if ((flush == MZ_FINISH) && (first_call))
- {
- /* MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. */
- decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;
- in_bytes = pStream->avail_in; out_bytes = pStream->avail_out;
- status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags);
- pState->m_last_status = status;
- pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes;
- pStream->adler = tinfl_get_adler32(&pState->m_decomp);
- pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes;
-
- if (status < 0)
- return MZ_DATA_ERROR;
- else if (status != TINFL_STATUS_DONE)
- {
- pState->m_last_status = TINFL_STATUS_FAILED;
- return MZ_BUF_ERROR;
- }
- return MZ_STREAM_END;
- }
- /* flush != MZ_FINISH then we must assume there's more input. */
- if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT;
-
- if (pState->m_dict_avail)
- {
- n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
- memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
- pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n;
- pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
- return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK;
- }
-
- for ( ; ; )
- {
- in_bytes = pStream->avail_in;
- out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs;
-
- status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags);
- pState->m_last_status = status;
-
- pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes;
- pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp);
-
- pState->m_dict_avail = (mz_uint)out_bytes;
-
- n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
- memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
- pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n;
- pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
-
- if (status < 0)
- return MZ_DATA_ERROR; /* Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). */
- else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in))
- return MZ_BUF_ERROR; /* Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. */
- else if (flush == MZ_FINISH)
- {
- /* The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. */
- if (status == TINFL_STATUS_DONE)
- return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END;
- /* status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. */
- else if (!pStream->avail_out)
- return MZ_BUF_ERROR;
- }
- else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail))
- break;
- }
-
- return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK;
-}
-
-static int mz_inflateEnd(mz_streamp pStream)
-{
- if (!pStream)
- return MZ_STREAM_ERROR;
- if (pStream->state)
- {
- pStream->zfree(pStream->opaque, pStream->state);
- pStream->state = NULL;
- }
- return MZ_OK;
-}
-
-/* make this a drop-in replacement for zlib... */
- #define voidpf void*
- #define uInt unsigned int
- #define z_stream mz_stream
- #define inflateInit2 mz_inflateInit2
- #define inflate mz_inflate
- #define inflateEnd mz_inflateEnd
- #define Z_SYNC_FLUSH MZ_SYNC_FLUSH
- #define Z_FINISH MZ_FINISH
- #define Z_OK MZ_OK
- #define Z_STREAM_END MZ_STREAM_END
- #define Z_NEED_DICT MZ_NEED_DICT
- #define Z_ERRNO MZ_ERRNO
- #define Z_STREAM_ERROR MZ_STREAM_ERROR
- #define Z_DATA_ERROR MZ_DATA_ERROR
- #define Z_MEM_ERROR MZ_MEM_ERROR
- #define Z_BUF_ERROR MZ_BUF_ERROR
- #define Z_VERSION_ERROR MZ_VERSION_ERROR
- #define MAX_WBITS 15
-
-#endif /* #ifndef TINFL_HEADER_FILE_ONLY */
-
-/*
- This is free and unencumbered software released into the public domain.
-
- Anyone is free to copy, modify, publish, use, compile, sell, or
- distribute this software, either in source code form or as a compiled
- binary, for any purpose, commercial or non-commercial, and by any
- means.
-
- In jurisdictions that recognize copyright laws, the author or authors
- of this software dedicate any and all copyright interest in the
- software to the public domain. We make this dedication for the benefit
- of the public at large and to the detriment of our heirs and
- successors. We intend this dedication to be an overt act of
- relinquishment in perpetuity of all present and future rights to this
- software under copyright law.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- OTHER DEALINGS IN THE SOFTWARE.
-
- For more information, please refer to
-*/
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/src/physfs_platforms.h
--- a/misc/physfs/src/physfs_platforms.h Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-#ifndef _INCL_PHYSFS_PLATFORMS
-#define _INCL_PHYSFS_PLATFORMS
-
-#ifndef __PHYSICSFS_INTERNAL__
-#error Do not include this header from your applications.
-#endif
-
-/*
- * These only define the platforms to determine which files in the platforms
- * directory should be compiled. For example, technically BeOS can be called
- * a "unix" system, but since it doesn't use unix.c, we don't define
- * PHYSFS_PLATFORM_UNIX on that system.
- */
-
-#if (defined __HAIKU__)
-# define PHYSFS_PLATFORM_HAIKU 1
-# define PHYSFS_PLATFORM_BEOS 1
-# define PHYSFS_PLATFORM_POSIX 1
-#elif ((defined __BEOS__) || (defined __beos__))
-# define PHYSFS_PLATFORM_BEOS 1
-# define PHYSFS_PLATFORM_POSIX 1
-#elif (defined _WIN32_WCE) || (defined _WIN64_WCE)
-# error PocketPC support was dropped from PhysicsFS 2.1. Sorry.
-#elif (((defined _WIN32) || (defined _WIN64)) && (!defined __CYGWIN__))
-# define PHYSFS_PLATFORM_WINDOWS 1
-#elif (defined OS2)
-# error OS/2 support was dropped from PhysicsFS 2.1. Sorry.
-#elif ((defined __MACH__) && (defined __APPLE__))
-/* To check if iphone or not, we need to include this file */
-# include
-# if ((TARGET_IPHONE_SIMULATOR) || (TARGET_OS_IPHONE))
-# define PHYSFS_NO_CDROM_SUPPORT 1
-# endif
-# define PHYSFS_PLATFORM_MACOSX 1
-# define PHYSFS_PLATFORM_POSIX 1
-#elif defined(macintosh)
-# error Classic Mac OS support was dropped from PhysicsFS 2.0. Move to OS X.
-#elif defined(__linux)
-# define PHYSFS_PLATFORM_LINUX 1
-# define PHYSFS_PLATFORM_UNIX 1
-# define PHYSFS_PLATFORM_POSIX 1
-#elif defined(__sun) || defined(sun)
-# define PHYSFS_PLATFORM_SOLARIS 1
-# define PHYSFS_PLATFORM_UNIX 1
-# define PHYSFS_PLATFORM_POSIX 1
-#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__)
-# define PHYSFS_PLATFORM_BSD 1
-# define PHYSFS_PLATFORM_UNIX 1
-# define PHYSFS_PLATFORM_POSIX 1
-#elif defined(unix) || defined(__unix__)
-# define PHYSFS_PLATFORM_UNIX 1
-# define PHYSFS_PLATFORM_POSIX 1
-#else
-# error Unknown platform.
-#endif
-
-#endif /* include-once blocker. */
-
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/src/physfs_unicode.c
--- a/misc/physfs/src/physfs_unicode.c Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,528 +0,0 @@
-#define __PHYSICSFS_INTERNAL__
-#include "physfs_internal.h"
-
-
-/*
- * From rfc3629, the UTF-8 spec:
- * http://www.ietf.org/rfc/rfc3629.txt
- *
- * Char. number range | UTF-8 octet sequence
- * (hexadecimal) | (binary)
- * --------------------+---------------------------------------------
- * 0000 0000-0000 007F | 0xxxxxxx
- * 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
- * 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
- * 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
- */
-
-
-/*
- * This may not be the best value, but it's one that isn't represented
- * in Unicode (0x10FFFF is the largest codepoint value). We return this
- * value from utf8codepoint() if there's bogus bits in the
- * stream. utf8codepoint() will turn this value into something
- * reasonable (like a question mark), for text that wants to try to recover,
- * whereas utf8valid() will use the value to determine if a string has bad
- * bits.
- */
-#define UNICODE_BOGUS_CHAR_VALUE 0xFFFFFFFF
-
-/*
- * This is the codepoint we currently return when there was bogus bits in a
- * UTF-8 string. May not fly in Asian locales?
- */
-#define UNICODE_BOGUS_CHAR_CODEPOINT '?'
-
-static PHYSFS_uint32 utf8codepoint(const char **_str)
-{
- const char *str = *_str;
- PHYSFS_uint32 retval = 0;
- PHYSFS_uint32 octet = (PHYSFS_uint32) ((PHYSFS_uint8) *str);
- PHYSFS_uint32 octet2, octet3, octet4;
-
- if (octet == 0) /* null terminator, end of string. */
- return 0;
-
- else if (octet < 128) /* one octet char: 0 to 127 */
- {
- (*_str)++; /* skip to next possible start of codepoint. */
- return octet;
- } /* else if */
-
- else if ((octet > 127) && (octet < 192)) /* bad (starts with 10xxxxxx). */
- {
- /*
- * Apparently each of these is supposed to be flagged as a bogus
- * char, instead of just resyncing to the next valid codepoint.
- */
- (*_str)++; /* skip to next possible start of codepoint. */
- return UNICODE_BOGUS_CHAR_VALUE;
- } /* else if */
-
- else if (octet < 224) /* two octets */
- {
- (*_str)++; /* advance at least one byte in case of an error */
- octet -= (128+64);
- octet2 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
- if ((octet2 & (128+64)) != 128) /* Format isn't 10xxxxxx? */
- return UNICODE_BOGUS_CHAR_VALUE;
-
- *_str += 1; /* skip to next possible start of codepoint. */
- retval = ((octet << 6) | (octet2 - 128));
- if ((retval >= 0x80) && (retval <= 0x7FF))
- return retval;
- } /* else if */
-
- else if (octet < 240) /* three octets */
- {
- (*_str)++; /* advance at least one byte in case of an error */
- octet -= (128+64+32);
- octet2 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
- if ((octet2 & (128+64)) != 128) /* Format isn't 10xxxxxx? */
- return UNICODE_BOGUS_CHAR_VALUE;
-
- octet3 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
- if ((octet3 & (128+64)) != 128) /* Format isn't 10xxxxxx? */
- return UNICODE_BOGUS_CHAR_VALUE;
-
- *_str += 2; /* skip to next possible start of codepoint. */
- retval = ( ((octet << 12)) | ((octet2-128) << 6) | ((octet3-128)) );
-
- /* There are seven "UTF-16 surrogates" that are illegal in UTF-8. */
- switch (retval)
- {
- case 0xD800:
- case 0xDB7F:
- case 0xDB80:
- case 0xDBFF:
- case 0xDC00:
- case 0xDF80:
- case 0xDFFF:
- return UNICODE_BOGUS_CHAR_VALUE;
- } /* switch */
-
- /* 0xFFFE and 0xFFFF are illegal, too, so we check them at the edge. */
- if ((retval >= 0x800) && (retval <= 0xFFFD))
- return retval;
- } /* else if */
-
- else if (octet < 248) /* four octets */
- {
- (*_str)++; /* advance at least one byte in case of an error */
- octet -= (128+64+32+16);
- octet2 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
- if ((octet2 & (128+64)) != 128) /* Format isn't 10xxxxxx? */
- return UNICODE_BOGUS_CHAR_VALUE;
-
- octet3 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
- if ((octet3 & (128+64)) != 128) /* Format isn't 10xxxxxx? */
- return UNICODE_BOGUS_CHAR_VALUE;
-
- octet4 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
- if ((octet4 & (128+64)) != 128) /* Format isn't 10xxxxxx? */
- return UNICODE_BOGUS_CHAR_VALUE;
-
- *_str += 3; /* skip to next possible start of codepoint. */
- retval = ( ((octet << 18)) | ((octet2 - 128) << 12) |
- ((octet3 - 128) << 6) | ((octet4 - 128)) );
- if ((retval >= 0x10000) && (retval <= 0x10FFFF))
- return retval;
- } /* else if */
-
- /*
- * Five and six octet sequences became illegal in rfc3629.
- * We throw the codepoint away, but parse them to make sure we move
- * ahead the right number of bytes and don't overflow the buffer.
- */
-
- else if (octet < 252) /* five octets */
- {
- (*_str)++; /* advance at least one byte in case of an error */
- octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
- if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */
- return UNICODE_BOGUS_CHAR_VALUE;
-
- octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
- if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */
- return UNICODE_BOGUS_CHAR_VALUE;
-
- octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
- if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */
- return UNICODE_BOGUS_CHAR_VALUE;
-
- octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
- if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */
- return UNICODE_BOGUS_CHAR_VALUE;
-
- *_str += 4; /* skip to next possible start of codepoint. */
- return UNICODE_BOGUS_CHAR_VALUE;
- } /* else if */
-
- else /* six octets */
- {
- (*_str)++; /* advance at least one byte in case of an error */
- octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
- if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */
- return UNICODE_BOGUS_CHAR_VALUE;
-
- octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
- if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */
- return UNICODE_BOGUS_CHAR_VALUE;
-
- octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
- if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */
- return UNICODE_BOGUS_CHAR_VALUE;
-
- octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
- if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */
- return UNICODE_BOGUS_CHAR_VALUE;
-
- octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
- if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */
- return UNICODE_BOGUS_CHAR_VALUE;
-
- *_str += 6; /* skip to next possible start of codepoint. */
- return UNICODE_BOGUS_CHAR_VALUE;
- } /* else if */
-
- return UNICODE_BOGUS_CHAR_VALUE;
-} /* utf8codepoint */
-
-
-void PHYSFS_utf8ToUcs4(const char *src, PHYSFS_uint32 *dst, PHYSFS_uint64 len)
-{
- len -= sizeof (PHYSFS_uint32); /* save room for null char. */
- while (len >= sizeof (PHYSFS_uint32))
- {
- PHYSFS_uint32 cp = utf8codepoint(&src);
- if (cp == 0)
- break;
- else if (cp == UNICODE_BOGUS_CHAR_VALUE)
- cp = UNICODE_BOGUS_CHAR_CODEPOINT;
- *(dst++) = cp;
- len -= sizeof (PHYSFS_uint32);
- } /* while */
-
- *dst = 0;
-} /* PHYSFS_utf8ToUcs4 */
-
-
-void PHYSFS_utf8ToUcs2(const char *src, PHYSFS_uint16 *dst, PHYSFS_uint64 len)
-{
- len -= sizeof (PHYSFS_uint16); /* save room for null char. */
- while (len >= sizeof (PHYSFS_uint16))
- {
- PHYSFS_uint32 cp = utf8codepoint(&src);
- if (cp == 0)
- break;
- else if (cp == UNICODE_BOGUS_CHAR_VALUE)
- cp = UNICODE_BOGUS_CHAR_CODEPOINT;
-
- if (cp > 0xFFFF) /* UTF-16 surrogates (bogus chars in UCS-2) */
- cp = UNICODE_BOGUS_CHAR_CODEPOINT;
-
- *(dst++) = cp;
- len -= sizeof (PHYSFS_uint16);
- } /* while */
-
- *dst = 0;
-} /* PHYSFS_utf8ToUcs2 */
-
-
-void PHYSFS_utf8ToUtf16(const char *src, PHYSFS_uint16 *dst, PHYSFS_uint64 len)
-{
- len -= sizeof (PHYSFS_uint16); /* save room for null char. */
- while (len >= sizeof (PHYSFS_uint16))
- {
- PHYSFS_uint32 cp = utf8codepoint(&src);
- if (cp == 0)
- break;
- else if (cp == UNICODE_BOGUS_CHAR_VALUE)
- cp = UNICODE_BOGUS_CHAR_CODEPOINT;
-
- if (cp > 0xFFFF) /* encode as surrogate pair */
- {
- if (len < (sizeof (PHYSFS_uint16) * 2))
- break; /* not enough room for the pair, stop now. */
-
- cp -= 0x10000; /* Make this a 20-bit value */
-
- *(dst++) = 0xD800 + ((cp >> 10) & 0x3FF);
- len -= sizeof (PHYSFS_uint16);
-
- cp = 0xDC00 + (cp & 0x3FF);
- } /* if */
-
- *(dst++) = cp;
- len -= sizeof (PHYSFS_uint16);
- } /* while */
-
- *dst = 0;
-} /* PHYSFS_utf8ToUtf16 */
-
-static void utf8fromcodepoint(PHYSFS_uint32 cp, char **_dst, PHYSFS_uint64 *_len)
-{
- char *dst = *_dst;
- PHYSFS_uint64 len = *_len;
-
- if (len == 0)
- return;
-
- if (cp > 0x10FFFF)
- cp = UNICODE_BOGUS_CHAR_CODEPOINT;
- else if ((cp == 0xFFFE) || (cp == 0xFFFF)) /* illegal values. */
- cp = UNICODE_BOGUS_CHAR_CODEPOINT;
- else
- {
- /* There are seven "UTF-16 surrogates" that are illegal in UTF-8. */
- switch (cp)
- {
- case 0xD800:
- case 0xDB7F:
- case 0xDB80:
- case 0xDBFF:
- case 0xDC00:
- case 0xDF80:
- case 0xDFFF:
- cp = UNICODE_BOGUS_CHAR_CODEPOINT;
- } /* switch */
- } /* else */
-
- /* Do the encoding... */
- if (cp < 0x80)
- {
- *(dst++) = (char) cp;
- len--;
- } /* if */
-
- else if (cp < 0x800)
- {
- if (len < 2)
- len = 0;
- else
- {
- *(dst++) = (char) ((cp >> 6) | 128 | 64);
- *(dst++) = (char) (cp & 0x3F) | 128;
- len -= 2;
- } /* else */
- } /* else if */
-
- else if (cp < 0x10000)
- {
- if (len < 3)
- len = 0;
- else
- {
- *(dst++) = (char) ((cp >> 12) | 128 | 64 | 32);
- *(dst++) = (char) ((cp >> 6) & 0x3F) | 128;
- *(dst++) = (char) (cp & 0x3F) | 128;
- len -= 3;
- } /* else */
- } /* else if */
-
- else
- {
- if (len < 4)
- len = 0;
- else
- {
- *(dst++) = (char) ((cp >> 18) | 128 | 64 | 32 | 16);
- *(dst++) = (char) ((cp >> 12) & 0x3F) | 128;
- *(dst++) = (char) ((cp >> 6) & 0x3F) | 128;
- *(dst++) = (char) (cp & 0x3F) | 128;
- len -= 4;
- } /* else if */
- } /* else */
-
- *_dst = dst;
- *_len = len;
-} /* utf8fromcodepoint */
-
-#define UTF8FROMTYPE(typ, src, dst, len) \
- if (len == 0) return; \
- len--; \
- while (len) \
- { \
- const PHYSFS_uint32 cp = (PHYSFS_uint32) ((typ) (*(src++))); \
- if (cp == 0) break; \
- utf8fromcodepoint(cp, &dst, &len); \
- } \
- *dst = '\0'; \
-
-void PHYSFS_utf8FromUcs4(const PHYSFS_uint32 *src, char *dst, PHYSFS_uint64 len)
-{
- UTF8FROMTYPE(PHYSFS_uint32, src, dst, len);
-} /* PHYSFS_utf8FromUcs4 */
-
-void PHYSFS_utf8FromUcs2(const PHYSFS_uint16 *src, char *dst, PHYSFS_uint64 len)
-{
- UTF8FROMTYPE(PHYSFS_uint64, src, dst, len);
-} /* PHYSFS_utf8FromUcs2 */
-
-/* latin1 maps to unicode codepoints directly, we just utf-8 encode it. */
-void PHYSFS_utf8FromLatin1(const char *src, char *dst, PHYSFS_uint64 len)
-{
- UTF8FROMTYPE(PHYSFS_uint8, src, dst, len);
-} /* PHYSFS_utf8FromLatin1 */
-
-#undef UTF8FROMTYPE
-
-
-void PHYSFS_utf8FromUtf16(const PHYSFS_uint16 *src, char *dst, PHYSFS_uint64 len)
-{
- if (len == 0)
- return;
-
- len--;
- while (len)
- {
- PHYSFS_uint32 cp = (PHYSFS_uint32) *(src++);
- if (cp == 0)
- break;
-
- /* Orphaned second half of surrogate pair? */
- if ((cp >= 0xDC00) && (cp <= 0xDFFF))
- cp = UNICODE_BOGUS_CHAR_CODEPOINT;
- else if ((cp >= 0xD800) && (cp <= 0xDBFF)) /* start surrogate pair! */
- {
- const PHYSFS_uint32 pair = (PHYSFS_uint32) *src;
- if ((pair < 0xDC00) || (pair > 0xDFFF))
- cp = UNICODE_BOGUS_CHAR_CODEPOINT;
- else
- {
- src++; /* eat the other surrogate. */
- cp = (((cp - 0xD800) << 10) | (pair - 0xDC00));
- } /* else */
- } /* else if */
-
- utf8fromcodepoint(cp, &dst, &len);
- } /* while */
-
- *dst = '\0';
-} /* PHYSFS_utf8FromUtf16 */
-
-
-typedef struct CaseFoldMapping
-{
- PHYSFS_uint32 from;
- PHYSFS_uint32 to0;
- PHYSFS_uint32 to1;
- PHYSFS_uint32 to2;
-} CaseFoldMapping;
-
-typedef struct CaseFoldHashBucket
-{
- const PHYSFS_uint8 count;
- const CaseFoldMapping *list;
-} CaseFoldHashBucket;
-
-#include "physfs_casefolding.h"
-
-static void locate_case_fold_mapping(const PHYSFS_uint32 from,
- PHYSFS_uint32 *to)
-{
- PHYSFS_uint32 i;
- const PHYSFS_uint8 hashed = ((from ^ (from >> 8)) & 0xFF);
- const CaseFoldHashBucket *bucket = &case_fold_hash[hashed];
- const CaseFoldMapping *mapping = bucket->list;
-
- for (i = 0; i < bucket->count; i++, mapping++)
- {
- if (mapping->from == from)
- {
- to[0] = mapping->to0;
- to[1] = mapping->to1;
- to[2] = mapping->to2;
- return;
- } /* if */
- } /* for */
-
- /* Not found...there's no remapping for this codepoint. */
- to[0] = from;
- to[1] = 0;
- to[2] = 0;
-} /* locate_case_fold_mapping */
-
-
-static int utf8codepointcmp(const PHYSFS_uint32 cp1, const PHYSFS_uint32 cp2)
-{
- PHYSFS_uint32 folded1[3], folded2[3];
- locate_case_fold_mapping(cp1, folded1);
- locate_case_fold_mapping(cp2, folded2);
- return ( (folded1[0] == folded2[0]) &&
- (folded1[1] == folded2[1]) &&
- (folded1[2] == folded2[2]) );
-} /* utf8codepointcmp */
-
-
-int __PHYSFS_utf8stricmp(const char *str1, const char *str2)
-{
- while (1)
- {
- const PHYSFS_uint32 cp1 = utf8codepoint(&str1);
- const PHYSFS_uint32 cp2 = utf8codepoint(&str2);
- if (!utf8codepointcmp(cp1, cp2)) break;
- if (cp1 == 0) return 1;
- } /* while */
-
- return 0;
-} /* __PHYSFS_utf8stricmp */
-
-
-int __PHYSFS_utf8strnicmp(const char *str1, const char *str2, PHYSFS_uint32 n)
-{
- while (n > 0)
- {
- const PHYSFS_uint32 cp1 = utf8codepoint(&str1);
- const PHYSFS_uint32 cp2 = utf8codepoint(&str2);
- if (!utf8codepointcmp(cp1, cp2)) return 0;
- if (cp1 == 0) return 1;
- n--;
- } /* while */
-
- return 1; /* matched to n chars. */
-} /* __PHYSFS_utf8strnicmp */
-
-
-int __PHYSFS_stricmpASCII(const char *str1, const char *str2)
-{
- while (1)
- {
- const char ch1 = *(str1++);
- const char ch2 = *(str2++);
- const char cp1 = ((ch1 >= 'A') && (ch1 <= 'Z')) ? (ch1+32) : ch1;
- const char cp2 = ((ch2 >= 'A') && (ch2 <= 'Z')) ? (ch2+32) : ch2;
- if (cp1 < cp2)
- return -1;
- else if (cp1 > cp2)
- return 1;
- else if (cp1 == 0) /* they're both null chars? */
- break;
- } /* while */
-
- return 0;
-} /* __PHYSFS_stricmpASCII */
-
-
-int __PHYSFS_strnicmpASCII(const char *str1, const char *str2, PHYSFS_uint32 n)
-{
- while (n-- > 0)
- {
- const char ch1 = *(str1++);
- const char ch2 = *(str2++);
- const char cp1 = ((ch1 >= 'A') && (ch1 <= 'Z')) ? (ch1+32) : ch1;
- const char cp2 = ((ch2 >= 'A') && (ch2 <= 'Z')) ? (ch2+32) : ch2;
- if (cp1 < cp2)
- return -1;
- else if (cp1 > cp2)
- return 1;
- else if (cp1 == 0) /* they're both null chars? */
- return 0;
- } /* while */
-
- return 0;
-} /* __PHYSFS_strnicmpASCII */
-
-
-/* end of physfs_unicode.c ... */
-
diff -r 404ddce27b23 -r c13ebed437cb misc/physfs/src/platform_beos.cpp
--- a/misc/physfs/src/platform_beos.cpp Wed Feb 20 02:21:58 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,239 +0,0 @@
-/*
- * BeOS platform-dependent support routines for PhysicsFS.
- *
- * Please see the file LICENSE.txt in the source's root directory.
- *
- * This file written by Ryan C. Gordon.
- */
-
-#define __PHYSICSFS_INTERNAL__
-#include "physfs_platforms.h"
-
-#ifdef PHYSFS_PLATFORM_BEOS
-
-#ifdef PHYSFS_PLATFORM_HAIKU
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include