# 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.

" - "

" + "

%1

" + "

%2

" + "

%3 known bugs

" + "

%4

" + "

") + .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 . ((:) "") . (flip (++) ["
"]) - . 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 . ((:) "") . (flip (++) ["
"]) + . 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 -#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/physfs/src/platform_macosx.c --- a/misc/physfs/src/platform_macosx.c Wed Feb 20 02:21:58 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,326 +0,0 @@ -/* - * 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/physfs/src/platform_posix.c --- a/misc/physfs/src/platform_posix.c Wed Feb 20 02:21:58 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,479 +0,0 @@ -/* - * 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/physfs/src/platform_unix.c --- a/misc/physfs/src/platform_unix.c Wed Feb 20 02:21:58 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,344 +0,0 @@ -/* - * 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/physfs/src/platform_windows.c --- a/misc/physfs/src/platform_windows.c Wed Feb 20 02:21:58 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,936 +0,0 @@ -/* - * 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/winutils/lib/libSDL_image.dll.a Binary file misc/winutils/lib/libSDL_image.dll.a has changed diff -r 404ddce27b23 -r c13ebed437cb misc/winutils/lib/libSDL_mixer.dll.a Binary file misc/winutils/lib/libSDL_mixer.dll.a has changed diff -r 404ddce27b23 -r c13ebed437cb project_files/Android-build/SDL-android-project/jni/jnidispatch/Android.mk --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/Android-build/SDL-android-project/jni/jnidispatch/Android.mk Tue Apr 02 21:00:57 2013 +0200 @@ -0,0 +1,6 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := libjnidispatch +LOCAL_SRC_FILES := libjnidispatch.so +include $(PREBUILT_SHARED_LIBRARY) \ No newline at end of file diff -r 404ddce27b23 -r c13ebed437cb project_files/Android-build/SDL-android-project/jni/jnidispatch/README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/Android-build/SDL-android-project/jni/jnidispatch/README Tue Apr 02 21:00:57 2013 +0200 @@ -0,0 +1,1 @@ +This library is part of JNA and just needs to be copied into the libs/armeabi folder. However, putting it there directly will get it cleaned away on build. \ No newline at end of file diff -r 404ddce27b23 -r c13ebed437cb project_files/Android-build/SDL-android-project/jni/jnidispatch/libjnidispatch.so Binary file project_files/Android-build/SDL-android-project/jni/jnidispatch/libjnidispatch.so has changed diff -r 404ddce27b23 -r c13ebed437cb project_files/Android-build/SDL-android-project/jni/src/hedgewars_main.c --- a/project_files/Android-build/SDL-android-project/jni/src/hedgewars_main.c Wed Feb 20 02:21:58 2013 +0100 +++ b/project_files/Android-build/SDL-android-project/jni/src/hedgewars_main.c Tue Apr 02 21:00:57 2013 +0200 @@ -1,3 +1,4 @@ +#include #include "android/log.h" #include "SDL.h" @@ -6,7 +7,7 @@ #define TAG "HWEngine Loader" -typedef (*HWEngine_Game)(char**); +typedef (*HWEngine_Game)(int32_t argc, char** argv); main(int argc, char *argv[]){ void *handle; @@ -33,7 +34,7 @@ exit(EXIT_FAILURE); } __android_log_print(ANDROID_LOG_INFO, TAG, "dlsym succeeded"); - Game(argv); + Game(argc, argv); __android_log_print(ANDROID_LOG_INFO, TAG, "Game() ended"); dlclose(handle); diff -r 404ddce27b23 -r c13ebed437cb project_files/Android-build/SDL-android-project/libs/armeabi/libjnidispatch.so Binary file project_files/Android-build/SDL-android-project/libs/armeabi/libjnidispatch.so has changed diff -r 404ddce27b23 -r c13ebed437cb project_files/Android-build/SDL-android-project/libs/jna-3.5.1.jar Binary file project_files/Android-build/SDL-android-project/libs/jna-3.5.1.jar has changed diff -r 404ddce27b23 -r c13ebed437cb project_files/Android-build/SDL-android-project/libs/jna.jar Binary file project_files/Android-build/SDL-android-project/libs/jna.jar has changed diff -r 404ddce27b23 -r c13ebed437cb project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/EngineProtocol/PascalExports.java --- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/EngineProtocol/PascalExports.java Wed Feb 20 02:21:58 2013 +0100 +++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/EngineProtocol/PascalExports.java Tue Apr 02 21:00:57 2013 +0200 @@ -32,7 +32,7 @@ System.loadLibrary("SDL_ttf"); System.loadLibrary("lua5.1"); System.loadLibrary("physfs"); - System.loadLibrary("physfsrwops"); + System.loadLibrary("physlayer"); System.loadLibrary("hwengine"); } diff -r 404ddce27b23 -r c13ebed437cb project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/frontlib/Frontlib.java --- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/frontlib/Frontlib.java Wed Feb 20 02:21:58 2013 +0100 +++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/frontlib/Frontlib.java Tue Apr 02 21:00:57 2013 +0200 @@ -21,6 +21,7 @@ package org.hedgewars.hedgeroid.frontlib; import java.io.UnsupportedEncodingException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -350,10 +351,14 @@ static class HogStruct extends Structure { public static class ByVal extends HogStruct implements Structure.ByValue {} public static class ByRef extends HogStruct implements Structure.ByReference {} - private static String[] FIELD_ORDER = new String[] {"name", "hat", "rounds", "kills", "deaths", "suicides", "difficulty", "initialHealth", "weaponset"}; - public HogStruct() { super(); setFieldOrder(FIELD_ORDER); } - public HogStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); } + public HogStruct() { super(); } + public HogStruct(Pointer ptr) { super(ptr); } + + @Override + protected List getFieldOrder() { + return Arrays.asList("name", "hat", "rounds", "kills", "deaths", "suicides", "difficulty", "initialHealth", "weaponset"); + } public void fillFrom(Hog hog) { difficulty = hog.level; @@ -382,10 +387,14 @@ static class TeamStruct extends Structure { public static class ByVal extends TeamStruct implements Structure.ByValue {} public static class ByRef extends TeamStruct implements Structure.ByReference {} - private static String[] FIELD_ORDER = new String[] {"hogs", "name", "grave", "fort", "voicepack", "flag", "bindings", "bindingCount", "rounds", "wins", "campaignProgress", "colorIndex", "hogsInGame", "remoteDriven", "ownerName"}; - public TeamStruct() { super(); setFieldOrder(FIELD_ORDER); } - public TeamStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); } + public TeamStruct() { super(); } + public TeamStruct(Pointer ptr) { super(ptr); } + + @Override + protected List getFieldOrder() { + return Arrays.asList("hogs", "name", "grave", "fort", "voicepack", "flag", "bindings", "bindingCount", "rounds", "wins", "campaignProgress", "colorIndex", "hogsInGame", "remoteDriven", "ownerName"); + } public void fillFrom(Team team, TeamIngameAttributes attrs) { if(team != null) { @@ -458,10 +467,14 @@ static class WeaponsetStruct extends Structure { public static class ByVal extends WeaponsetStruct implements Structure.ByValue {} public static class ByRef extends WeaponsetStruct implements Structure.ByReference {} - private static String[] FIELD_ORDER = new String[] {"loadout", "crateprob", "crateammo", "delay", "name"}; + + public WeaponsetStruct() { super(); } + public WeaponsetStruct(Pointer ptr) { super(ptr); } - public WeaponsetStruct() { super(); setFieldOrder(FIELD_ORDER); } - public WeaponsetStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); } + @Override + protected List getFieldOrder() { + return Arrays.asList("loadout", "crateprob", "crateammo", "delay", "name"); + } public void fillFrom(Weaponset weaponset) { fillWeaponInfo(loadout, weaponset.loadout); @@ -501,10 +514,13 @@ * Represents a flib_weaponset*, for use as part of a flib_weaponset** */ static class WeaponsetPointerByReference extends Structure implements Structure.ByReference { - private static String[] FIELD_ORDER = new String[] {"weaponset"}; + public WeaponsetPointerByReference() { super(); } + public WeaponsetPointerByReference(Pointer ptr) { super(ptr); } - public WeaponsetPointerByReference() { super(); setFieldOrder(FIELD_ORDER); } - public WeaponsetPointerByReference(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); } + @Override + protected List getFieldOrder() { + return Arrays.asList("weaponset"); + } public WeaponsetStruct.ByRef weaponset; } @@ -512,10 +528,14 @@ static class WeaponsetListStruct extends Structure { public static class ByVal extends WeaponsetListStruct implements Structure.ByValue {} public static class ByRef extends WeaponsetListStruct implements Structure.ByReference {} - private static String[] FIELD_ORDER = new String[] {"weaponsetCount", "weaponsets"}; + + public WeaponsetListStruct() { super(); } + public WeaponsetListStruct(Pointer ptr) { super(ptr); } - public WeaponsetListStruct() { super(); setFieldOrder(FIELD_ORDER); } - public WeaponsetListStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); } + @Override + protected List getFieldOrder() { + return Arrays.asList("weaponsetCount", "weaponsets"); + } public void fillFrom(List list) { weaponsetCount = list.size(); @@ -560,11 +580,15 @@ static class RoomStruct extends Structure { public static class ByVal extends RoomStruct implements Structure.ByValue {} public static class ByRef extends RoomStruct implements Structure.ByReference {} - private static String[] FIELD_ORDER = new String[] {"inProgress", "name", "playerCount", "teamCount", "owner", "map", "scheme", "weapons"}; - public RoomStruct() { super(); setFieldOrder(FIELD_ORDER); } - public RoomStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); } + public RoomStruct() { super(); } + public RoomStruct(Pointer ptr) { super(ptr); } + @Override + protected List getFieldOrder() { + return Arrays.asList("inProgress", "name", "playerCount", "teamCount", "owner", "map", "scheme", "weapons"); + } + public Room toRoomlistRoom() { return new Room(name, map, scheme, weapons, owner, playerCount, teamCount, inProgress); } @@ -582,10 +606,14 @@ static class MapRecipeStruct extends Structure { public static class ByVal extends MapRecipeStruct implements Structure.ByValue {} public static class ByRef extends MapRecipeStruct implements Structure.ByReference {} - private static String[] FIELD_ORDER = new String[] {"mapgen", "name", "seed", "theme", "drawData", "drawDataSize", "templateFilter", "mazeSize"}; + + public MapRecipeStruct() { super(); } + public MapRecipeStruct(Pointer ptr) { super(ptr); } - public MapRecipeStruct() { super(); setFieldOrder(FIELD_ORDER); } - public MapRecipeStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); } + @Override + protected List getFieldOrder() { + return Arrays.asList("mapgen", "name", "seed", "theme", "drawData", "drawDataSize", "templateFilter", "mazeSize"); + } public void fillFrom(MapRecipe map) { mapgen = map.mapgen; @@ -593,24 +621,14 @@ seed = map.seed; theme = map.theme; byte[] buf = map.getDrawData(); - if(buf==null || buf.length==0) { - drawData = null; - } else { - drawData = ByteArrayPtr.createJavaOwned(buf).getPointer(); - } + drawData = ByteArrayPtr.createJavaOwned(buf); drawDataSize = NativeSizeT.valueOf(buf==null ? 0 : buf.length); templateFilter = map.templateFilter; mazeSize = map.mazeSize; } public MapRecipe toMapRecipe() { - byte[] buf; - int size = drawDataSize.intValue(); - if(size>0) { - buf = drawData.getByteArray(0, size); - } else { - buf = null; - } + byte[] buf = ByteArrayPtr.deref(drawData, drawDataSize.intValue()); return new MapRecipe(mapgen, templateFilter, mazeSize, name, seed, theme, buf); } @@ -618,7 +636,7 @@ public String name; public String seed; public String theme; - public Pointer drawData; // We can't use ByteArrayPtr in a struct because JNA will overwrite the value with NULL - probably a bug. + public ByteArrayPtr drawData; public NativeSizeT drawDataSize; public int templateFilter; public int mazeSize; @@ -627,10 +645,14 @@ static class MetaschemeSettingStruct extends Structure { public static class ByVal extends MetaschemeSettingStruct implements Structure.ByValue {} public static class ByRef extends MetaschemeSettingStruct implements Structure.ByReference {} - private static String[] FIELD_ORDER = new String[] {"name", "engineCommand", "maxMeansInfinity", "times1000", "min", "max", "def"}; + + public MetaschemeSettingStruct() { super(); } + public MetaschemeSettingStruct(Pointer ptr) { super(ptr); } - public MetaschemeSettingStruct() { super(); setFieldOrder(FIELD_ORDER); } - public MetaschemeSettingStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); } + @Override + protected List getFieldOrder() { + return Arrays.asList("name", "engineCommand", "maxMeansInfinity", "times1000", "min", "max", "def"); + } public void fillFrom(Setting setting) { name = setting.name; @@ -658,10 +680,14 @@ static class MetaschemeModStruct extends Structure { public static class ByVal extends MetaschemeModStruct implements Structure.ByValue {} public static class ByRef extends MetaschemeModStruct implements Structure.ByReference {} - private static String[] FIELD_ORDER = new String[] {"name", "bitmaskIndex"}; + + public MetaschemeModStruct() { super(); } + public MetaschemeModStruct(Pointer ptr) { super(ptr); } - public MetaschemeModStruct() { super(); setFieldOrder(FIELD_ORDER); } - public MetaschemeModStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); } + @Override + protected List getFieldOrder() { + return Arrays.asList("name", "bitmaskIndex"); + } public void fillFrom(Mod mod) { name = mod.name; @@ -681,10 +707,13 @@ public static class ByVal extends MetaschemeStruct implements Structure.ByValue {} public static class ByRef extends MetaschemeStruct implements Structure.ByReference {} - private static String[] FIELD_ORDER = new String[] {"settingCount", "modCount", "settings", "mods"}; + public MetaschemeStruct() { super(); } + public MetaschemeStruct(Pointer ptr) { super(ptr); } - public MetaschemeStruct() { super(); setFieldOrder(FIELD_ORDER); } - public MetaschemeStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); } + @Override + protected List getFieldOrder() { + return Arrays.asList("settingCount", "modCount", "settings", "mods"); + } /** * Only use on native-owned structs! @@ -720,10 +749,14 @@ static class SchemeStruct extends Structure { public static class ByVal extends SchemeStruct implements Structure.ByValue {} public static class ByRef extends SchemeStruct implements Structure.ByReference {} - private static String[] FIELD_ORDER = new String[] {"name", "settings", "mod"}; + + public SchemeStruct() { super(); } + public SchemeStruct(Pointer ptr) { super(ptr); } - public SchemeStruct() { super(); setFieldOrder(FIELD_ORDER); } - public SchemeStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); } + @Override + protected List getFieldOrder() { + return Arrays.asList("name", "settings", "mods"); + } public void fillFrom(Scheme scheme) { MetaScheme meta = MetaScheme.INSTANCE; @@ -762,10 +795,13 @@ * Represents a flib_scheme*, for use as part of a flib_scheme** */ static class SchemePointerByReference extends Structure implements Structure.ByReference { - private static String[] FIELD_ORDER = new String[] {"scheme"}; + public SchemePointerByReference() { super(); } + public SchemePointerByReference(Pointer ptr) { super(ptr); } - public SchemePointerByReference() { super(); setFieldOrder(FIELD_ORDER); } - public SchemePointerByReference(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); } + @Override + protected List getFieldOrder() { + return Arrays.asList("scheme"); + } public SchemeStruct.ByRef scheme; } @@ -773,10 +809,14 @@ static class SchemelistStruct extends Structure { public static class ByVal extends SchemelistStruct implements Structure.ByValue {} public static class ByRef extends SchemelistStruct implements Structure.ByReference {} - private static String[] FIELD_ORDER = new String[] {"schemeCount", "schemes"}; + + public SchemelistStruct() { super(); } + public SchemelistStruct(Pointer ptr) { super(ptr); } - public SchemelistStruct() { super(); setFieldOrder(FIELD_ORDER); } - public SchemelistStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); } + @Override + protected List getFieldOrder() { + return Arrays.asList("schemeCount", "schemes"); + } public void fillFrom(List schemeList) { schemeCount = schemeList.size(); @@ -823,10 +863,13 @@ * Represents a flib_team*, for use as part of a flib_team** */ static class TeamPointerByReference extends Structure implements Structure.ByReference { - private static String[] FIELD_ORDER = new String[] {"team"}; + public TeamPointerByReference() { super(); } + public TeamPointerByReference(Pointer ptr) { super(ptr); } - public TeamPointerByReference() { super(); setFieldOrder(FIELD_ORDER); } - public TeamPointerByReference(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); } + @Override + protected List getFieldOrder() { + return Arrays.asList("team"); + } public TeamStruct.ByRef team; } @@ -835,10 +878,13 @@ public static class ByVal extends TeamlistStruct implements Structure.ByValue {} public static class ByRef extends TeamlistStruct implements Structure.ByReference {} - private static String[] FIELD_ORDER = new String[] {"teamCount", "teams"}; + public TeamlistStruct() { super(); } + public TeamlistStruct(Pointer ptr) { super(ptr); } - public TeamlistStruct() { super(); setFieldOrder(FIELD_ORDER); } - public TeamlistStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); } + @Override + protected List getFieldOrder() { + return Arrays.asList("teamCount", "teams"); + } public void fillFrom(List teamList, WeaponsetStruct.ByRef weaponset, int initialHealth) { teamCount = teamList.size(); @@ -878,10 +924,14 @@ static class GameSetupStruct extends Structure { public static class ByVal extends GameSetupStruct implements Structure.ByValue {} public static class ByRef extends GameSetupStruct implements Structure.ByReference {} - private static String[] FIELD_ORDER = new String[] {"script", "gamescheme", "map", "teamlist"}; + + public GameSetupStruct() { super(); } + public GameSetupStruct(Pointer ptr) { super(ptr); } - public GameSetupStruct() { super(); setFieldOrder(FIELD_ORDER); } - public GameSetupStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); } + @Override + protected List getFieldOrder() { + return Arrays.asList("script", "gamescheme", "map", "teamlist"); + } public void fillFrom(GameConfig conf) { script = conf.style; diff -r 404ddce27b23 -r c13ebed437cb project_files/HedgewarsMobile/Hedgewars.xcodeproj/project.pbxproj --- a/project_files/HedgewarsMobile/Hedgewars.xcodeproj/project.pbxproj Wed Feb 20 02:21:58 2013 +0100 +++ b/project_files/HedgewarsMobile/Hedgewars.xcodeproj/project.pbxproj Tue Apr 02 21:00:57 2013 +0200 @@ -35,7 +35,6 @@ 610D5FB21270E2660033333A /* Icon-Small@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 61F7A43411E290650040BA66 /* Icon-Small@2x.png */; }; 610D5FB31270E26C0033333A /* Icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 61F7A43611E290650040BA66 /* Icon@2x.png */; }; 610FB7C81661390E002FB2A7 /* uPhysFSLayer.pas in Sources */ = {isa = PBXBuildFile; fileRef = 610FB7C71661390E002FB2A7 /* uPhysFSLayer.pas */; }; - 610FB81A166139DF002FB2A7 /* libPhysfs.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 610FB7F8166139A4002FB2A7 /* libPhysfs.a */; }; 61156521147F48B6006729A9 /* About.strings in Resources */ = {isa = PBXBuildFile; fileRef = 61156520147F48B6006729A9 /* About.strings */; }; 61156523147F48B7006729A9 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 61156522147F48B7006729A9 /* Localizable.strings */; }; 61156525147F48B8006729A9 /* Scheme.strings in Resources */ = {isa = PBXBuildFile; fileRef = 61156524147F48B8006729A9 /* Scheme.strings */; }; @@ -171,6 +170,8 @@ 6179883C114AA34C00BA94A9 /* uVisualGears.pas in Sources */ = {isa = PBXBuildFile; fileRef = 6179880E114AA34C00BA94A9 /* uVisualGears.pas */; }; 6179883D114AA34C00BA94A9 /* uWorld.pas in Sources */ = {isa = PBXBuildFile; fileRef = 6179880F114AA34C00BA94A9 /* uWorld.pas */; }; 61798935114AB25F00BA94A9 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 61798934114AB25F00BA94A9 /* AudioToolbox.framework */; }; + 617D791E16D933060091D4D6 /* libPhysfs.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 617D78E016D932310091D4D6 /* libPhysfs.a */; }; + 617D795716D9345F0091D4D6 /* libPhyslayer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 617D794816D933B00091D4D6 /* libPhyslayer.a */; }; 61808A5D128C930A005D0E2F /* backSound.caf in Resources */ = {isa = PBXBuildFile; fileRef = 611EE9D7122AA10A00DF6938 /* backSound.caf */; }; 61889985129995B500D55FD6 /* title~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 61889984129995B500D55FD6 /* title~ipad.png */; }; 61915D5B143A4E2C00299991 /* MissionTrainingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 61915D59143A4E2C00299991 /* MissionTrainingViewController.m */; }; @@ -312,20 +313,6 @@ remoteGlobalIDString = BE1FA72F07AF4C45004B6283; remoteInfo = libSDL_image; }; - 610FB7F7166139A4002FB2A7 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 610FB7F3166139A4002FB2A7 /* Physfs.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = D2AAC07E0554694100DB518D; - remoteInfo = Physfs; - }; - 610FB81B166139EC002FB2A7 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 610FB7F3166139A4002FB2A7 /* Physfs.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = D2AAC07D0554694100DB518D; - remoteInfo = Physfs; - }; 6162456614E6159C00CC97FB /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 619599BA1364E65900B429B6 /* Freetype.xcodeproj */; @@ -333,6 +320,34 @@ remoteGlobalIDString = D2AAC07E0554694100DB518D; remoteInfo = libFreetype; }; + 617D78DF16D932310091D4D6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 617D78D816D932310091D4D6 /* Physfs.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = D2AAC07E0554694100DB518D; + remoteInfo = Physfs; + }; + 617D791C16D932EC0091D4D6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 617D78D816D932310091D4D6 /* Physfs.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = D2AAC07D0554694100DB518D; + remoteInfo = Physfs; + }; + 617D794716D933B00091D4D6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 617D794316D933B00091D4D6 /* Physlayer.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = D2AAC07E0554694100DB518D; + remoteInfo = Physlayer; + }; + 617D794916D933BC0091D4D6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 617D794316D933B00091D4D6 /* Physlayer.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = D2AAC07D0554694100DB518D; + remoteInfo = Physlayer; + }; 6195981C1364BCD200B429B6 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 619598181364BCD200B429B6 /* Tremor.xcodeproj */; @@ -418,7 +433,6 @@ 610C8E3514E018D200CF5C4C /* MNEValueTrackingSlider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MNEValueTrackingSlider.h; path = Classes/MNEValueTrackingSlider.h; sourceTree = ""; }; 610C8E3614E018D200CF5C4C /* MNEValueTrackingSlider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MNEValueTrackingSlider.m; path = Classes/MNEValueTrackingSlider.m; sourceTree = ""; }; 610FB7C71661390E002FB2A7 /* uPhysFSLayer.pas */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; name = uPhysFSLayer.pas; path = ../../hedgewars/uPhysFSLayer.pas; sourceTree = SOURCE_ROOT; }; - 610FB7F3166139A4002FB2A7 /* Physfs.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Physfs.xcodeproj; path = ../../misc/physfs/Xcode/Physfs.xcodeproj; sourceTree = SOURCE_ROOT; }; 6115651A147F48AE006729A9 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = Locale/English.lproj/About.strings; sourceTree = ""; }; 6115651B147F48AE006729A9 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = Locale/English.lproj/Localizable.strings; sourceTree = ""; }; 6115651C147F48AE006729A9 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = Locale/English.lproj/Scheme.strings; sourceTree = ""; }; @@ -613,6 +627,8 @@ 617BC22D1490210E00E1C294 /* Italian */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Italian; path = Locale/Italian.lproj/About.strings; sourceTree = ""; }; 617BC2391490211500E1C294 /* Italian */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Italian; path = Locale/Italian.lproj/Localizable.strings; sourceTree = ""; }; 617BC23A1490211F00E1C294 /* Italian */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Italian; path = Locale/Italian.lproj/Scheme.strings; sourceTree = ""; }; + 617D78D816D932310091D4D6 /* Physfs.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Physfs.xcodeproj; path = ../../misc/libphysfs/Xcode/Physfs.xcodeproj; sourceTree = SOURCE_ROOT; }; + 617D794316D933B00091D4D6 /* Physlayer.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Physlayer.xcodeproj; path = ../../misc/libphyslayer/Xcode/Physlayer.xcodeproj; sourceTree = SOURCE_ROOT; }; 6183D83C11E2BCE200A88903 /* Default-ipad-Landscape.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default-ipad-Landscape.png"; path = "Resources/Icons/Default-ipad-Landscape.png"; sourceTree = ""; }; 6183D83D11E2BCE200A88903 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Default.png; path = Resources/Icons/Default.png; sourceTree = ""; }; 618899811299516000D55FD6 /* title@2x~iphone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "title@2x~iphone.png"; path = "Resources/Frontend/title@2x~iphone.png"; sourceTree = ""; }; @@ -717,11 +733,12 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 617D791E16D933060091D4D6 /* libPhysfs.a in Frameworks */, + 617D795716D9345F0091D4D6 /* libPhyslayer.a in Frameworks */, 922F64900F10F53100DC6EC0 /* libfpc.a in Frameworks */, 616245D114E6160200CC97FB /* libFreetype.a in Frameworks */, 619599451364C83D00B429B6 /* libLua.a in Frameworks */, 6195981F1364BCEF00B429B6 /* libTremor.a in Frameworks */, - 610FB81A166139DF002FB2A7 /* libPhysfs.a in Frameworks */, 61A19AFC14D20170004B1E6D /* libSDL2.a in Frameworks */, 61A19B7714D20B7A004B1E6D /* libSDL2_image.a in Frameworks */, 61A19C2414D20F5A004B1E6D /* libSDL2_mixer.a in Frameworks */, @@ -830,7 +847,8 @@ 29B97323FDCFA39411CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( - 610FB7F3166139A4002FB2A7 /* Physfs.xcodeproj */, + 617D78D816D932310091D4D6 /* Physfs.xcodeproj */, + 617D794316D933B00091D4D6 /* Physlayer.xcodeproj */, 619599BA1364E65900B429B6 /* Freetype.xcodeproj */, 6195993F1364C82B00B429B6 /* Lua.xcodeproj */, 619598181364BCD200B429B6 /* Tremor.xcodeproj */, @@ -854,14 +872,6 @@ name = Frameworks; sourceTree = ""; }; - 610FB7F4166139A4002FB2A7 /* Products */ = { - isa = PBXGroup; - children = ( - 610FB7F8166139A4002FB2A7 /* libPhysfs.a */, - ); - name = Products; - sourceTree = ""; - }; 61156510147F481B006729A9 /* Locale */ = { isa = PBXGroup; children = ( @@ -1039,6 +1049,22 @@ name = Overlay; sourceTree = ""; }; + 617D78D916D932310091D4D6 /* Products */ = { + isa = PBXGroup; + children = ( + 617D78E016D932310091D4D6 /* libPhysfs.a */, + ); + name = Products; + sourceTree = ""; + }; + 617D794416D933B00091D4D6 /* Products */ = { + isa = PBXGroup; + children = ( + 617D794816D933B00091D4D6 /* libPhyslayer.a */, + ); + name = Products; + sourceTree = ""; + }; 619598191364BCD200B429B6 /* Products */ = { isa = PBXGroup; children = ( @@ -1303,7 +1329,8 @@ 610FB7EC16613980002FB2A7 /* PBXTargetDependency */, 610FB7EE16613980002FB2A7 /* PBXTargetDependency */, 610FB7F016613980002FB2A7 /* PBXTargetDependency */, - 610FB81C166139EC002FB2A7 /* PBXTargetDependency */, + 617D791D16D932EC0091D4D6 /* PBXTargetDependency */, + 617D794A16D933BC0091D4D6 /* PBXTargetDependency */, ); name = Hedgewars; productName = HedgewarsMobile; @@ -1364,8 +1391,12 @@ ProjectRef = 6195993F1364C82B00B429B6 /* Lua.xcodeproj */; }, { - ProductGroup = 610FB7F4166139A4002FB2A7 /* Products */; - ProjectRef = 610FB7F3166139A4002FB2A7 /* Physfs.xcodeproj */; + ProductGroup = 617D78D916D932310091D4D6 /* Products */; + ProjectRef = 617D78D816D932310091D4D6 /* Physfs.xcodeproj */; + }, + { + ProductGroup = 617D794416D933B00091D4D6 /* Products */; + ProjectRef = 617D794316D933B00091D4D6 /* Physlayer.xcodeproj */; }, { ProductGroup = 61A19AE414D2010A004B1E6D /* Products */; @@ -1402,13 +1433,6 @@ /* End PBXProject section */ /* Begin PBXReferenceProxy section */ - 610FB7F8166139A4002FB2A7 /* libPhysfs.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libPhysfs.a; - remoteRef = 610FB7F7166139A4002FB2A7 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; 6162456714E6159C00CC97FB /* libFreetype.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; @@ -1416,6 +1440,20 @@ remoteRef = 6162456614E6159C00CC97FB /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + 617D78E016D932310091D4D6 /* libPhysfs.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libPhysfs.a; + remoteRef = 617D78DF16D932310091D4D6 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 617D794816D933B00091D4D6 /* libPhyslayer.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libPhyslayer.a; + remoteRef = 617D794716D933B00091D4D6 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; 6195981D1364BCD200B429B6 /* libTremor.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; @@ -1795,10 +1833,15 @@ name = libSDL_image; targetProxy = 610FB7EF16613980002FB2A7 /* PBXContainerItemProxy */; }; - 610FB81C166139EC002FB2A7 /* PBXTargetDependency */ = { + 617D791D16D932EC0091D4D6 /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = Physfs; - targetProxy = 610FB81B166139EC002FB2A7 /* PBXContainerItemProxy */; + targetProxy = 617D791C16D932EC0091D4D6 /* PBXContainerItemProxy */; + }; + 617D794A16D933BC0091D4D6 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Physlayer; + targetProxy = 617D794916D933BC0091D4D6 /* PBXContainerItemProxy */; }; 9283015A0F10E41300CC5A3C /* PBXTargetDependency */ = { isa = PBXTargetDependency; diff -r 404ddce27b23 -r c13ebed437cb project_files/hedgewars.pro --- a/project_files/hedgewars.pro Wed Feb 20 02:21:58 2013 +0100 +++ b/project_files/hedgewars.pro Tue Apr 02 21:00:57 2013 +0200 @@ -10,8 +10,8 @@ INCLUDEPATH += ../QTfrontend/net INCLUDEPATH += ../QTfrontend/util INCLUDEPATH += ../QTfrontend/util/platform -INCLUDEPATH += ../misc/physfs/src -INCLUDEPATH += ../misc/physfs/extras +INCLUDEPATH += ../misc/libphysfs +INCLUDEPATH += ../misc/libphyslayer DESTDIR = ../bin @@ -114,9 +114,9 @@ ../QTfrontend/util/MessageDialog.h \ ../QTfrontend/ui/widget/hatprompt.h \ ../QTfrontend/ui/widget/feedbackdialog.h \ - ../QTfrontend/ui/widget/flowlayout.h \ ../QTfrontend/ui/widget/lineeditcursor.h \ - ../QTfrontend/servermessages.h + ../QTfrontend/servermessages.h \ + ../QTfrontend/ui/widget/roomnameprompt.h SOURCES += ../QTfrontend/model/ammoSchemeModel.cpp \ @@ -214,8 +214,8 @@ ../QTfrontend/ui/widget/themeprompt.cpp \ ../QTfrontend/util/MessageDialog.cpp \ ../QTfrontend/ui/widget/feedbackdialog.cpp \ - ../QTfrontend/ui/widget/flowlayout.cpp \ - ../QTfrontend/ui/widget/lineeditcursor.cpp + ../QTfrontend/ui/widget/lineeditcursor.cpp \ + ../QTfrontend/ui/widget/roomnameprompt.cpp TRANSLATIONS += ../share/hedgewars/Data/Locale/hedgewars_ar.ts \ diff -r 404ddce27b23 -r c13ebed437cb share/CMakeLists.txt --- a/share/CMakeLists.txt Wed Feb 20 02:21:58 2013 +0100 +++ b/share/CMakeLists.txt Tue Apr 02 21:00:57 2013 +0200 @@ -1,21 +1,15 @@ -add_subdirectory(hedgewars) + +set(SHAREPATH ${HEDGEWARS_DATADIR}) + +add_subdirectory(hedgewars/Data) if(APPLE) - #needed for CFBundleVersion and CFBundleShortVersionString - #should reuse the variables set in main CMakeLists.txt - if(HGCOMMAND AND (EXISTS ${CMAKE_SOURCE_DIR}/.hg)) - set(HEDGEWARS_REVISION ${revision_number}) - else() - set(HEDGEWARS_REVISION ${HEDGEWARS_VERSION}) - endif() + #CFBundleVersion is HEDGEWARS_REVISION + #CFBundleShortVersionString is HEDGEWARS_VERSION - #silly libav that always brings in VideoDecoderAcceleration, avaible only from 10.6.3 - if(NOT NOVIDEOREC) - set(FFMPEG_FIND_QUIETLY true) - find_package(FFMPEG) - if(${FFMPEG_FOUND} AND ${minimum_macosx_version} VERSION_EQUAL "10.6") - set(minimum_macosx_version "10.6.3") - endif() + #libav/ffmpeg always brings in VideoDecoderAcceleration, avaible only from 10.6.3 + if(${FFMPEG_FOUND} AND ${minimum_macosx_version} VERSION_EQUAL "10.6") + set(minimum_macosx_version "10.6.3") endif() configure_file(${hedgewars_SOURCE_DIR}/share/Info.plist.in diff -r 404ddce27b23 -r c13ebed437cb share/Info.plist.in --- a/share/Info.plist.in Wed Feb 20 02:21:58 2013 +0100 +++ b/share/Info.plist.in Tue Apr 02 21:00:57 2013 +0200 @@ -25,7 +25,7 @@ NSHumanReadableCopyright Copyright © 2004-2012, Hedgewars Project NSAppleScriptEnabled - + LSRequiresNativeExecution LSMinimumSystemVersionByArchitecture @@ -156,5 +156,21 @@ Viewer + CFBundleURLTypes + + + CFBundleURLName + Hedgewars URIs + CFBundleURLSchemes + + + hwplay + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/CMakeLists.txt --- a/share/hedgewars/CMakeLists.txt Wed Feb 20 02:21:58 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -add_subdirectory(Data) diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Forts/SteelTower-icon.png Binary file share/hedgewars/Data/Forts/SteelTower-icon.png has changed diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Forts/SteelTower-icon@2x.png Binary file share/hedgewars/Data/Forts/SteelTower-icon@2x.png has changed diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Forts/SteelTower-preview.png Binary file share/hedgewars/Data/Forts/SteelTower-preview.png has changed diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Forts/SteelTower-preview@2x.png Binary file share/hedgewars/Data/Forts/SteelTower-preview@2x.png has changed diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Forts/SteelTowerL.png Binary file share/hedgewars/Data/Forts/SteelTowerL.png has changed diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Forts/SteelTowerR.png Binary file share/hedgewars/Data/Forts/SteelTowerR.png has changed diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Graphics/Flags/cm_belarus.png Binary file share/hedgewars/Data/Graphics/Flags/cm_belarus.png has changed diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Graphics/Hedgehog.png Binary file share/hedgewars/Data/Graphics/Hedgehog.png has changed diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Graphics/Hedgehog/amFrozenHog.png Binary file share/hedgewars/Data/Graphics/Hedgehog/amFrozenHog.png has changed diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Graphics/Hedgehog/amIceGun.png Binary file share/hedgewars/Data/Graphics/Hedgehog/amIceGun.png has changed diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Graphics/icetexture.png Binary file share/hedgewars/Data/Graphics/icetexture.png has changed diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/cs.txt --- a/share/hedgewars/Data/Locale/cs.txt Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/cs.txt Tue Apr 02 21:00:57 2013 +0200 @@ -54,8 +54,8 @@ 00:51=Hrouda bláta 00:52=Není vybrána žádná zbraň 00:53=TimeBox -00:54=Struktura -00:55=Pozemek s rozprašovačem +; 00:54=Struktura +00:54=Pozemek s rozprašovačem 01:00=Do boje! 01:01=Kolo nerozhodně diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/da.txt --- a/share/hedgewars/Data/Locale/da.txt Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/da.txt Tue Apr 02 21:00:57 2013 +0200 @@ -54,8 +54,8 @@ 00:51=Mudderklat 00:52=Intet våben valgt 00:53=Tidsboks -00:54=Struktur -00:55=Jordspray +; 00:54=Struktur +00:54=Jordspray 01:00=Kæmp! 01:01=Runde uafgjort diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/de.txt --- a/share/hedgewars/Data/Locale/de.txt Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/de.txt Tue Apr 02 21:00:57 2013 +0200 @@ -54,10 +54,10 @@ 00:51=Schlammball 00:52=Keine Waffe ausgewählt 00:53=ZeitBox -00:54=Bauwerk -00:55=Landkanone -00:56=Gefrierer -00:57=Hackbeil +; 00:54=Bauwerk +00:54=Landkanone +00:55=Gefrierer +00:56=Hackebeil 01:00=Auf in die Schlacht! @@ -69,7 +69,7 @@ 01:06=Sudden Death! 01:07=%1 verbleibend 01:08=Treibstoff -01:09=Synchronisiere ... +01:09=Synchronisiere … 01:10=Benutzung beendet nicht die eigene Runde! 01:11=Waffe oder Werkzeug noch nicht verfügbar! 01:10=Benutzung beendet nicht die eigene Runde! @@ -83,70 +83,68 @@ 01:18=Hohe 01:19=Extreme 01:20=%1 Sprungkraft -01:21=Audio Stumm +01:21=Audio stumm ; Event messages ; Hog (%1) died 02:00=%1 hat den Löffel abgegeben! 02:00=%1 steht wohl nicht mehr auf! -02:00=%1 hat's nicht geschafft! +02:00=%1 hat’s nicht geschafft! 02:00=%1 stellt sich tot! 02:00=%1 hat schon bessere Tage gesehen! 02:00=%1 sieht tote Igel! 02:00=%1 hat ins Gras gebissen! 02:00=%1 ist Futter für die Würmer! -02:00=Das war's wohl, %1! -02:00=%1 hat's hinter sich! +02:00=Das war’s wohl, %1! +02:00=%1 hat’s hinter sich! 02:00=%1 kann schon das Licht sehen! 02:00=Für %1 gehen alle Lichter aus! 02:00=%1 kommt wieder! 02:00=%1 ist urlaubsreif! 02:00=%1 trifft seine Ahnen. 02:00=%1 war nicht hartnäckig genug! -02:00=%1 war einmal. -02:00=%1 hat wohl versagt. -02:00=Mach's gut, %1! -02:00=%1 hinterlässt eine Frau und Kind -02:00=%1 ins Leben gerufen hat seine letzte Panzerfaust -02:00=%1 hat seine letzte Granate geworfen -02:00=%1 hat seine letzte Kuchen gebacken -02:00=%1 hat auf seiner letzten Seil schwangen -02:00=%1 genannt hat seinen letzten Luftangriff -02:00=%1 gepumpt hat seine letzte Schrotflinte -02:00=%1 geworfen hat seine letzte Melone -02:00=%1 gezogen hat seinen letzten deagle +02:00=%1 war einmal +02:00=%1 hat wohl versagt +02:00=Mach’s gut, %1! +02:00=%1 hinterlässt Frau und Kind +02:00=%1 hat die letzte Bazooka gefeuert +02:00=%1 hat die letzte Granate geworfen +02:00=%1 hat den letzten Kuchen gebacken +02:00=%1 hat den letzten Luftangriff angefordert +02:00=%1 hat die letzte Schrotflinte gepumpt +02:00=%1 hat die letzte Melone geworfen +02:00=%1 hat die letzte Deagle gezogen 02:00=%1 nahm einen Schuss zu viel -02:00=%1 könnte wirklich eine gesundheitliche Kiste verwendet haben -02:00=%1 gegangen ist, um ein besseres Spiel zu spielen -02:00=%1 hat ragequit Leben +02:00=%1 hätte wirklich ein Erste-Hilfe-Kit gebrauchen können +02:00=%1 ist gegangen, um ein besseres Spiel zu spielen +02:00=%1 verlässt sein Leben aus Wut 02:00=%1 scheitert -02:00=Schlecht schlecht %1... -02:00=%1 lieber Warmux -02:00=%1 wurde blockiert Schüsse mit seinem Gesicht -02:00=%1 ist ein Held unter mir ... err ... Schweine -02:00=%1 findet seinen Platz in der Walhalla -02:00=%1 hat das Gebäude verlassen +02:00=Schlecht, schlecht, %1 … +02:00=%1 sollte lieber WarMUX spielen +02:00=%1 hat versucht die Kugeln mit den Zähnen zu fangen +02:00=%1 findet seinen Platz in der Walhall 02:00=%1 geht den Weg der Dinosaurier -02:00=%1 Igel bringt, einen Schritt näher zum Aussterben -02:00=%1 bringt eine Träne zu mir ins Auge -02:00=%1 ist ein Ex-Schwein -02:00=%1 wird die Radieschen -02:00=%1 hat aufgehört zu sein +02:00=%1 bringt die Igelspezies einen Schritt näher zum Aussterben +02:00=%1 wird vermisst werden +02:00=%1 ist ab jetzt ein Ex-Igel +02:00=%1 sieht sich die Radieschen von unten an +02:00=%1 hat aufgehört, zu sein 02:00=Verabschieden Sie sich von %1 -02:00=Keine Hoffnung mehr für %1 -02:00=%1 steht vor der letzte Vorhang -02:00=Rauchen, wenn du hast, %1 -02:00=%1 erleidet einen spontanen massiven Vorhandensein Ausfall -02:00=%1 weitergegeben hat +02:00=Für %1 gibt es keine Hoffnung mehr +02:00=%1 trat von der Lebensbühne ab +02:00=%1 erleidet ein spontanes multiples Organversagen 02:00=%1 ist mausetot -02:00=%1 nicht mehr -02:00=%1 abgelaufen -02:00=Beraubt des Lebens, %1 ruht in Frieden -02:00=%1 tritt der Chor unsichtbar -02:00=Abschied %1, wussten wir kaum ye! -02:00=%1 hatte eine geringe Toleranz für erschossen -02:00=%1 hätte verwenden können ein zusätzliches Leben -02:00=Gibt es einen Arzt im Haus? +02:00=%1s Lebensuhr ist abgelaufen +02:00=Beraubt des Lebens, ruht %1 in Frieden +02:00=%1 hatte eine geringe Schadenstoleranz +02:00=%1 hat all seine Extraleben aufgebraucht +02:00=Ist ein Arzt im Haus?! +02:00=%1 ist tot +02:00=%1 ist hinüber +02:00=%1 wurde in tausend Stücke zerfetzt +02:00=Schade um %1 +02:00=Wir trauern um %1 +02:00=%1 beißt ins Gras ; Hog (%1) drowned 02:01=%1 geht auf Tauchstation! @@ -157,97 +155,81 @@ 02:01=%1 versagt beim Seepferdchen! 02:01=%1 ist ein Opfer der Gezeiten! 02:01=%1 findet Nemo! -02:01=%1 taucht unter ... +02:01=%1 taucht unter … 02:01=Atlantis wartet, %1! 02:01=%1 nimmt ein entspannendes Bad. 02:01=%1 hat nie das Seepferdchen gemacht! 02:01=%1 ist Fischfutter! -02:01=%1 im Rausch der Tiefe! +02:01=%1 ist im Rausch der Tiefe! 02:01=Was für ein feuchtes Erlebnis! 02:01=%1 geht unter die Perlentaucher! 02:01=%1 über Bord! -02:01=%1 verlässt das sinkende Schiff. +02:01=%1 verlässt das sinkende Schiff 02:01=%1 überschätzt seinen Auftrieb! 02:01=%1 erliegt dem Sog der Tiefe! 02:01=%1 geht der Sache auf den Grund! 02:01=%1 wäre fast verdurstet! -02:01=%1 checkt das tiefe Ende -02:01=%1 geht gluck gluck gluck -02:01=%1 geht Spritzer -02:01=%1 vergaß seine Armbinden -02:01=%1 wirklich genommen haben sollte Schwimmunterricht -02:01=%1 verließ seinem Surfbrett zu Hause -02:01=%1 wird gewaschen, bis -02:01=%1 ist ein Schwein matschig -02:01=%1 vergessen, sein Leben zu bringen Jacke -02:01=%1 geht Splish Spritzer -02:01=%1 wird mit den Fischen schlafen -02:01=%1 denkt das Wasser saugen Physik in diesem Spiel -02:01=%1 sieht durstig -02:01=Das Meer behauptet %1 -02:01=%1 wird auf dem Meer verschollen -02:01=%1 sollten mitgebracht haben seine Tauchausrüstung -02:01=%1 bekommt eine Bestattung auf See -02:01=%1 hat, dass die sinkenden Gefühl -02:01=%1 übt seine Rückenschwimmen +02:01=%1 macht »Gluck, gluck, gluck!« +02:01=%1 macht »Platsch!« +02:01=%1 vergaß seine Schwimmflügel +02:01=%1 hätte Schwimmunterricht nehmen sollen +02:01=%1 ließ sein Surfbrett zu Hause +02:01=%1 wird gewaschen +02:01=%1 ist ein nasser Igel +02:01=%1 hat seine Schwimmweste vergessen +02:01=%1 macht »Plitsch-platsch!« +02:01=%1 sieht durstig aus +02:01=%1 ist auf dem Meer verschollen +02:01=%1 bekommt eine Seebestattung +02:01=%1 übt sein Rückenschwimmen 02:01=%1 geht auf der Suche nach der Titanic 02:01=%1 ist nicht Jesus -02:01=%1 wird Findet Nemo -02:01=%1 ein Leck -02:01=Du mußt fragen, wie viele Schweine sind da unten +02:01=%1 hat ein Leck +02:01=Wie viele Igel wohl da unten liegen? 02:01=%1 macht das Meer etwas höher -02:01=%1 nicht in der Marine zu gewinnen -02:01=%1 tut sein Identitätswechsel von einem toten Fisch -02:01=Zumindest ging nicht in die Toilette, %1 -02:01=Sonic nicht schwimmen konnte und kann weder %1 -02:01=%1 will spielen Ecco the Dolphin -02:01=%1, Aquaria ist gegangen, um zu besuchen -02:01=%1 hat festgestellt, die verlorene Stadt Atlantis -02:01=%1 Ziele für die Hauptrolle in Bioshock 3 -02:01=Ihre doggy Paddel könnte ein wenig Arbeit, %1 -02:01=%1 sollten mitgebracht haben einen Jet-Ski -02:01=%1 mag es nicht, Wassersport -02:01=%1 wird forever blowing bubbles -02:01=%1 ist kurz von einem Floß -02:01=%1 denkt Salzwasser ist gut für die Haut +02:01=%1 ist absolut nicht Marinetauglich +02:01=%1 glaubt, er sei ein Fisch +02:01=Wenigstens ging die Sache nicht ins Klo, %1! +02:01=Sonic konnte nicht schwimmen, %1 auch nicht +02:01=%1 spielt »Flipper der Delphin« +02:01=%1 ist von uns gegangen, um Aquaria zu besuchen +02:01=%1 strebt die Hauptrolle in Bioshock 3 an +02:01=%1 hasst Wassersport +02:01=%1 wird für immer Blasen machen +02:01=%1 war ganz, ganz knapp vor einem Floß +02:01=%1 dachte, Salzwasser sei gut für die Haut 02:01=%1 bekommt Salzwasser in seine Wunden -02:01=%1 hat ging die Planke -02:01=%1 verfügt über eine Badewanne -02:01=%1 ist nass nass nass -02:01=%1 bekommt seine Federkiele nass -02:01=Es ist Davy Jones 'locker für %1 +02:01=%1 ging über die Planke +02:01=%1 geht baden +02:01=%1 ist nass, nass, nass +02:01=%1 macht blubb +02:01=%1, Igel, der mit dem Blubb +02:01=Nächster Halt: Meeresgrund +02:01=%1 hätte den Schwimmkurs nicht schwänzen sollen ; Round starts 02:02=Auf in die Schlacht! 02:02=Geladen und entsichert! -02:02=Jetzt geht's rund! -02:02=Los geht's! +02:02=Jetzt geht’s rund! +02:02=Los geht’s! 02:02=Alles angetreten! 02:02=Los, los, los! -02:02=Lassen Sie uns dies Partei beginnen -02:02=Letzte Schwein steht gewinnt -02:02=Gehen wir! +02:02=Der letzte Igel, der noch atmet, hat gewonnen +02:02=Los geht’s! 02:02=Lasst uns rocken! -02:02=Lassen Sie uns jam! -02:02=Es ist Anfang ... +02:02=Lasst uns jammen! +02:02=Das ist der Anfang … 02:02=Dies ist der Beginn von etwas Großem 02:02=Willkommen bei Hedgewars -02:02=Willkommen auf der Front -02:02=Crush deine Feinde! -02:02=Mai die beste Schwein Sieg +02:02=Willkommen an der Front +02:02=Mögen die besten Igel gewinnen! 02:02=Sieg oder Tod -02:02=Dem Sieger geht die Beute -02:02=Verlieren ist keine Option -02:02=Cry Havoc! Lassen Sie verlieren die Schweine des Krieges! -02:02=Hedgewars, die Ihnen von Hedgewars.org -02:02=GL HF -02:02=Nur sich glücklich schätzen du bist nicht gegen Tiyuri -02:02=Nur sich glücklich schätzen du bist nicht gegen unC0Rr -02:02=Nur sich glücklich schätzen du bist nicht gegen Nemo -02:02=Nur sich glücklich schätzen du bist nicht gegen Smaxx -02:02=Nur sich glücklich schätzen du bist nicht gegen Jessor +02:02=Dem Sieger gehört die Beute +02:02=Diese Schlacht muss gewonnen werden! +02:02=Hedgewars, präsentiert von hedgewars.org +02:02=Sei froh, wenn du nicht gegen Nemo kämpfst 02:02=Gib alles! -02:02=Die Verlierer machen die Reinigung auf! +02:02=Die Verlierer müssen putzen! 02:02=Lassen Sie den Kampf des Jahrtausends beginnen 02:02=Lassen Sie den Kampf des Jahrhunderts beginnen 02:02=Lassen Sie den Kampf des Jahrzehnts beginnen @@ -257,22 +239,18 @@ 02:02=Lassen Sie den Kampf des Tages beginnen 02:02=Lassen Sie den Kampf der Stunde beginnen 02:02=Tun Sie Ihr Bestes! -02:02=Zerstöre den Feind! -02:02=Viel Glück -02:02=Viel Spaß -02:02=Kämpfe den guten Kampf -02:02=Kampf schmutzig +02:02=Zerstört den Feind! +02:02=Viel Glück! +02:02=Viel Spaß! +02:02=Kampf im Schmutz 02:02=Kampf mit Ehre -02:02=Gib nicht auf -02:02=Never surrender -02:02=Rock und Socke! -02:02=Lassen Sie den fragfest beginnen! -02:02=Ich hoffe du bist bereit für einen Kampf! -02:02=Gehen gehen! -02:02=Igel Voraus! -02:02=Bringt es ihnen! +02:02=Niemals aufgeben, niemals kapitulieren! +02:02=Lassen Sie das Schlachtfest beginnen! +02:02=Ich hoffe, du bist bereit für einen Kampf! +02:02=Los, los! +02:02=Igel voraus! +02:02=Zeigt’s ihnen! 02:02=Habt keine Angst! -02:02=Seien Sie mutig und erobern ; Round ends (win; unused atm) 02:03=... @@ -288,14 +266,15 @@ 02:05=Mit Liebe verpackt? 02:05=Frisches Pflaster! 02:05=So werden Sie sich besser fühlen -02:05=Ein Hallo-Trank! Whoops falsche Spiel -02:05=Ein wählen mir oben! -02:05=Zugreifen +02:05=Ein Hallo-Trank! Upps, falsches Spiel +02:05=Zugreifen! 02:05=Ein gesunder Snack -02:05=Ein Mittel, um Schmerzen -02:05=Richtige Dosierung: so viele wie du finden kannst! -02:05=Schnelle Lieferung +02:05=Ein Mittel, um Schmerzen zu lindern +02:05=Richtige Dosierung: so viele, wie du finden kannst! +02:05=Express-Lieferung 02:05=Vorräte! +02:05=Ein Erste-Hilfe-Koffer! +02:05=Ein Grund zur Hoffnung! ; New ammo crate 02:06=Nachschub! @@ -305,19 +284,19 @@ 02:06=Tod aus der Luft! 02:06=Ein Geschenk! 02:06=Spezielle Lieferung! -02:06=Es war ein Alptraum bekommen dies durch den Zoll -02:06=Destruktive Spielzeug aus dem Himmel -02:06=Warnung! Inhalt Flüchtige -02:06=Wählen es oder blasen sie auf, ist Qual der Wahl +02:06=Es war ein Alptraum, diese Kiste durch den Zoll zu kriegen … +02:06=Destruktives Spielzeug aus dem Himmel +02:06=Vorsicht! Inhalt leicht entzündlich +02:06=Einsammeln oder sprengen, das ist die Frage 02:06=Extras! -02:06=Mmm Munition +02:06=M-M-M-Munition 02:06=Eine Schachtel zerstörerische Kraft 02:06=Luftpost! -02:06=Was auch immer ist in diesem Feld ist es nicht Pizza -02:06=Bekommen! -02:06=Waffe fallen zu lassen eingehende -02:06=Lassen Sie sich nicht, dass der Feind schnappen! -02:06=Shiny neues Spielzeug! +02:06=Was auch immer da drin ist, es ist bestimmt nicht Pizza +02:06=Einsammlen! +02:06=Eine Waffenkiste! +02:06=Lassen Sie nicht zu, dass sich der Feind sie holt! +02:06=Schönes neues Spielzeug! 02:06=Eine geheimnisvolle Kiste! ; New utility crate @@ -330,91 +309,107 @@ 02:07=Extras für Sie! 02:07=Dies sollte gut sein! 02:07=Verwenden Sie diese mit Bedacht -02:07=Ooo diese Box ist schwer -02:07=Möglicherweise müssen Sie diese +02:07=Uff, diese Box ist schwer ; Hog (%1) skips his turn -02:08=%1 ist so ein Langeweiler ... -02:08=%1 denkt weiter nach ... +02:08=%1 ist so ein Langeweiler … +02:08=%1 denkt weiter nach … +02:08=%1 schmiedet einen Plan … 02:08=Das war öde, %1! 02:08=%1 führt etwas im Schilde! 02:08=%1 setzt aus. 02:08=%1 ist ein Drückeberger. 02:08=%1 überdenkt die Situation. 02:08=%1 kann sich nicht entscheiden. -02:08=%1 muss ein wenig mehr Motivation +02:08=%1 ist unmotiviert +02:08=%1 braucht etwas Motivation 02:08=%1 ist ein Pazifist 02:08=%1 hat eine Verschnaufpause -02:08=%1 hat einen Rest -02:08=%1 Schüttelfrost aus +02:08=%1 hat eine Pause +02:08=%1 ist dem Schüttelfrost ausgesetz 02:08=%1 hat kein Vertrauen in seine eigenen Fähigkeiten 02:08=%1 beschließt, nichts zu tun -02:08=%1 lässt den Feind zu vernichten selbst -02:08=%1 wäre bei Partys schrecklich +02:08=%1 lässt den Feind sich selbst vernichten +02:08=%1 wäre furchtbar auf Partys 02:08=%1 versteckt sich -02:08=%1 hat sich entschlossen, diese Chance geben -02:08=%1 entscheidet das Beste, was er tun kann, ist nichts ... +02:08=%1 verpasst die Gelegenheit +02:08=%1 verschenkt die Chance +02:08=%1 meint, das Beste, was er tun kann, ist nichts … 02:08=%1 ist ein großes Weichei -02:08=Bock bock bock, %1 ist ein Huhn -02:08=%1 schaut ein wenig gelb +02:08=Gock, gock, gock, %1 ist ein Huhn +02:08=%1 sieht etwas gelblich aus 02:08=%1 ist ein Feigling! -02:08=%1 wird für den plötzlichen Tod wartet -02:08=%1 ist wartet auf Sudden Death -02:08=%1 ist nicht die Bekämpfung von Typ -02:08=%1 überdenkt seinen Sinn im Leben -02:08=%1 war nie viel von einem guten Schuss ohnehin -02:08=%1 wollte nicht, dass die Armee in erster Linie verbinden -02:08=Aufhören, unsere Zeit, %1 -02:08=Ich bin in dir enttäuscht, %1 -02:08=Los, können Sie es besser machen %1 -02:08=%1 wird gebrochen +02:08=%1 wartet auf Sudden Death +02:08=%1 ist nicht so der Kämpfertyp +02:08=%1 denkt über den Sinn des Lebens nach +02:08=%1 war noch nie so Recht in Schuss +02:08=%1 wollte eigentlich niemals zur Armee +02:08=Die Zeit ist um, %1! +02:08=Ich bin von dir enttäuscht, %1 +02:08=Los, du kannst es besser, %1! 02:08=%1 hat anscheinend Besseres zu tun -02:08=%1 ist zu Tode erschrocken +02:08=%1 hat sich fast zu Tode erschrocken 02:08=%1 ist eingeschlafen ; Hog (%1) hurts himself only -02:09=%1 sollte besser Zielen üben! -02:09=%1 scheint sich zu hassen. +02:09=%1 sollte lieber zielen üben! +02:09=%1 scheint sich zu hassen 02:09=%1 steht auf der falschen Seite! 02:09=%1 lebt gefährlich! -02:09=%1 hat keinen Instinkt der Selbsterhaltung -02:09=%1 durcheinander -02:09=%1 vermasselt +02:09=%1 hat keinen Selbsterhaltungstrieb +02:09=%1 ist durcheinander +02:09=%1 vermasselt’s 02:09=Das war ein schlechter Schuss, %1 -02:09=%1 ist ein wenig zu sorglos mit gefährlichen Waffen +02:09=%1 geht ein wenig zu sorglos mit gefährlichen Waffen um 02:09=%1 sollte eine Änderung der Laufbahn betrachten -02:09=Schlechteste. Schuss. Je! -02:09=Kein kein kein %1, Sie schießen auf den Feind! -02:09=%1 sollte nur werden, den Feind zu vernichten -02:09=%1 bewegt sich einen Schritt näher an Selbstmord -02:09=%1, Hilfsmittel der Feind -02:09=Das war dumm %1 -02:09=%1 Leben mit dem Mantra des "keine Schmerzen, keine gewinnen" +02:09=Das. War. Schlecht! +02:09=Nein, nein, nein, %1, Sie müssen auf den Feind schießen! +02:09=%1 bewegt sich einen Schritt näher zum Selbstmord +02:09=%1, Helfer des Feindes +02:09=Das war dumm, %1 +02:09=%1 lebt nach dem Mantra des »Ohne Schmerz kein Sieg!« 02:09=%1 ist verwirrt -02:09=%1 verletzen sich in seiner Verwirrung -02:09=%1 hat ein Talent für sich zu blamieren +02:09=%1 ist geistig verwirrt +02:09=%1 verletzt sich selbst +02:09=%1 blamiert sich! 02:09=%1 ist ein Trottel! 02:09=%1 ist ungeschickt -02:09=%1 zeigt der Feind, wozu er fähig ist -02:09=%1 kann nicht erwartet werden, perfekt zu sein werden die ganze Zeit -02:09=Mach dir keine Sorgen %1, pobody die nerfect -02:09=%1 völlig mit Absicht getan -02:09=Ich werde niemandem sagen, wenn Sie nicht tun, %1 +02:09=%1 zeigt dem Feind, wozu er fähig ist +02:09=%1 ist nicht perfekt +02:09=Mach dir keine Sorgen, %1, piemand ist nerfekt +02:09=%1 hat das mit Absicht getan +02:09=Ich werd es auch niemandem verraten, mein Ehrenwort, %1! 02:09=Wie peinlich! -02:09=Ich bin sicher, niemand sah, dass %1 -02:09=%1, Bedürfnisse, seine Field Manual überprüfen -02:09=%1 Waffe eindeutig versagt +02:09=Ich hoffe, dass das niemand gesehen hat, %1 +02:09=%1 sollte dringend die Gebrauchsanweisung noch einmal durchlesen +02:09=%1s hat eindeutig versagt +02:09=%1s Schuss ging nach hinten los! ; Hog (%1) shot an home run (using the bat and another hog) 02:10=Home Run! -02:10=Ein Vogel, ein Flugzeug, ... +02:10=Ein Vogel, ein Flugzeug, … 02:10=Der verleiht Flügel! +02:10=%1 landet einen Home Run! +02:10=%1 vor, noch ein Tor! +02:10=Ausgezeichnet, %1! +02:10=Bravo, %1! ; Hog (%1) has to leave (team is gone) 02:11=%1 muss ins Bett! 02:11=%1 scheint zu beschäftigt zu sein 02:11=Beam ihn hoch, Scotty! 02:11=%1 muss weg +02:11=%1 verkrümelt sich +02:11=%1 macht sich vom Acker +02:11=%1 zieht den Schwanz ein +02:11=%1 macht sich aus dem Staub +02:11=%1 macht einen Rückzieher +02:11=%1 zieht sich zurück +02:11=%1 teleportiert sich in eine andere Dimension +02:11=%1 teleportiert sich in ein Paralleluniversum +02:11=%1 verschwindet +02:11=%1 ist futsch +02:11=%1 hat wohl besseres zu tun ; Weapon Categories 03:00=Zeitzünder-Granate @@ -422,15 +417,15 @@ 03:02=Ballistische Waffe 03:03=Vorsicht, sticht! 03:04=Gewehr (mehrere Schüsse) -03:05=Grabwerkzeug +03:05=Grabewerkzeug 03:06=Aktion 03:07=Fortbewegungsmittel 03:08=Annäherungsmine 03:09=Pistole (mehrere Schüsse) -03:10=BOOM! +03:10=BUMM! 03:11=Bonk! 03:12=Kampfkunst -03:13=UNUSED +03:13=NICHT IN VERWENDUNG 03:14=Fortbewegungsmittel 03:15=Luftschlag 03:16=Luftschlag @@ -446,7 +441,7 @@ 03:26=Saftige Granate 03:27=Feurige Granate 03:28=Ballistische Waffe -03:29=Ballistische Waffe +03:29=Ball-istische Waffe 03:30=Luftschlag 03:31=Ferngesteuerte Bombe 03:32=Temporärer Effekt @@ -464,7 +459,7 @@ 03:43=Spiele Beathovens tödliche Sonate! 03:44=Ziemlich alt und stinkig 03:45=Die Macht der Wissenschaft -03:46=Heiß heiß heiß! +03:46=Heiß, heiß, heiß! 03:47=Mach es weg! 03:48=Stop! Hammer time! 03:49=Tut, was man vermutet @@ -499,7 +494,7 @@ 04:20=Erlaubt es dir, den aktiven Igel zu wechseln|und mit einem anderen Igel fortzufahren.|Angriff: Wechsel aktivieren 04:21=Feuere ein granatenartiges Projektil in die|Richtung deines Gegners, das beim Aufschlag|mehrere kleine Bomben freisetzen wird.|Angriff: Mit voller Kraft feuern 04:22=Nicht nur etwas für Indiana Jones! Die Peitsche|eignet sich besonders gut, um ungezogene Igel|eine Klippe hinunter zu treiben.|Angriff: Alles vor dem Igel schlagen -04:23=Wenn man nichts mehr zu verlieren hat ...|Opfere deinen Igel, indem du ihn in eine|festgelegte Richtung losstürmen lässt.|Er wird alles auf dem Weg treffen und am|Ende selbst explodieren.|Angriff: Tödlichen Angriff starten +04:23=Wenn man nichts mehr zu verlieren hat …|Opfere deinen Igel, indem du ihn in eine|festgelegte Richtung losstürmen lässt.|Er wird alles auf dem Weg treffen und am|Ende selbst explodieren.|Angriff: Tödlichen Angriff starten 04:24=Alles Gute! Schick diesen Kuchen auf den Weg,|damit er deinen lieben Feinden eine explosive|Party beschert. Die Torte überwindet fast jedes|Terrain, verliert dabei aber an Laufzeit.|Angriff: Torte losschicken explodieren lassen 04:25=Benutze diese Verkleidung, um einen Feind blind|vor Liebe in deine Richtung (und damit in einen|Abgrund oder ähnliches) springen zu lassen.|Angriff: Verkleiden und verführen 04:26=Wirf diese saftige Wassermelone auf deine Feinde.|Sobald die Zeit abgelaufen ist, wird sie in|einzelne und explosive Stücke zerspringen.|Angriff: Halten, um mit mehr Kraft zu werfen @@ -509,8 +504,8 @@ 04:30=Rufe ein Flugzeug, um ein Areal gezielt mit|tödlichem Napalm einzudecken. Gut gezielt|lassen sich so große Teile der Karte auslöschen.|Links/Rechts: Angriffsrichtung wählen|Cursor: Zielgebiet wählen und Angriff starten 04:31=Das RC-Flugzeug kann Kisten einsammeln und weit|entfernte Igel angreifen. Steuere es direkt in|ein Opfer oder wirf erst einige Bomben ab.|Angriff: Flugzeug starten und Bomben abwerfen|Weiter Sprung: "Ritt der Walküren"|Hoch/Runter: Flugzeug lenken 04:32=Niedrige Schwerkraft ist effektiver als jede|Diät! Springe höher und weiter oder lass|einfach deine Gegner noch weiter fliegen.|Angriff: Aktivieren -04:33=Manchmal muss es eben doch ein bisschen|mehr sein ...|Angreifen: Aktivieren -04:34=Can't touch me!|Angreifen: Aktivieren +04:33=Manchmal muss es eben doch ein bisschen|mehr sein …|Angreifen: Aktivieren +04:34=Can’t touch me!|Angreifen: Aktivieren 04:35=Manchmal vergeht die Zeit einfach zu schnell.|Schnapp dir einige zusätzliche Sekunden, um|deinen Angriff abzuschließen.|Angriff: Aktivieren 04:36=Nun, manchmal trifft man einfach nicht. In solchen|Fällen kann die moderne Technik natürlich nachhelfen.|Angriff: Aktivieren 04:37=Fürchte nicht das Tageslicht! Die Wirkung hält|nur eine Runde an, aber sie erlaubt es deinem|Igel, den Schaden, den er direkt verursacht|als Leben zu absorbieren.|Angreifen: Aktivieren @@ -518,8 +513,8 @@ 04:39=Fliege mit der fliegenden Untertasse in andere|Teile der Karte. Sie ist schwer zu beherrschen,|bringt dich aber an so gut wie jeden Ort.|Angriff: Aktivieren|Hoch/Links/Rechts: Beschleunigen|Weiter Sprung: Waffe benutzen 04:40=Entzünde einen Teil der Landschaft oder auch etwas|mehr mit dieser (schon bald) brennenden Flüssigkeit.|Angriff: Halten, um mit mehr Kraft zu werfen 04:41=Der Beweis, dass die Natur sogar die fliegende|Untertasse übertreffen könnte. Birdy kann|deinen Igel herumtragen und zudem Eier auf|deine Feinde fallen lassen.|Angriff: Aktivieren und Eier fallen lassen|Hoch/Links/Rechts: In eine Richtung flattern -04:42=Das tragbare Portal Device ermöglicht es dir,|dich, deine Feinde oder Waffen direkt zwischen|zwei Punkten auf der Karte zu|teleportieren.|Benutze es weise und deine Kampagne wird ein...|RIESENERFOLG!|Angriff: Öffnet ein Portal|Wechsel: Wechsle die Portalfarbe -04:43=Lass dein musikalisches Debüt einschlagen wie eine Bombe!|Lass ein Piano vom Himmel fallen, aber pass auf...|jemand muss es spielen und das könnte dich |dein Leben kosten!|Cursor: Zielgebiet wählen und Angriff starten|F1-F9: Spiel das Piano +04:42=Das tragbare Portal Device ermöglicht es dir,|dich, deine Feinde oder Waffen direkt zwischen|zwei Punkten auf der Karte zu|teleportieren.|Benutze es weise und deine Kampagne wird ein …|RIESENERFOLG!|Angriff: Öffnet ein Portal|Wechsel: Wechsle die Portalfarbe +04:43=Lass dein musikalisches Debüt einschlagen wie eine Bombe!|Lass ein Piano vom Himmel fallen, aber pass auf …|jemand muss es spielen und das könnte dich |dein Leben kosten!|Cursor: Zielgebiet wählen und Angriff starten|F1-F9: Spiel das Piano 04:44=Das ist nicht nur Käse, das ist biologische Kriegsführung!|Er wird nicht viel Schaden verursachen, sobald der Zünder|abgelaufen ist, aber er wird garantiert jeden in der Nähe|vergiften!|1-5: Zeitzünder einstellen|Angriff: Halten, um mit mehr Kraft zu werfen 04:45=All die Physikstunden haben sich endlich|bezahlt gemacht: Entfessle eine zerstörerische Sinuswelle|gegen deine Feinde.|Pass auf, die Waffe erzeugt einen ordentlichen Rückstoß.|(Diese Waffe ist unvollständig)|Angriff: Sinuswellen erzeugen 04:46=Brutzle deine Feinde mit fließenden Flammen.|Herzerwärmend!|Angriff: Aktivieren|Hoch/Runter: Im Feuern zielen|Links/Rechts: Durchfluss ändern @@ -548,7 +543,7 @@ 05:11=Gemeinsames Arsenal: Alle Teams gleicher Farbe teilen sich ihr Arsenal 05:12=Minenzünder: Minen explodieren nach %1 Sekunde(n) 05:13=Minenzünder: Minen explodieren sofort -05:14=Minenzünder: Minen explodieren nach 0 - 3 Sekunden +05:14=Minenzünder: Minen explodieren nach 0-3 Sekunden 05:15=Prozentualer Schaden: Alle Waffen verursachen %1 % Schaden 05:16=Lebenspunkter aller Igel wird am Ende jeder Runde zurückgesetzt 05:17=Computergesteuerte Igel erscheinen nach dem Tod wieder diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/en.txt --- a/share/hedgewars/Data/Locale/en.txt Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/en.txt Tue Apr 02 21:00:57 2013 +0200 @@ -54,10 +54,10 @@ 00:51=Mudball 00:52=No weapon selected 00:53=TimeBox -00:54=Structure -00:55=Land Spray -00:56=Freezer -00:57=Cleaver +; 00:54=Structure +00:54=Land Spray +00:55=Freezer +00:56=Cleaver 01:00=Let's fight! 01:01=Round draw diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/es.txt --- a/share/hedgewars/Data/Locale/es.txt Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/es.txt Tue Apr 02 21:00:57 2013 +0200 @@ -55,8 +55,8 @@ 00:51=Bola de barro 00:52=No hay arma seleccionada 00:53=Cabina del tiempo -00:54=Estructura -00:55=Pistola de barro +; 00:54=Estructura +00:54=Pistola de barro 01:00=¡Luchad! 01:01=Empate diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_ar.ts --- a/share/hedgewars/Data/Locale/hedgewars_ar.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_ar.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,6 +2,13 @@ + About + + Unknown Compiler + + + + AbstractPage Go back @@ -91,6 +98,22 @@ Send Feedback + + Please give us feedback! + + + + We are always happy about suggestions, ideas, or bug reports. + + + + If you found a bug, you can see if it's already known here (english): + + + + Your email address is optional, but we may want to contact you. + + FreqSpinBox @@ -118,34 +141,68 @@ Edit schemes - Game Options - - - Game scheme will auto-select a weapon + + Map + خارطة + + + Game options + + HWApplication - + %1 minutes - - - + + + + + + %1 hour - - - + + + + + + %1 hours - - - + + + + + + %1 day - - - + + + + + + %1 days + + + + + + + Scheme '%1' not supported + + + + Cannot create directory %1 + Cannot create directory %1 + + + Failed to open data directory: +%1 + +Please check your installation! @@ -388,10 +445,6 @@ - Largetunnels - - - Small islands @@ -435,6 +488,10 @@ All files + + Large tunnels + + HWNetServersModel @@ -508,6 +565,21 @@ Login + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + Nickname: + + + + Password: + + HWUploadVideoDialog @@ -530,14 +602,6 @@ HatPrompt - Select a hat - - - - Filter: - - - Cancel الغاء @@ -545,6 +609,10 @@ Use selected hat + + Search for a hat: + + KB @@ -864,6 +932,18 @@ Play a game on an official server + + Feedback + + + + Play local network game + + + + Play official network game + + PageMultiplayer @@ -880,7 +960,7 @@ PageNetGame Control - تحكم + تحكم Edit game preferences @@ -890,6 +970,21 @@ Start ابدا + + Update + تحديث + + + Room controls + + + + + PageNetServer + + Insert your address here + + PageOptions @@ -1077,11 +1172,11 @@ PageRoomsList Create - اصنع + اصنع Join - انضم + انضم Admin features @@ -1089,7 +1184,7 @@ Room Name: - رقم الغرقة + رقم الغرقة Rules: @@ -1099,14 +1194,6 @@ Weapons: - - Search: - - - - Clear - - %1 players online @@ -1114,6 +1201,30 @@ + + Search for a room: + + + + Create room + + + + Join room + + + + Room state + + + + Clear filters + + + + Open server administration page + + PageScheme @@ -1387,7 +1498,19 @@ Update - تحديث + تحديث + + + Restrict Unregistered Players Join + + + + Show games in lobby + + + + Show games in-progress + @@ -1488,14 +1611,6 @@ - In lobby - - - - In progress - - - Disabled @@ -1607,7 +1722,7 @@ Version - نسخة + نسخة Weapons @@ -1742,10 +1857,6 @@ - This program is distributed under the GNU General Public License v2 - - - There are videos that are currently being processed. Exiting now will abort them. Do you really want to quit? @@ -1835,6 +1946,14 @@ Type the security code: + + Revision + + + + This program is distributed under the %1 + + QLineEdit @@ -1857,6 +1976,10 @@ Hedgewars %1 Hedgewars %1 + + -r%1 (%2) + + QMessageBox @@ -1919,35 +2042,12 @@ - Main - Error - - - Cannot create directory %1 - Cannot create directory %1 - - - Failed to open data directory: -%1 - -Please check your installation! - - - - TCP - Error - + Cannot create directory %1 Unable to start the server: %1. - Unable to start the server: %1. - - - Unable to run engine at - - - - Error code: %1 - + Unable to start the server: %1. Video upload - Error @@ -2094,7 +2194,12 @@ - Hedgewars + Not all players are ready + + + + Are you sure you want to start this game? +Not all players are ready. @@ -2200,6 +2305,41 @@ Upload this video to your Youtube account + + Reset + + + + Set the default server port for Hedgewars + + + + Invite your friends to your server in just 1 click! + + + + 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. + + + + Start private server + + + + + RoomNamePrompt + + Enter a name for your room. + + + + Cancel + الغاء + + + Create room + + RoomsListModel @@ -2295,6 +2435,25 @@ + TCPBase + + Unable to start server at %1. + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + At least two teams are required to play! + + + + TeamShowWidget %1's team @@ -2304,13 +2463,17 @@ ThemePrompt - Select a theme for this map - - - Cancel الغاء + + Search for a theme: + + + + Use selected theme + + binds @@ -2892,4 +3055,119 @@ + + server + + Not room master + + + + Corrupted hedgehogs info + + + + too many teams + + + + too many hedgehogs + + + + There's already a team with same name in the list + + + + round in progress + + + + restricted + + + + REMOVE_TEAM: no such team + + + + Not team owner! + + + + Less than two clans! + + + + Room with such name already exists + + + + Nickname already chosen + + + + Illegal nickname + + + + Protocol already known + + + + Bad number + + + + Nickname is already in use + + + + No checker rights + + + + Authentication failed + + + + 60 seconds cooldown after kick + + + + kicked + + + + Ping timeout + + + + bye + + + + Illegal room name + + + + No such room + + + + Joining restricted + + + + Registered users only + + + + You are banned in this room + + + + Empty config entry + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_bg.ts --- a/share/hedgewars/Data/Locale/hedgewars_bg.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_bg.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,6 +2,13 @@ + About + + Unknown Compiler + + + + AbstractPage Go back @@ -91,6 +98,22 @@ Send Feedback + + Please give us feedback! + + + + We are always happy about suggestions, ideas, or bug reports. + + + + If you found a bug, you can see if it's already known here (english): + + + + Your email address is optional, but we may want to contact you. + + FreqSpinBox @@ -117,34 +140,68 @@ Редактиране на оръжията - Game Options - - - Game scheme will auto-select a weapon + + Map + Карта + + + Game options + + HWApplication - + %1 minutes - - - + + + + + + %1 hour - - - + + + + + + %1 hours - - - + + + + + + %1 day - - - + + + + + + %1 days + + + + + + + Scheme '%1' not supported + + + + Cannot create directory %1 + Не може да се създаде папка %1 + + + Failed to open data directory: +%1 + +Please check your installation! @@ -387,10 +444,6 @@ - Largetunnels - - - Small islands @@ -434,6 +487,10 @@ All files + + Large tunnels + + HWNetServersModel @@ -507,6 +564,21 @@ Login + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + Nickname: + + + + Password: + + HWUploadVideoDialog @@ -529,14 +601,6 @@ HatPrompt - Select a hat - - - - Filter: - - - Cancel Отказ @@ -544,6 +608,10 @@ Use selected hat + + Search for a hat: + + KB @@ -863,6 +931,18 @@ Play a game on an official server + + Feedback + + + + Play local network game + + + + Play official network game + + PageMultiplayer @@ -879,7 +959,7 @@ PageNetGame Control - Контрол + Контрол Edit game preferences @@ -889,6 +969,21 @@ Start Старт + + Update + Актуализиране + + + Room controls + + + + + PageNetServer + + Insert your address here + + PageOptions @@ -1076,11 +1171,11 @@ PageRoomsList Create - Създаване + Създаване Join - Присъединяване + Присъединяване Admin features @@ -1088,7 +1183,7 @@ Room Name: - Име на стаята: + Име на стаята: Rules: @@ -1100,11 +1195,11 @@ Search: - Търсене: + Търсене: Clear - Изчистване + Изчистване %1 players online @@ -1113,6 +1208,30 @@ + + Search for a room: + + + + Create room + + + + Join room + + + + Room state + + + + Clear filters + + + + Open server administration page + + PageScheme @@ -1386,7 +1505,19 @@ Update - Актуализиране + Актуализиране + + + Restrict Unregistered Players Join + + + + Show games in lobby + + + + Show games in-progress + @@ -1488,11 +1619,11 @@ In lobby - В лоби + В лоби In progress - В прогрес + В прогрес Disabled @@ -1658,7 +1789,7 @@ Version - Версия + Версия Initial sound volume @@ -1741,10 +1872,6 @@ - This program is distributed under the GNU General Public License v2 - - - There are videos that are currently being processed. Exiting now will abort them. Do you really want to quit? @@ -1834,6 +1961,14 @@ Type the security code: + + Revision + + + + This program is distributed under the %1 + + QLineEdit @@ -1856,6 +1991,10 @@ Hedgewars %1 Таралежови войни %1 + + -r%1 (%2) + + QMessageBox @@ -1918,35 +2057,12 @@ - Main - Error - - - Cannot create directory %1 - Не може да се създаде папка %1 - - - Failed to open data directory: -%1 - -Please check your installation! - - - - TCP - Error - + Не може да се създаде папка %1 Unable to start the server: %1. - Грешка при стартиране на сървъра: %1. - - - Unable to run engine at - - - - Error code: %1 - + Грешка при стартиране на сървъра: %1. Video upload - Error @@ -2094,7 +2210,12 @@ - Hedgewars + Not all players are ready + + + + Are you sure you want to start this game? +Not all players are ready. @@ -2200,6 +2321,41 @@ Upload this video to your Youtube account + + Reset + + + + Set the default server port for Hedgewars + + + + Invite your friends to your server in just 1 click! + + + + 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. + + + + Start private server + + + + + RoomNamePrompt + + Enter a name for your room. + + + + Cancel + Отказ + + + Create room + + RoomsListModel @@ -2295,6 +2451,25 @@ + TCPBase + + Unable to start server at %1. + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + At least two teams are required to play! + + + + TeamShowWidget %1's team @@ -2304,13 +2479,17 @@ ThemePrompt - Select a theme for this map - - - Cancel Отказ + + Search for a theme: + + + + Use selected theme + + binds @@ -2892,4 +3071,119 @@ + + server + + Not room master + + + + Corrupted hedgehogs info + + + + too many teams + + + + too many hedgehogs + + + + There's already a team with same name in the list + + + + round in progress + + + + restricted + + + + REMOVE_TEAM: no such team + + + + Not team owner! + + + + Less than two clans! + + + + Room with such name already exists + + + + Nickname already chosen + + + + Illegal nickname + + + + Protocol already known + + + + Bad number + + + + Nickname is already in use + + + + No checker rights + + + + Authentication failed + + + + 60 seconds cooldown after kick + + + + kicked + + + + Ping timeout + + + + bye + + + + Illegal room name + + + + No such room + + + + Joining restricted + + + + Registered users only + + + + You are banned in this room + + + + Empty config entry + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_cs.ts --- a/share/hedgewars/Data/Locale/hedgewars_cs.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_cs.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,6 +2,13 @@ + About + + Unknown Compiler + + + + AbstractPage Go back @@ -91,6 +98,22 @@ Send Feedback + + Please give us feedback! + + + + We are always happy about suggestions, ideas, or bug reports. + + + + If you found a bug, you can see if it's already known here (english): + + + + Your email address is optional, but we may want to contact you. + + FreqSpinBox @@ -118,34 +141,73 @@ Editovat schémata - Game Options - - - Game scheme will auto-select a weapon + + Map + Mapa + + + Game options + + HWApplication - + %1 minutes - - - + + + + + + + %1 hour - - - + + + + + + + %1 hours - - - + + + + + + + %1 day - - - + + + + + + + %1 days + + + + + + + + Scheme '%1' not supported + + + + Cannot create directory %1 + Nemohu vytvořit adresář %1 + + + Failed to open data directory: +%1 + +Please check your installation! @@ -388,10 +450,6 @@ - Largetunnels - - - Small islands @@ -435,6 +493,10 @@ All files + + Large tunnels + + HWNetServersModel @@ -508,6 +570,21 @@ Login + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + Nickname: + + + + Password: + + HWUploadVideoDialog @@ -530,14 +607,6 @@ HatPrompt - Select a hat - - - - Filter: - - - Cancel Zrušit @@ -545,6 +614,10 @@ Use selected hat + + Search for a hat: + + KB @@ -870,6 +943,18 @@ Play a game on an official server + + Feedback + + + + Play local network game + + + + Play official network game + + PageMultiplayer @@ -886,7 +971,7 @@ PageNetGame Control - Ovládání + Ovládání Edit game preferences @@ -896,6 +981,21 @@ Start Start + + Update + Obnovit + + + Room controls + + + + + PageNetServer + + Insert your address here + + PageOptions @@ -1083,11 +1183,11 @@ PageRoomsList Create - Vytvořit + Vytvořit Join - Připojit se + Připojit se Admin features @@ -1095,7 +1195,7 @@ Room Name: - Jméno místnosti: + Jméno místnosti: Rules: @@ -1107,11 +1207,11 @@ Search: - Hledej: + Hledej: Clear - Vyčisti + Vyčisti %1 players online @@ -1121,6 +1221,30 @@ + + Search for a room: + + + + Create room + + + + Join room + + + + Room state + + + + Clear filters + + + + Open server administration page + + PageScheme @@ -1395,7 +1519,19 @@ Update - Obnovit + Obnovit + + + Restrict Unregistered Players Join + + + + Show games in lobby + + + + Show games in-progress + @@ -1497,11 +1633,11 @@ In lobby - V čekárně + V čekárně In progress - Probíhá + Probíhá Disabled @@ -1607,7 +1743,7 @@ QLabel Version - Verze + Verze Weapons @@ -1750,10 +1886,6 @@ - This program is distributed under the GNU General Public License v2 - - - There are videos that are currently being processed. Exiting now will abort them. Do you really want to quit? @@ -1843,6 +1975,14 @@ Type the security code: + + Revision + + + + This program is distributed under the %1 + + QLineEdit @@ -1865,6 +2005,10 @@ Hedgewars %1 Hedgewars %1 + + -r%1 (%2) + + QMessageBox @@ -1927,35 +2071,12 @@ - Main - Error - - - Cannot create directory %1 - Nemohu vytvořit adresář %1 - - - Failed to open data directory: -%1 - -Please check your installation! - - - - TCP - Error - + Nemohu vytvořit adresář %1 Unable to start the server: %1. - Nemohu spustit server: %1. - - - Unable to run engine at - - - - Error code: %1 - + Nemohu spustit server: %1. Video upload - Error @@ -2104,7 +2225,12 @@ - Hedgewars + Not all players are ready + + + + Are you sure you want to start this game? +Not all players are ready. @@ -2210,6 +2336,41 @@ Upload this video to your Youtube account + + Reset + + + + Set the default server port for Hedgewars + + + + Invite your friends to your server in just 1 click! + + + + 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. + + + + Start private server + + + + + RoomNamePrompt + + Enter a name for your room. + + + + Cancel + Zrušit + + + Create room + + RoomsListModel @@ -2305,6 +2466,25 @@ + TCPBase + + Unable to start server at %1. + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + At least two teams are required to play! + + + + TeamShowWidget %1's team @@ -2314,13 +2494,17 @@ ThemePrompt - Select a theme for this map - - - Cancel Zrušit + + Search for a theme: + + + + Use selected theme + + binds @@ -2902,4 +3086,119 @@ + + server + + Not room master + + + + Corrupted hedgehogs info + + + + too many teams + + + + too many hedgehogs + + + + There's already a team with same name in the list + + + + round in progress + + + + restricted + + + + REMOVE_TEAM: no such team + + + + Not team owner! + + + + Less than two clans! + + + + Room with such name already exists + + + + Nickname already chosen + + + + Illegal nickname + + + + Protocol already known + + + + Bad number + + + + Nickname is already in use + + + + No checker rights + + + + Authentication failed + + + + 60 seconds cooldown after kick + + + + kicked + + + + Ping timeout + + + + bye + + + + Illegal room name + + + + No such room + + + + Joining restricted + + + + Registered users only + + + + You are banned in this room + + + + Empty config entry + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_da.ts --- a/share/hedgewars/Data/Locale/hedgewars_da.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_da.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,6 +2,13 @@ + About + + Unknown Compiler + + + + AbstractPage Go back @@ -91,6 +98,22 @@ Send Feedback + + Please give us feedback! + + + + We are always happy about suggestions, ideas, or bug reports. + + + + If you found a bug, you can see if it's already known here (english): + + + + Your email address is optional, but we may want to contact you. + + FreqSpinBox @@ -118,33 +141,71 @@ Game Options - Spilindstillinger + Spilindstillinger Game scheme will auto-select a weapon + + Map + Bane + + + Game options + + HWApplication - + %1 minutes - - - + + + + + + %1 hour + + + + + + + %1 hours + + + + + + + %1 day + + + + + + + %1 days + + + + + + + Scheme '%1' not supported - %1 hours - - - - %1 day - - - - %1 days + Cannot create directory %1 + Kan ikke oprette mappe %1 + + + Failed to open data directory: +%1 + +Please check your installation! @@ -387,10 +448,6 @@ - Largetunnels - - - Small islands @@ -434,6 +491,10 @@ All files Alle filer + + Large tunnels + + HWNetServersModel @@ -507,6 +568,21 @@ Login + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + Nickname: + + + + Password: + + HWUploadVideoDialog @@ -529,14 +605,6 @@ HatPrompt - Select a hat - - - - Filter: - - - Cancel Annuler @@ -544,6 +612,10 @@ Use selected hat + + Search for a hat: + + KB @@ -863,6 +935,18 @@ Play a game on an official server + + Feedback + + + + Play local network game + + + + Play official network game + + PageMultiplayer @@ -879,7 +963,7 @@ PageNetGame Control - Kontrol + Kontrol Edit game preferences @@ -889,6 +973,21 @@ Start Start + + Update + Opdater + + + Room controls + + + + + PageNetServer + + Insert your address here + + PageOptions @@ -1076,11 +1175,11 @@ PageRoomsList Create - Opret + Opret Join - Tilslut + Tilslut Admin features @@ -1088,7 +1187,7 @@ Room Name: - Navn på Rum: + Navn på Rum: Rules: @@ -1100,11 +1199,11 @@ Search: - Søg: + Søg: Clear - Ryd + Ryd %1 players online @@ -1113,6 +1212,30 @@ %1 spillere er online + + Search for a room: + + + + Create room + + + + Join room + + + + Room state + + + + Clear filters + + + + Open server administration page + + PageScheme @@ -1386,7 +1509,19 @@ Update - Opdater + Opdater + + + Restrict Unregistered Players Join + + + + Show games in lobby + + + + Show games in-progress + @@ -1488,11 +1623,11 @@ In lobby - I lobbyen + I lobbyen In progress - I gang + I gang Disabled @@ -1606,7 +1741,7 @@ Version - Version + Version Weapons @@ -1742,7 +1877,7 @@ This program is distributed under the GNU General Public License v2 - Dette program distribueres under GNU General Public License v2 + Dette program distribueres under GNU General Public License v2 There are videos that are currently being processed. @@ -1834,6 +1969,14 @@ Type the security code: + + Revision + + + + This program is distributed under the %1 + + QLineEdit @@ -1856,6 +1999,10 @@ Hedgewars %1 Hedgewars %1 + + -r%1 (%2) + + QMessageBox @@ -1904,35 +2051,12 @@ - Main - Error - - - Cannot create directory %1 - Kan ikke oprette mappe %1 - - - Failed to open data directory: -%1 - -Please check your installation! - - - - TCP - Error - + Kan ikke oprette mappe %1 Unable to start the server: %1. - Ude af stand til at starte serveren: %1. - - - Unable to run engine at - - - - Error code: %1 - + Ude af stand til at starte serveren: %1. Error while authenticating at google.com: @@ -2094,7 +2218,12 @@ - Hedgewars + Not all players are ready + + + + Are you sure you want to start this game? +Not all players are ready. @@ -2200,6 +2329,41 @@ Cancel uploading + + Reset + + + + Set the default server port for Hedgewars + + + + Invite your friends to your server in just 1 click! + + + + 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. + + + + Start private server + + + + + RoomNamePrompt + + Enter a name for your room. + + + + Cancel + Annuler + + + Create room + + RoomsListModel @@ -2295,6 +2459,25 @@ + TCPBase + + Unable to start server at %1. + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + At least two teams are required to play! + + + + TeamShowWidget %1's team @@ -2304,13 +2487,17 @@ ThemePrompt - Select a theme for this map - - - Cancel Annuler + + Search for a theme: + + + + Use selected theme + + binds @@ -2892,4 +3079,119 @@ DPad + + server + + Not room master + + + + Corrupted hedgehogs info + + + + too many teams + + + + too many hedgehogs + + + + There's already a team with same name in the list + + + + round in progress + + + + restricted + + + + REMOVE_TEAM: no such team + + + + Not team owner! + + + + Less than two clans! + + + + Room with such name already exists + + + + Nickname already chosen + + + + Illegal nickname + + + + Protocol already known + + + + Bad number + + + + Nickname is already in use + + + + No checker rights + + + + Authentication failed + + + + 60 seconds cooldown after kick + + + + kicked + + + + Ping timeout + + + + bye + + + + Illegal room name + + + + No such room + + + + Joining restricted + + + + Registered users only + + + + You are banned in this room + + + + Empty config entry + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_de.ts --- a/share/hedgewars/Data/Locale/hedgewars_de.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_de.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,6 +2,13 @@ + About + + Unknown Compiler + + + + AbstractPage Go back @@ -91,6 +98,22 @@ Send Feedback + + Please give us feedback! + + + + We are always happy about suggestions, ideas, or bug reports. + + + + If you found a bug, you can see if it's already known here (english): + + + + Your email address is optional, but we may want to contact you. + + FreqSpinBox @@ -118,34 +141,75 @@ Game Options - Spieloptionen + Spieloptionen Game scheme will auto-select a weapon + + Map + Karte + + + Game options + + HWApplication - + %1 minutes - - - + + + + + + %1 hour - - - + + + + + + %1 hours - - - + + + + + + %1 day + + + + + + + %1 days + + + + + + + Scheme '%1' not supported - %1 days - + Cannot create directory %1 + Verzeichnis %1 konnte nicht angelegt werden + + + Failed to open data directory: +%1 + +Please check your installation! + Konnte Daten-Verzeichnis nicht öffnen: +%1 + +Bitte überprüfe deine Installation! @@ -387,10 +451,6 @@ - Largetunnels - - - Small islands @@ -434,6 +494,10 @@ All files Alle Dateien + + Large tunnels + + HWNetServersModel @@ -507,6 +571,21 @@ Login + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + Nickname: + + + + Password: + + HWUploadVideoDialog @@ -529,14 +608,6 @@ HatPrompt - Select a hat - - - - Filter: - - - Cancel Abbrechen @@ -544,6 +615,10 @@ Use selected hat + + Search for a hat: + + KB @@ -863,6 +938,18 @@ Play a game on an official server + + Feedback + + + + Play local network game + + + + Play official network game + + PageMultiplayer @@ -879,7 +966,7 @@ PageNetGame Control - Steuerung + Steuerung Edit game preferences @@ -889,6 +976,21 @@ Start Start + + Update + Aktualisieren + + + Room controls + + + + + PageNetServer + + Insert your address here + + PageOptions @@ -1076,11 +1178,11 @@ PageRoomsList Create - Erstellen + Erstellen Join - Betreten + Betreten Admin features @@ -1088,7 +1190,7 @@ Room Name: - Raumname: + Raumname: Rules: @@ -1100,11 +1202,11 @@ Search: - Suche: + Suche: Clear - Leeren + Leeren %1 players online @@ -1113,6 +1215,30 @@ %1 Spieler online + + Search for a room: + + + + Create room + + + + Join room + + + + Room state + + + + Clear filters + + + + Open server administration page + + PageScheme @@ -1386,7 +1512,19 @@ Update - Aktualisieren + Aktualisieren + + + Restrict Unregistered Players Join + + + + Show games in lobby + + + + Show games in-progress + @@ -1488,11 +1626,11 @@ In lobby - In Lobby + In Lobby In progress - Im Spiel + Im Spiel Disabled @@ -1626,7 +1764,7 @@ Version - Version + Version Initial sound volume @@ -1742,7 +1880,7 @@ This program is distributed under the GNU General Public License v2 - Dieses Spiel wird unter den Bedingungen der GNU General Public License v2 verbreitet + Dieses Spiel wird unter den Bedingungen der GNU General Public License v2 verbreitet There are videos that are currently being processed. @@ -1836,6 +1974,14 @@ Type the security code: + + Revision + + + + This program is distributed under the %1 + + QLineEdit @@ -1858,6 +2004,10 @@ Hedgewars %1 Hedgewars %1 + + -r%1 (%2) + + QMessageBox @@ -1923,37 +2073,37 @@ Main - Error - Hedgewars - Fehler + Hedgewars - Fehler Cannot create directory %1 - Verzeichnis %1 konnte nicht angelegt werden + Verzeichnis %1 konnte nicht angelegt werden Failed to open data directory: %1 Please check your installation! - Konnte Daten-Verzeichnis nicht öffnen: + Konnte Daten-Verzeichnis nicht öffnen: %1 Bitte überprüfe deine Installation! TCP - Error - TCP - Fehler + TCP - Fehler Unable to start the server: %1. - Server %1 konnte nicht gestartet werden. + Server %1 konnte nicht gestartet werden. Unable to run engine at - Konnte Engine nicht starten: + Konnte Engine nicht starten: Error code: %1 - Fehler-Code: %1 + Fehler-Code: %1 Video upload - Error @@ -2101,7 +2251,12 @@ - Hedgewars + Not all players are ready + + + + Are you sure you want to start this game? +Not all players are ready. @@ -2207,6 +2362,41 @@ Upload this video to your Youtube account + + Reset + + + + Set the default server port for Hedgewars + + + + Invite your friends to your server in just 1 click! + + + + 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. + + + + Start private server + + + + + RoomNamePrompt + + Enter a name for your room. + + + + Cancel + Abbrechen + + + Create room + + RoomsListModel @@ -2302,6 +2492,25 @@ + TCPBase + + Unable to start server at %1. + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + At least two teams are required to play! + + + + TeamShowWidget %1's team @@ -2311,13 +2520,17 @@ ThemePrompt - Select a theme for this map - - - Cancel Abbrechen + + Search for a theme: + + + + Use selected theme + + binds @@ -2899,4 +3112,119 @@ Steuerkreuz + + server + + Not room master + + + + Corrupted hedgehogs info + + + + too many teams + + + + too many hedgehogs + + + + There's already a team with same name in the list + + + + round in progress + + + + restricted + + + + REMOVE_TEAM: no such team + + + + Not team owner! + + + + Less than two clans! + + + + Room with such name already exists + + + + Nickname already chosen + + + + Illegal nickname + + + + Protocol already known + + + + Bad number + + + + Nickname is already in use + + + + No checker rights + + + + Authentication failed + + + + 60 seconds cooldown after kick + + + + kicked + + + + Ping timeout + + + + bye + + + + Illegal room name + + + + No such room + + + + Joining restricted + + + + Registered users only + + + + You are banned in this room + + + + Empty config entry + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_el.ts --- a/share/hedgewars/Data/Locale/hedgewars_el.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_el.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,6 +2,13 @@ + About + + Unknown Compiler + + + + AbstractPage Go back @@ -91,6 +98,22 @@ Send Feedback + + Please give us feedback! + + + + We are always happy about suggestions, ideas, or bug reports. + + + + If you found a bug, you can see if it's already known here (english): + + + + Your email address is optional, but we may want to contact you. + + FreqSpinBox @@ -117,34 +140,68 @@ Επεξεργασία σχεδιασμών - Game Options - - - Game scheme will auto-select a weapon + + Map + Χάρτης + + + Game options + + HWApplication - + %1 minutes - - - + + + + + + %1 hour - - - + + + + + + %1 hours - - - + + + + + + %1 day - - - + + + + + + %1 days + + + + + + + Scheme '%1' not supported + + + + Cannot create directory %1 + Δεν μπορεί να δημιουργηθεί ο κατάλογος %1 + + + Failed to open data directory: +%1 + +Please check your installation! @@ -389,10 +446,6 @@ - Largetunnels - - - Small islands @@ -436,6 +489,10 @@ All files + + Large tunnels + + HWNetServersModel @@ -509,6 +566,21 @@ Login + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + Nickname: + + + + Password: + + HWUploadVideoDialog @@ -531,14 +603,6 @@ HatPrompt - Select a hat - - - - Filter: - - - Cancel Άκυρο @@ -546,6 +610,10 @@ Use selected hat + + Search for a hat: + + KB @@ -865,6 +933,18 @@ Play a game on an official server + + Feedback + + + + Play local network game + + + + Play official network game + + PageMultiplayer @@ -881,7 +961,7 @@ PageNetGame Control - Έλεγχος + Έλεγχος Edit game preferences @@ -891,6 +971,21 @@ Start Εκκίνηση + + Update + Αναβάθμιση + + + Room controls + + + + + PageNetServer + + Insert your address here + + PageOptions @@ -1078,11 +1173,11 @@ PageRoomsList Create - Δημιουργία + Δημιουργία Join - Σύνδεση + Σύνδεση Admin features @@ -1090,7 +1185,7 @@ Room Name: - Όνομα δωματίου : + Όνομα δωματίου : Rules: @@ -1102,11 +1197,11 @@ Search: - Αναζήτηση : + Αναζήτηση : Clear - Καθαρισμός + Καθαρισμός %1 players online @@ -1115,6 +1210,30 @@ + + Search for a room: + + + + Create room + + + + Join room + + + + Room state + + + + Clear filters + + + + Open server administration page + + PageScheme @@ -1388,7 +1507,19 @@ Update - Αναβάθμιση + Αναβάθμιση + + + Restrict Unregistered Players Join + + + + Show games in lobby + + + + Show games in-progress + @@ -1490,11 +1621,11 @@ In lobby - Σε αναμονή + Σε αναμονή In progress - Σε εξέλιξη + Σε εξέλιξη Disabled @@ -1608,7 +1739,7 @@ Version - Έκδοση + Έκδοση Weapons @@ -1793,10 +1924,6 @@ - This program is distributed under the GNU General Public License v2 - - - Style @@ -1836,6 +1963,14 @@ Type the security code: + + Revision + + + + This program is distributed under the %1 + + QLineEdit @@ -1858,6 +1993,10 @@ Hedgewars %1 Hedgewars %1 + + -r%1 (%2) + + QMessageBox @@ -1906,35 +2045,12 @@ - Main - Error - - - Cannot create directory %1 - Δεν μπορεί να δημιουργηθεί ο κατάλογος %1 - - - Failed to open data directory: -%1 - -Please check your installation! - - - - TCP - Error - + Δεν μπορεί να δημιουργηθεί ο κατάλογος %1 Unable to start the server: %1. - Δεν είναι δυνατόν να ξεκινήσει ο εξυπηρετητής : %1. - - - Unable to run engine at - - - - Error code: %1 - + Δεν είναι δυνατόν να ξεκινήσει ο εξυπηρετητής : %1. Error while authenticating at google.com: @@ -2096,7 +2212,12 @@ - Hedgewars + Not all players are ready + + + + Are you sure you want to start this game? +Not all players are ready. @@ -2202,6 +2323,41 @@ Cancel uploading + + Reset + + + + Set the default server port for Hedgewars + + + + Invite your friends to your server in just 1 click! + + + + 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. + + + + Start private server + + + + + RoomNamePrompt + + Enter a name for your room. + + + + Cancel + Άκυρο + + + Create room + + RoomsListModel @@ -2297,6 +2453,25 @@ + TCPBase + + Unable to start server at %1. + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + At least two teams are required to play! + + + + TeamShowWidget %1's team @@ -2306,13 +2481,17 @@ ThemePrompt - Select a theme for this map - - - Cancel Άκυρο + + Search for a theme: + + + + Use selected theme + + binds @@ -2894,4 +3073,119 @@ DPad + + server + + Not room master + + + + Corrupted hedgehogs info + + + + too many teams + + + + too many hedgehogs + + + + There's already a team with same name in the list + + + + round in progress + + + + restricted + + + + REMOVE_TEAM: no such team + + + + Not team owner! + + + + Less than two clans! + + + + Room with such name already exists + + + + Nickname already chosen + + + + Illegal nickname + + + + Protocol already known + + + + Bad number + + + + Nickname is already in use + + + + No checker rights + + + + Authentication failed + + + + 60 seconds cooldown after kick + + + + kicked + + + + Ping timeout + + + + bye + + + + Illegal room name + + + + No such room + + + + Joining restricted + + + + Registered users only + + + + You are banned in this room + + + + Empty config entry + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_en.ts --- a/share/hedgewars/Data/Locale/hedgewars_en.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_en.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,6 +2,13 @@ + About + + Unknown Compiler + + + + AbstractPage Go back @@ -91,6 +98,22 @@ Send Feedback + + Please give us feedback! + + + + We are always happy about suggestions, ideas, or bug reports. + + + + If you found a bug, you can see if it's already known here (english): + + + + Your email address is optional, but we may want to contact you. + + FreqSpinBox @@ -117,34 +140,68 @@ Edit schemes - Game Options - - - Game scheme will auto-select a weapon + + Map + Map + + + Game options + + HWApplication - + %1 minutes - - - + + + + + + %1 hour - - - + + + + + + %1 hours - - - + + + + + + %1 day - - - + + + + + + %1 days + + + + + + + Scheme '%1' not supported + + + + Cannot create directory %1 + Cannot create directory %1 + + + Failed to open data directory: +%1 + +Please check your installation! @@ -387,10 +444,6 @@ - Largetunnels - - - Small islands @@ -434,6 +487,10 @@ All files + + Large tunnels + + HWNetServersModel @@ -507,6 +564,21 @@ Login + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + Nickname: + + + + Password: + + HWUploadVideoDialog @@ -529,14 +601,6 @@ HatPrompt - Select a hat - - - - Filter: - - - Cancel Cancel @@ -544,6 +608,10 @@ Use selected hat + + Search for a hat: + + KB @@ -863,6 +931,18 @@ Play a game on an official server + + Feedback + + + + Play local network game + + + + Play official network game + + PageMultiplayer @@ -879,7 +959,7 @@ PageNetGame Control - Control + Control Edit game preferences @@ -889,6 +969,21 @@ Start Start + + Update + Update + + + Room controls + + + + + PageNetServer + + Insert your address here + + PageOptions @@ -1076,11 +1171,11 @@ PageRoomsList Create - Create + Create Join - Join + Join Admin features @@ -1088,7 +1183,7 @@ Room Name: - Room Name: + Room Name: Rules: @@ -1098,14 +1193,6 @@ Weapons: - - Search: - - - - Clear - - %1 players online @@ -1113,6 +1200,30 @@ + + Search for a room: + + + + Create room + + + + Join room + + + + Room state + + + + Clear filters + + + + Open server administration page + + PageScheme @@ -1386,7 +1497,19 @@ Update - Update + Update + + + Restrict Unregistered Players Join + + + + Show games in lobby + + + + Show games in-progress + @@ -1487,14 +1610,6 @@ - In lobby - - - - In progress - - - Disabled @@ -1606,7 +1721,7 @@ Version - Version + Version Weapons @@ -1741,10 +1856,6 @@ - This program is distributed under the GNU General Public License v2 - - - There are videos that are currently being processed. Exiting now will abort them. Do you really want to quit? @@ -1834,6 +1945,14 @@ Type the security code: + + Revision + + + + This program is distributed under the %1 + + QLineEdit @@ -1856,6 +1975,10 @@ Hedgewars %1 Hedgewars %1 + + -r%1 (%2) + + QMessageBox @@ -1918,35 +2041,12 @@ - Main - Error - - - Cannot create directory %1 - Cannot create directory %1 - - - Failed to open data directory: -%1 - -Please check your installation! - - - - TCP - Error - + Cannot create directory %1 Unable to start the server: %1. - Unable to start the server: %1. - - - Unable to run engine at - - - - Error code: %1 - + Unable to start the server: %1. Video upload - Error @@ -2094,7 +2194,12 @@ - Hedgewars + Not all players are ready + + + + Are you sure you want to start this game? +Not all players are ready. @@ -2200,6 +2305,41 @@ Upload this video to your Youtube account + + Reset + + + + Set the default server port for Hedgewars + + + + Invite your friends to your server in just 1 click! + + + + 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. + + + + Start private server + + + + + RoomNamePrompt + + Enter a name for your room. + + + + Cancel + Cancel + + + Create room + + RoomsListModel @@ -2295,6 +2435,25 @@ + TCPBase + + Unable to start server at %1. + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + At least two teams are required to play! + + + + TeamShowWidget %1's team @@ -2304,13 +2463,17 @@ ThemePrompt - Select a theme for this map - - - Cancel Cancel + + Search for a theme: + + + + Use selected theme + + binds @@ -2892,4 +3055,119 @@ + + server + + Not room master + + + + Corrupted hedgehogs info + + + + too many teams + + + + too many hedgehogs + + + + There's already a team with same name in the list + + + + round in progress + + + + restricted + + + + REMOVE_TEAM: no such team + + + + Not team owner! + + + + Less than two clans! + + + + Room with such name already exists + + + + Nickname already chosen + + + + Illegal nickname + + + + Protocol already known + + + + Bad number + + + + Nickname is already in use + + + + No checker rights + + + + Authentication failed + + + + 60 seconds cooldown after kick + + + + kicked + + + + Ping timeout + + + + bye + + + + Illegal room name + + + + No such room + + + + Joining restricted + + + + Registered users only + + + + You are banned in this room + + + + Empty config entry + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_es.ts --- a/share/hedgewars/Data/Locale/hedgewars_es.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_es.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,6 +2,13 @@ + About + + Unknown Compiler + + + + AbstractPage Go back @@ -91,6 +98,22 @@ Send Feedback + + Please give us feedback! + + + + We are always happy about suggestions, ideas, or bug reports. + + + + If you found a bug, you can see if it's already known here (english): + + + + Your email address is optional, but we may want to contact you. + + FreqSpinBox @@ -118,33 +141,71 @@ Game Options - Opciones de juego + Opciones de juego Game scheme will auto-select a weapon + + Map + Mapa + + + Game options + + HWApplication - + %1 minutes - - - + + + + + + %1 hour - - - + + + + + + %1 hours - - - + + + + + + %1 day - - - + + + + + + %1 days + + + + + + + Scheme '%1' not supported + + + + Cannot create directory %1 + No se pudo crear el directorio %1 + + + Failed to open data directory: +%1 + +Please check your installation! @@ -387,10 +448,6 @@ - Largetunnels - - - Small islands @@ -434,6 +491,10 @@ All files Todos los ficheros + + Large tunnels + + HWNetServersModel @@ -507,6 +568,21 @@ Login + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + Nickname: + + + + Password: + + HWUploadVideoDialog @@ -529,14 +605,6 @@ HatPrompt - Select a hat - - - - Filter: - - - Cancel Cancelar @@ -544,6 +612,10 @@ Use selected hat + + Search for a hat: + + KB @@ -863,6 +935,18 @@ Play a game on an official server + + Feedback + + + + Play local network game + + + + Play official network game + + PageMultiplayer @@ -879,7 +963,7 @@ PageNetGame Control - Opciones + Opciones Edit game preferences @@ -889,6 +973,21 @@ Start Empezar + + Update + Actualizar + + + Room controls + + + + + PageNetServer + + Insert your address here + + PageOptions @@ -1076,11 +1175,11 @@ PageRoomsList Create - Crear + Crear Join - Entrar + Entrar Admin features @@ -1088,7 +1187,7 @@ Room Name: - Nombre de la sala: + Nombre de la sala: Rules: @@ -1100,11 +1199,11 @@ Search: - Búsqueda: + Búsqueda: Clear - Limpiar + Limpiar %1 players online @@ -1113,6 +1212,30 @@ + + Search for a room: + + + + Create room + + + + Join room + + + + Room state + + + + Clear filters + + + + Open server administration page + + PageScheme @@ -1386,7 +1509,19 @@ Update - Actualizar + Actualizar + + + Restrict Unregistered Players Join + + + + Show games in lobby + + + + Show games in-progress + @@ -1488,11 +1623,11 @@ In lobby - En espera + En espera In progress - En progreso + En progreso Disabled @@ -1626,7 +1761,7 @@ Version - Versión + Versión Initial sound volume @@ -1741,10 +1876,6 @@ % duración de retirada - This program is distributed under the GNU General Public License v2 - - - There are videos that are currently being processed. Exiting now will abort them. Do you really want to quit? @@ -1834,6 +1965,14 @@ Type the security code: + + Revision + + + + This program is distributed under the %1 + + QLineEdit @@ -1856,6 +1995,10 @@ Hedgewars %1 Hedgewars %1 + + -r%1 (%2) + + QMessageBox @@ -1918,35 +2061,12 @@ - Main - Error - - - Cannot create directory %1 - No se pudo crear el directorio %1 - - - Failed to open data directory: -%1 - -Please check your installation! - - - - TCP - Error - + No se pudo crear el directorio %1 Unable to start the server: %1. - No se pudo iniciar el servidor: %1. - - - Unable to run engine at - - - - Error code: %1 - + No se pudo iniciar el servidor: %1. Video upload - Error @@ -2094,7 +2214,12 @@ - Hedgewars + Not all players are ready + + + + Are you sure you want to start this game? +Not all players are ready. @@ -2200,6 +2325,41 @@ Upload this video to your Youtube account + + Reset + + + + Set the default server port for Hedgewars + + + + Invite your friends to your server in just 1 click! + + + + 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. + + + + Start private server + + + + + RoomNamePrompt + + Enter a name for your room. + + + + Cancel + Cancelar + + + Create room + + RoomsListModel @@ -2295,6 +2455,25 @@ + TCPBase + + Unable to start server at %1. + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + At least two teams are required to play! + + + + TeamShowWidget %1's team @@ -2304,13 +2483,17 @@ ThemePrompt - Select a theme for this map - - - Cancel Cancelar + + Search for a theme: + + + + Use selected theme + + binds @@ -2892,4 +3075,119 @@ DPad + + server + + Not room master + + + + Corrupted hedgehogs info + + + + too many teams + + + + too many hedgehogs + + + + There's already a team with same name in the list + + + + round in progress + + + + restricted + + + + REMOVE_TEAM: no such team + + + + Not team owner! + + + + Less than two clans! + + + + Room with such name already exists + + + + Nickname already chosen + + + + Illegal nickname + + + + Protocol already known + + + + Bad number + + + + Nickname is already in use + + + + No checker rights + + + + Authentication failed + + + + 60 seconds cooldown after kick + + + + kicked + + + + Ping timeout + + + + bye + + + + Illegal room name + + + + No such room + + + + Joining restricted + + + + Registered users only + + + + You are banned in this room + + + + Empty config entry + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_fi.ts --- a/share/hedgewars/Data/Locale/hedgewars_fi.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_fi.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,6 +2,13 @@ + About + + Unknown Compiler + + + + AbstractPage Go back @@ -91,6 +98,22 @@ Send Feedback + + Please give us feedback! + + + + We are always happy about suggestions, ideas, or bug reports. + + + + If you found a bug, you can see if it's already known here (english): + + + + Your email address is optional, but we may want to contact you. + + FreqSpinBox @@ -117,34 +140,68 @@ Muokkaa kaavaa - Game Options - - - Game scheme will auto-select a weapon + + Map + Kartta + + + Game options + + HWApplication - + %1 minutes - - - + + + + + + %1 hour - - - + + + + + + %1 hours - - - + + + + + + %1 day - - - + + + + + + %1 days + + + + + + + Scheme '%1' not supported + + + + Cannot create directory %1 + Hakemiston %1 luonti epäonnistui + + + Failed to open data directory: +%1 + +Please check your installation! @@ -387,10 +444,6 @@ - Largetunnels - - - Small islands @@ -434,6 +487,10 @@ All files + + Large tunnels + + HWNetServersModel @@ -507,6 +564,21 @@ Login + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + Nickname: + + + + Password: + + HWUploadVideoDialog @@ -529,14 +601,6 @@ HatPrompt - Select a hat - - - - Filter: - - - Cancel Peruuta @@ -544,6 +608,10 @@ Use selected hat + + Search for a hat: + + KB @@ -863,6 +931,18 @@ Play a game on an official server + + Feedback + + + + Play local network game + + + + Play official network game + + PageMultiplayer @@ -879,7 +959,7 @@ PageNetGame Control - Säädöt + Säädöt Edit game preferences @@ -889,6 +969,21 @@ Start + + Update + Päivitä + + + Room controls + + + + + PageNetServer + + Insert your address here + + PageOptions @@ -1076,11 +1171,11 @@ PageRoomsList Create - Luo + Luo Join - Liity + Liity Admin features @@ -1088,7 +1183,7 @@ Room Name: - Huoneen nimi: + Huoneen nimi: Rules: @@ -1100,11 +1195,11 @@ Search: - Haku: + Haku: Clear - Tyhjennä + Tyhjennä %1 players online @@ -1113,6 +1208,30 @@ + + Search for a room: + + + + Create room + + + + Join room + + + + Room state + + + + Clear filters + + + + Open server administration page + + PageScheme @@ -1386,7 +1505,19 @@ Update - Päivitä + Päivitä + + + Restrict Unregistered Players Join + + + + Show games in lobby + + + + Show games in-progress + @@ -1488,11 +1619,11 @@ In lobby - Aulassa + Aulassa In progress - Kesken + Kesken Disabled @@ -1606,7 +1737,7 @@ Version - Versio + Versio Weapons @@ -1741,10 +1872,6 @@ - This program is distributed under the GNU General Public License v2 - - - There are videos that are currently being processed. Exiting now will abort them. Do you really want to quit? @@ -1834,6 +1961,14 @@ Type the security code: + + Revision + + + + This program is distributed under the %1 + + QLineEdit @@ -1856,6 +1991,10 @@ Hedgewars %1 Hedgewars %1 + + -r%1 (%2) + + QMessageBox @@ -1918,35 +2057,12 @@ - Main - Error - - - Cannot create directory %1 - Hakemiston %1 luonti epäonnistui - - - Failed to open data directory: -%1 - -Please check your installation! - - - - TCP - Error - + Hakemiston %1 luonti epäonnistui Unable to start the server: %1. - Palvelinta ei pystytty käynnistämään: %1. - - - Unable to run engine at - - - - Error code: %1 - + Palvelinta ei pystytty käynnistämään: %1. Video upload - Error @@ -2094,7 +2210,12 @@ - Hedgewars + Not all players are ready + + + + Are you sure you want to start this game? +Not all players are ready. @@ -2200,6 +2321,41 @@ Upload this video to your Youtube account + + Reset + + + + Set the default server port for Hedgewars + + + + Invite your friends to your server in just 1 click! + + + + 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. + + + + Start private server + + + + + RoomNamePrompt + + Enter a name for your room. + + + + Cancel + Peruuta + + + Create room + + RoomsListModel @@ -2295,6 +2451,25 @@ + TCPBase + + Unable to start server at %1. + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + At least two teams are required to play! + + + + TeamShowWidget %1's team @@ -2304,13 +2479,17 @@ ThemePrompt - Select a theme for this map - - - Cancel Peruuta + + Search for a theme: + + + + Use selected theme + + binds @@ -2892,4 +3071,119 @@ Hiiri: Vasen nappi + + server + + Not room master + + + + Corrupted hedgehogs info + + + + too many teams + + + + too many hedgehogs + + + + There's already a team with same name in the list + + + + round in progress + + + + restricted + + + + REMOVE_TEAM: no such team + + + + Not team owner! + + + + Less than two clans! + + + + Room with such name already exists + + + + Nickname already chosen + + + + Illegal nickname + + + + Protocol already known + + + + Bad number + + + + Nickname is already in use + + + + No checker rights + + + + Authentication failed + + + + 60 seconds cooldown after kick + + + + kicked + + + + Ping timeout + + + + bye + + + + Illegal room name + + + + No such room + + + + Joining restricted + + + + Registered users only + + + + You are banned in this room + + + + Empty config entry + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_fr.ts --- a/share/hedgewars/Data/Locale/hedgewars_fr.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_fr.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,6 +2,13 @@ + About + + Unknown Compiler + + + + AbstractPage Go back @@ -91,6 +98,22 @@ Send Feedback + + Please give us feedback! + + + + We are always happy about suggestions, ideas, or bug reports. + + + + If you found a bug, you can see if it's already known here (english): + + + + Your email address is optional, but we may want to contact you. + + FreqSpinBox @@ -117,34 +140,68 @@ Éditer les paramètres - Game Options - - - Game scheme will auto-select a weapon + + Map + Carte + + + Game options + + HWApplication - + %1 minutes - - - + + + + + + %1 hour - - - + + + + + + %1 hours - - - + + + + + + %1 day - - - + + + + + + %1 days + + + + + + + Scheme '%1' not supported + + + + Cannot create directory %1 + Impossible de créer le dossier %1 + + + Failed to open data directory: +%1 + +Please check your installation! @@ -387,10 +444,6 @@ - Largetunnels - - - Small islands @@ -434,6 +487,10 @@ All files + + Large tunnels + + HWNetServersModel @@ -507,6 +564,21 @@ Login + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + Nickname: + + + + Password: + + HWUploadVideoDialog @@ -529,14 +601,6 @@ HatPrompt - Select a hat - - - - Filter: - - - Cancel Annuler @@ -544,6 +608,10 @@ Use selected hat + + Search for a hat: + + KB @@ -863,6 +931,18 @@ Play a game on an official server + + Feedback + + + + Play local network game + + + + Play official network game + + PageMultiplayer @@ -879,7 +959,7 @@ PageNetGame Control - Contrôles + Contrôles Edit game preferences @@ -889,6 +969,21 @@ Start Démarrer + + Update + Mise à jour + + + Room controls + + + + + PageNetServer + + Insert your address here + + PageOptions @@ -1076,11 +1171,11 @@ PageRoomsList Create - Création + Création Join - Rejoindre + Rejoindre Admin features @@ -1088,7 +1183,7 @@ Room Name: - Nom du salon: + Nom du salon: Rules: @@ -1100,11 +1195,11 @@ Search: - Recherche : + Recherche : Clear - Effacer + Effacer %1 players online @@ -1113,6 +1208,30 @@ + + Search for a room: + + + + Create room + + + + Join room + + + + Room state + + + + Clear filters + + + + Open server administration page + + PageScheme @@ -1386,7 +1505,19 @@ Update - Mise à jour + Mise à jour + + + Restrict Unregistered Players Join + + + + Show games in lobby + + + + Show games in-progress + @@ -1488,11 +1619,11 @@ In lobby - En attente + En attente In progress - En cours + En cours Disabled @@ -1626,7 +1757,7 @@ Version - Version + Version Initial sound volume @@ -1741,10 +1872,6 @@ - This program is distributed under the GNU General Public License v2 - - - There are videos that are currently being processed. Exiting now will abort them. Do you really want to quit? @@ -1834,6 +1961,14 @@ Type the security code: + + Revision + + + + This program is distributed under the %1 + + QLineEdit @@ -1856,6 +1991,10 @@ Hedgewars %1 Hedgewars %1 + + -r%1 (%2) + + QMessageBox @@ -1918,35 +2057,12 @@ - Main - Error - - - Cannot create directory %1 - Impossible de créer le dossier %1 - - - Failed to open data directory: -%1 - -Please check your installation! - - - - TCP - Error - + Impossible de créer le dossier %1 Unable to start the server: %1. - Impossible de démarrer le serveur: %1. - - - Unable to run engine at - - - - Error code: %1 - + Impossible de démarrer le serveur: %1. Video upload - Error @@ -2093,7 +2209,12 @@ - Hedgewars + Not all players are ready + + + + Are you sure you want to start this game? +Not all players are ready. @@ -2199,6 +2320,41 @@ Upload this video to your Youtube account + + Reset + + + + Set the default server port for Hedgewars + + + + Invite your friends to your server in just 1 click! + + + + 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. + + + + Start private server + + + + + RoomNamePrompt + + Enter a name for your room. + + + + Cancel + Annuler + + + Create room + + RoomsListModel @@ -2294,6 +2450,25 @@ + TCPBase + + Unable to start server at %1. + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + At least two teams are required to play! + + + + TeamShowWidget %1's team @@ -2303,13 +2478,17 @@ ThemePrompt - Select a theme for this map - - - Cancel Annuler + + Search for a theme: + + + + Use selected theme + + binds @@ -2892,4 +3071,119 @@ Effacer + + server + + Not room master + + + + Corrupted hedgehogs info + + + + too many teams + + + + too many hedgehogs + + + + There's already a team with same name in the list + + + + round in progress + + + + restricted + + + + REMOVE_TEAM: no such team + + + + Not team owner! + + + + Less than two clans! + + + + Room with such name already exists + + + + Nickname already chosen + + + + Illegal nickname + + + + Protocol already known + + + + Bad number + + + + Nickname is already in use + + + + No checker rights + + + + Authentication failed + + + + 60 seconds cooldown after kick + + + + kicked + + + + Ping timeout + + + + bye + + + + Illegal room name + + + + No such room + + + + Joining restricted + + + + Registered users only + + + + You are banned in this room + + + + Empty config entry + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_gl.ts --- a/share/hedgewars/Data/Locale/hedgewars_gl.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_gl.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,6 +2,13 @@ + About + + Unknown Compiler + + + + AbstractPage Go back @@ -91,6 +98,22 @@ Send Feedback + + Please give us feedback! + + + + We are always happy about suggestions, ideas, or bug reports. + + + + If you found a bug, you can see if it's already known here (english): + + + + Your email address is optional, but we may want to contact you. + + FreqSpinBox @@ -117,34 +140,68 @@ Editar os modos de xogo - Game Options - - - Game scheme will auto-select a weapon + + Map + Mapa + + + Game options + + HWApplication - + %1 minutes - - - + + + + + + %1 hour - - - + + + + + + %1 hours - - - + + + + + + %1 day - - - + + + + + + %1 days + + + + + + + Scheme '%1' not supported + + + + Cannot create directory %1 + Non se puido crear o directorio %1 + + + Failed to open data directory: +%1 + +Please check your installation! @@ -387,10 +444,6 @@ - Largetunnels - - - Small islands @@ -434,6 +487,10 @@ All files + + Large tunnels + + HWNetServersModel @@ -507,6 +564,21 @@ Login + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + Nickname: + + + + Password: + + HWUploadVideoDialog @@ -529,14 +601,6 @@ HatPrompt - Select a hat - - - - Filter: - - - Cancel Cancelar @@ -544,6 +608,10 @@ Use selected hat + + Search for a hat: + + KB @@ -863,6 +931,18 @@ Play a game on an official server + + Feedback + + + + Play local network game + + + + Play official network game + + PageMultiplayer @@ -879,7 +959,7 @@ PageNetGame Control - Control + Control Edit game preferences @@ -889,6 +969,21 @@ Start Iniciar + + Update + Actualizar + + + Room controls + + + + + PageNetServer + + Insert your address here + + PageOptions @@ -1076,11 +1171,11 @@ PageRoomsList Create - Crear + Crear Join - Entrar + Entrar Admin features @@ -1088,7 +1183,7 @@ Room Name: - Nome da sala: + Nome da sala: Rules: @@ -1099,12 +1194,8 @@ - Search: - - - Clear - Borrado + Borrado %1 players online @@ -1113,6 +1204,30 @@ + + Search for a room: + + + + Create room + + + + Join room + + + + Room state + + + + Clear filters + + + + Open server administration page + + PageScheme @@ -1366,7 +1481,7 @@ Update - Actualizar + Actualizar Follow @@ -1388,6 +1503,18 @@ Remove friend + + Restrict Unregistered Players Join + + + + Show games in lobby + + + + Show games in-progress + + QCheckBox @@ -1546,14 +1673,6 @@ Any - - In lobby - - - - In progress - - QGroupBox @@ -1606,7 +1725,7 @@ Version - Versión + Versión Weapons @@ -1791,10 +1910,6 @@ - This program is distributed under the GNU General Public License v2 - - - Style @@ -1834,6 +1949,14 @@ Type the security code: + + Revision + + + + This program is distributed under the %1 + + QLineEdit @@ -1856,6 +1979,10 @@ Hedgewars %1 Hedgewars %1 + + -r%1 (%2) + + QMessageBox @@ -1904,35 +2031,12 @@ - Main - Error - - - Cannot create directory %1 - Non se puido crear o directorio %1 - - - Failed to open data directory: -%1 - -Please check your installation! - - - - TCP - Error - + Non se puido crear o directorio %1 Unable to start the server: %1. - Non se puido iniciar o servidor: %1. - - - Unable to run engine at - - - - Error code: %1 - + Non se puido iniciar o servidor: %1. Error while authenticating at google.com: @@ -2093,7 +2197,12 @@ - Hedgewars + Not all players are ready + + + + Are you sure you want to start this game? +Not all players are ready. @@ -2199,6 +2308,41 @@ Cancel uploading + + Reset + + + + Set the default server port for Hedgewars + + + + Invite your friends to your server in just 1 click! + + + + 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. + + + + Start private server + + + + + RoomNamePrompt + + Enter a name for your room. + + + + Cancel + Cancelar + + + Create room + + RoomsListModel @@ -2294,6 +2438,25 @@ + TCPBase + + Unable to start server at %1. + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + At least two teams are required to play! + + + + TeamShowWidget %1's team @@ -2303,13 +2466,17 @@ ThemePrompt - Select a theme for this map - - - Cancel Cancelar + + Search for a theme: + + + + Use selected theme + + binds @@ -2891,4 +3058,119 @@ Mando + + server + + Not room master + + + + Corrupted hedgehogs info + + + + too many teams + + + + too many hedgehogs + + + + There's already a team with same name in the list + + + + round in progress + + + + restricted + + + + REMOVE_TEAM: no such team + + + + Not team owner! + + + + Less than two clans! + + + + Room with such name already exists + + + + Nickname already chosen + + + + Illegal nickname + + + + Protocol already known + + + + Bad number + + + + Nickname is already in use + + + + No checker rights + + + + Authentication failed + + + + 60 seconds cooldown after kick + + + + kicked + + + + Ping timeout + + + + bye + + + + Illegal room name + + + + No such room + + + + Joining restricted + + + + Registered users only + + + + You are banned in this room + + + + Empty config entry + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_hu.ts --- a/share/hedgewars/Data/Locale/hedgewars_hu.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_hu.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,6 +2,13 @@ + About + + Unknown Compiler + + + + AbstractPage Go back @@ -91,6 +98,22 @@ Send Feedback + + Please give us feedback! + + + + We are always happy about suggestions, ideas, or bug reports. + + + + If you found a bug, you can see if it's already known here (english): + + + + Your email address is optional, but we may want to contact you. + + FreqSpinBox @@ -116,34 +139,63 @@ Sémák szerkesztése - Game Options - - - Game scheme will auto-select a weapon + + Map + Pálya + + + Game options + + HWApplication - + %1 minutes - - - + + + + + %1 hour - - - + + + + + %1 hours - - - + + + + + %1 day - - - + + + + + %1 days + + + + + + Scheme '%1' not supported + + + + Cannot create directory %1 + Nem sikerült létrehozni %1 + + + Failed to open data directory: +%1 + +Please check your installation! @@ -386,10 +438,6 @@ - Largetunnels - - - Small islands @@ -433,6 +481,10 @@ All files + + Large tunnels + + HWNetServersModel @@ -506,6 +558,21 @@ Login + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + Nickname: + + + + Password: + + HWUploadVideoDialog @@ -528,14 +595,6 @@ HatPrompt - Select a hat - - - - Filter: - - - Cancel Mégse @@ -543,6 +602,10 @@ Use selected hat + + Search for a hat: + + KB @@ -856,6 +919,18 @@ Play a game on an official server + + Feedback + + + + Play local network game + + + + Play official network game + + PageMultiplayer @@ -872,7 +947,7 @@ PageNetGame Control - Irányítás + Irányítás Edit game preferences @@ -882,6 +957,21 @@ Start Start + + Update + Frissítés + + + Room controls + + + + + PageNetServer + + Insert your address here + + PageOptions @@ -1069,11 +1159,11 @@ PageRoomsList Create - Létrehozás + Létrehozás Join - Csatlakozás + Csatlakozás Admin features @@ -1081,7 +1171,7 @@ Room Name: - Szoba neve: + Szoba neve: Rules: @@ -1092,12 +1182,8 @@ - Search: - - - Clear - Törlés + Törlés %1 players online @@ -1105,6 +1191,30 @@ + + Search for a room: + + + + Create room + + + + Join room + + + + Room state + + + + Clear filters + + + + Open server administration page + + PageScheme @@ -1377,7 +1487,19 @@ Update - Frissítés + Frissítés + + + Restrict Unregistered Players Join + + + + Show games in lobby + + + + Show games in-progress + @@ -1478,14 +1600,6 @@ - In lobby - - - - In progress - - - Disabled @@ -1597,7 +1711,7 @@ Version - Verzió + Verzió Weapons @@ -1732,10 +1846,6 @@ - This program is distributed under the GNU General Public License v2 - - - There are videos that are currently being processed. Exiting now will abort them. Do you really want to quit? @@ -1825,6 +1935,14 @@ Type the security code: + + Revision + + + + This program is distributed under the %1 + + QLineEdit @@ -1847,6 +1965,10 @@ Hedgewars %1 Hedgewars %1 + + -r%1 (%2) + + QMessageBox @@ -1909,35 +2031,12 @@ - Main - Error - - - Cannot create directory %1 - Nem sikerült létrehozni %1 - - - Failed to open data directory: -%1 - -Please check your installation! - - - - TCP - Error - + Nem sikerült létrehozni %1 Unable to start the server: %1. - Nem sikerült a szerverhez csatlakozni: %1. - - - Unable to run engine at - - - - Error code: %1 - + Nem sikerült a szerverhez csatlakozni: %1. Video upload - Error @@ -2083,7 +2182,12 @@ - Hedgewars + Not all players are ready + + + + Are you sure you want to start this game? +Not all players are ready. @@ -2189,6 +2293,41 @@ Upload this video to your Youtube account + + Reset + + + + Set the default server port for Hedgewars + + + + Invite your friends to your server in just 1 click! + + + + 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. + + + + Start private server + + + + + RoomNamePrompt + + Enter a name for your room. + + + + Cancel + Mégse + + + Create room + + RoomsListModel @@ -2284,6 +2423,25 @@ + TCPBase + + Unable to start server at %1. + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + At least two teams are required to play! + + + + TeamShowWidget %1's team @@ -2293,13 +2451,17 @@ ThemePrompt - Select a theme for this map - - - Cancel Mégse + + Search for a theme: + + + + Use selected theme + + binds @@ -2881,4 +3043,119 @@ DPad + + server + + Not room master + + + + Corrupted hedgehogs info + + + + too many teams + + + + too many hedgehogs + + + + There's already a team with same name in the list + + + + round in progress + + + + restricted + + + + REMOVE_TEAM: no such team + + + + Not team owner! + + + + Less than two clans! + + + + Room with such name already exists + + + + Nickname already chosen + + + + Illegal nickname + + + + Protocol already known + + + + Bad number + + + + Nickname is already in use + + + + No checker rights + + + + Authentication failed + + + + 60 seconds cooldown after kick + + + + kicked + + + + Ping timeout + + + + bye + + + + Illegal room name + + + + No such room + + + + Joining restricted + + + + Registered users only + + + + You are banned in this room + + + + Empty config entry + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_it.ts --- a/share/hedgewars/Data/Locale/hedgewars_it.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_it.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,6 +2,13 @@ + About + + Unknown Compiler + Compilatore sconosciuto + + + AbstractPage Go back @@ -23,72 +30,88 @@ BanDialog IP - IP + IP Nick - + Soprannome IP/Nick - + IP/Soprannome Reason - + Motivo Duration - + Durata Ok - + Ok Cancel - Annulla + Annulla you know why - + Warning - + Avviso Please, specify %1 - + Per favore, specifica %1 nickname - + soprannome permanent - + permanente DataManager Use Default - + Usa Default FeedbackDialog View - + Leggi Cancel - Annulla + Annulla Send Feedback + Invia Commento + + + Please give us feedback! + + + + We are always happy about suggestions, ideas, or bug reports. + + + + If you found a bug, you can see if it's already known here (english): + + + + Your email address is optional, but we may want to contact you. @@ -118,34 +141,75 @@ Game Options - Opzioni di Gioco + Opzioni di Gioco Game scheme will auto-select a weapon - + Lo schema di gioco sceglierà automaticamente un'arma + + + Map + Mappa + + + Game options + Opzioni di gioco HWApplication - + %1 minutes - - - + + %1 minuto + %1 minuti + + + %1 hour - - - + + %1 ora + %1 ore + + + %1 hours - - - + + %1 ora + %1 ore + + + %1 day + + %1 giorno + %1 giorni + + + + %1 days + + %1 giorno + %1 giorni + + + + Scheme '%1' not supported - %1 days - + Cannot create directory %1 + Impossibile creare la directory %1 + + + Failed to open data directory: +%1 + +Please check your installation! + Impossibile creare la directory dati: +%1 + +Per favore controlla l'installazione! @@ -232,25 +296,25 @@ Nickname - Nickname + Nome No nickname supplied. - Nessun nickname valido inserito. + Nessun nome valido inserito. Someone already uses your nickname %1 on the server. Please pick another nickname: - Qualcun altro sta già usando il tuo nickname %1 sul server. -Per favore scegli un altro nickname: + Qualcun altro sta già usando il tuo nome %1 sul server. +Per favore scegli un altro nome: %1's Team - + Squadra di %1 Hedgewars - Nick registered - + Hedgewars - Nome registrato This nick is registered, and you haven't specified a password. @@ -258,44 +322,53 @@ If this nick isn't yours, please register your own nick at www.hedgewars.org Password: - + Questo nome è registrato, e non hai specificato una password. + +Se questo nome non è tuo, per favore registra un tuo nome a www.hedgewars.org + +Password: Your nickname is not registered. To prevent someone else from using it, please register it at www.hedgewars.org - + Il tuo nome non è registrato. +Per evitare che qualcun altro lo usi, +per favore registralo su www.hedgewars.org Your password wasn't saved either. - + + +Anche la tua password non è stata salvata. Hedgewars - Empty nickname - + Hedgewars - Nome vuoto Hedgewars - Wrong password - + Hedgewars - Password sbagliata You entered a wrong password. - + Hai inserito una password sbagliata. Try Again - + Prova ancora Hedgewars - Connection error - + Hedgewars - Errore di connessione You reconnected too fast. Please wait a few seconds and try again. - + Ti sei ricollegato troppo velocemente. +Per favore aspetta qualche secondo e prova di nuovo. @@ -349,91 +422,91 @@ Map type: - + Tipo mappa: Image map - + Immagine mappa Mission map - + Mappa missione Hand-drawn - Disegnata a mano + Disegnata a mano Randomly generated - + Generata casualmente Random maze - + Labirinto casuale Random - Casuale + Casuale Map preview: - + Anteprima mappa: Load map drawing - + Carica disegno mappa Edit map drawing - - - - Largetunnels - + Modifica disegno mappa Small islands - + Isole piccole Medium islands - + Isole medie Large islands - + Isole grandi Map size: - + Dimensione mappa: Maze style: - + Stile labirinto: Mission: - + Missione: Map: - + Mappa: Theme: - + Tema: Load drawn map - Carica mappa disegnata + Carica mappa disegnata Drawn Maps - Mappe disegnate + Mappe disegnate All files - Tutti i file + Tutti i file + + + Large tunnels + @@ -506,6 +579,21 @@ HWPasswordDialog Login + Login + + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + Nickname: + + + + Password: @@ -524,26 +612,22 @@ HatButton Change hat (%1) - + Cambia cappello (%1) HatPrompt - Select a hat - - - - Filter: - - - Cancel - Annulla + Annulla Use selected hat - + Usa cappello selezionato + + + Search for a hat: + Cerca un cappello: @@ -557,7 +641,7 @@ KeyBinder Category - + Categoria @@ -581,14 +665,14 @@ unknown - + sconosciuto MapModel No description available. - + Nessuna descrizione disponibile. @@ -623,35 +707,35 @@ General - Generale + Generale Bans - + Espulsi IP/Nick - + IP/Nome Expiration - + Scadenza Reason - + Motivo Refresh - + Aggiorna Add - + Aggiungi Remove - + Rimuovi @@ -708,39 +792,39 @@ Select an action to choose a custom key bind for this team - + Seleziona un'azione per scegliere il tasto personalizzato per questa squadra Use my default - + Usa il mio predefinito Reset all binds - + Ripristina tutte le associazioni Custom Controls - + Controlli personalizzati Hat - Cappello + Cappello Name - Nome + Nome This hedgehog's name - + Il nome di questo riccio Randomize this hedgehog's name - + Genera casualmetne il nome di questo riccio Random Team - Squadra Casuale + Squadra Casuale @@ -808,7 +892,7 @@ PageInGame In game... - In Game.... + In gioco... @@ -858,10 +942,22 @@ Play a game across a local area network - + Gioca una partita su una rete locale Play a game on an official server + Gioca una partita su un server ufficiale + + + Feedback + Opinioni + + + Play local network game + + + + Play official network game @@ -873,22 +969,37 @@ Edit game preferences - Modifica preferenze + Modifica preferenze PageNetGame Control - Controllo + Controllo Edit game preferences - Modifica preferenze + Modifica preferenze Start - Gioca + Gioca + + + Update + Aggiorna + + + Room controls + Controlli stanza + + + + PageNetServer + + Insert your address here + @@ -975,91 +1086,91 @@ Select an action to change what key controls it - + Seleziona un'azione per cambiare il tasto che la controlla Reset to default - + Ripristina i valori predefiniti Reset all binds - + Ripristina tutte le associazioni Game - + Gioco Graphics - + Grafica Audio - + Audio Controls - + Controlli Video Recording - + Registrazione video Network - + Rete Teams - Squadre + Squadre Schemes - + Schemi Weapons - Armi + Armi Frontend - + Presentazione Custom colors - Colori personalizzati + Colori personalizzati Game audio - + Audio gioco Frontend audio - + Audio presentazione Account - + Account Proxy settings - + Impostazioni proxy Miscellaneous - Varie + Varie Updates - + Aggiornamenti Check for updates - + Controlla aggiornamenti Video recording options - Opzioni di registrazione video + Opzioni di registrazione video @@ -1077,11 +1188,11 @@ PageRoomsList Create - Crea + Crea Join - Entra + Entra Admin features @@ -1089,7 +1200,7 @@ Room Name: - Nome stanza: + Nome stanza: Rules: @@ -1101,11 +1212,11 @@ Search: - Cerca: + Cerca: Clear - Cancella + Cancella %1 players online @@ -1114,6 +1225,30 @@ %1 giocatori online + + Search for a room: + Cerca una stanza: + + + Create room + Crea stanza + + + Join room + Entra nella stanza + + + Room state + Stato della stanza + + + Clear filters + Rimuovi filtri + + + Open server administration page + Apri pagina di amministrazione del server + PageScheme @@ -1316,8 +1451,8 @@ %1 bytes - %1 bytes - %1 bytes + %1 byte + %1 byte @@ -1335,12 +1470,14 @@ Date: %1 - + Data: %1 + Size: %1 - + Dimensione: %1 + @@ -1387,7 +1524,19 @@ Update - Aggiorna + Aggiorna + + + Restrict Unregistered Players Join + Impedisci la partecipazione di giocatori non registrati + + + Show games in lobby + Mostra le partite nell'elenco + + + Show games in-progress + Mostra partite in corso @@ -1438,31 +1587,31 @@ Visual effects - + Effetti speciali Sound - + Suono In-game sound effects - + Effetti sonori nel gioco Music - + Musica In-game music - + Musica nel gioco Frontend sound effects - + Effetti sonori in presentazione Frontend music - + Musica in presentazione @@ -1489,11 +1638,11 @@ In lobby - In lobby + In lobby In progress - In corso + In corso Disabled @@ -1635,7 +1784,7 @@ Version - Versione + Versione Initial sound volume @@ -1743,7 +1892,7 @@ This program is distributed under the GNU General Public License v2 - Questo programma è distribuito con licenza GNU General Public License v2 + Questo programma è distribuito con licenza GNU General Public License v2 There are videos that are currently being processed. @@ -1807,35 +1956,43 @@ 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! - + Questo rilascio è in fase di sviluppo e potrebbe non essere compatibile con altre versioni del gioco, e alcune funzionalità potrebbero essere malfunzionanti o incomplete! Fullscreen - Schermo intero + Schermo intero Fullscreen Resolution - + Risoluzione schermo interno Windowed Resolution - + Risoluzione finestra Your Email - + Indirizzo di posta elettronica Summary - + Sommario Send system information - + Invia informazioni di sistema Type the security code: - + Inserisci il codice di sicurezza: + + + Revision + Revisione + + + This program is distributed under the %1 + Questo programma è distribuito secondo i termini di %1 @@ -1859,6 +2016,10 @@ Hedgewars %1 Hedgewars %1 + + -r%1 (%2) + -r%1 (%2) + QMessageBox @@ -1922,37 +2083,37 @@ Main - Error - Main - Errore + Main - Errore Cannot create directory %1 - Impossibile creare la directory %1 + Impossibile creare la directory %1 Failed to open data directory: %1 Please check your installation! - Impossibile creare la directory dati: + Impossibile creare la directory dati: %1 Per favore controlla l'installazione! TCP - Error - TCP - Errore + TCP - Errore Unable to start the server: %1. - Impossibile avviare il server: %1. + Impossibile avviare il server: %1. Unable to run engine at - Impossibile avviare il motore a + Impossibile avviare il motore a Error code: %1 - Codice di errore: %1 + Codice di errore: %1 Video upload - Error @@ -2026,7 +2187,7 @@ Do you really want to remove %1 file(s)? - + Vuoi davvero cancellare il file? Vuoi davvero cancellare %1 file? @@ -2073,35 +2234,45 @@ Hedgewars - Nick not registered - + Hedgewars - Nome non registrato System Information Preview - + Anteprima informazioni di sistema Failed to generate captcha - + Impossibile generare captcha Failed to download captcha - + Impossibile scaricare captcha Please fill out all fields. Email is optional. - + Per favore riempi tutti i campi. L'indirizzo di posta elettronica è opzionale. Hedgewars - Warning - + Hedgewars - Attenzione Hedgewars - Information - + Hedgewars - Avviso Hedgewars - + Hedgewars + + + Not all players are ready + Non tutti i giocatori sono pronti + + + Are you sure you want to start this game? +Not all players are ready. + Sei sicuro che vuoi iniziare il gioco? +Non tutti i giocatori sono pronti. @@ -2206,6 +2377,41 @@ Upload this video to your Youtube account Cariva questo video nel tuo account Youtube + + Reset + + + + Set the default server port for Hedgewars + + + + Invite your friends to your server in just 1 click! + + + + 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. + + + + Start private server + + + + + RoomNamePrompt + + Enter a name for your room. + Inserisci un nome per la tua stanza. + + + Cancel + Annulla + + + Create room + Crea stanza + RoomsListModel @@ -2258,19 +2464,19 @@ SeedPrompt The map seed is the basis for all random values generated by the game. - + Il seme della mappa è la base per tutti i valori casuali generati dal gioco. Cancel - Annulla + Annulla Set seed - + Imposta seme Close - + Chiudi @@ -2301,21 +2507,44 @@ + TCPBase + + Unable to start server at %1. + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + At least two teams are required to play! + + + + TeamShowWidget %1's team - + Squadra di %1 ThemePrompt - Select a theme for this map - - - Cancel - Annulla + Annulla + + + Search for a theme: + Cerca un tema: + + + Use selected theme + Usa tema selezionato @@ -2486,26 +2715,26 @@ hedgehog info - + informazioni riccio binds (categories) Movement - + Movimento Weapons - Armi + Armi Camera - + Telecamera Miscellaneous - Varie + Varie @@ -2576,7 +2805,7 @@ Hedgehog movement - + Movimento riccio @@ -2898,4 +3127,119 @@ DPad + + server + + Not room master + Non proprietario della stanza + + + Corrupted hedgehogs info + Informazioni ricci corrotte + + + too many teams + troppe squadre + + + too many hedgehogs + troppi ricci + + + There's already a team with same name in the list + C'è già una quadra collo stesso nome in lista + + + round in progress + turno in corso + + + restricted + proibito + + + REMOVE_TEAM: no such team + CANCELLA_SQUADRA: squadra non presente + + + Not team owner! + Non proprietario della squadra! + + + Less than two clans! + Meno di due clan! + + + Room with such name already exists + Esiste già una stanza con questo nome + + + Nickname already chosen + Nome già scelto + + + Illegal nickname + Nome non valido + + + Protocol already known + Protocollo già conosciuto + + + Bad number + Numero non valido + + + Nickname is already in use + Nome già in uso + + + No checker rights + + + + Authentication failed + Autenticazione fallita + + + 60 seconds cooldown after kick + 60 secondi di raffreddamento prima dell'espulsione + + + kicked + espulso + + + Ping timeout + Scadenza ping + + + bye + ciao + + + Illegal room name + Nome stanza non valido + + + No such room + Stanza non esistente + + + Joining restricted + Ingresso riservato + + + Registered users only + Solo utenti registrati + + + You are banned in this room + Sei stato espulso dalla stanza + + + Empty config entry + Configurazione vuota + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_ja.ts --- a/share/hedgewars/Data/Locale/hedgewars_ja.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_ja.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,6 +2,13 @@ + About + + Unknown Compiler + + + + AbstractPage Go back @@ -91,6 +98,22 @@ Send Feedback + + Please give us feedback! + + + + We are always happy about suggestions, ideas, or bug reports. + + + + If you found a bug, you can see if it's already known here (english): + + + + Your email address is optional, but we may want to contact you. + + FreqSpinBox @@ -116,34 +139,63 @@ しくみを編集 - Game Options - - - Game scheme will auto-select a weapon + + Map + 地図 + + + Game options + + HWApplication - + %1 minutes - - - + + + + + %1 hour - - - + + + + + %1 hours - - - + + + + + %1 day - - - + + + + + %1 days + + + + + + Scheme '%1' not supported + + + + Cannot create directory %1 + フォルダー%1作成拒否 + + + Failed to open data directory: +%1 + +Please check your installation! @@ -386,10 +438,6 @@ - Largetunnels - - - Small islands @@ -433,6 +481,10 @@ All files + + Large tunnels + + HWNetServersModel @@ -506,6 +558,21 @@ Login + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + Nickname: + + + + Password: + + HWUploadVideoDialog @@ -528,14 +595,6 @@ HatPrompt - Select a hat - - - - Filter: - - - Cancel キャンセル @@ -543,6 +602,10 @@ Use selected hat + + Search for a hat: + + KB @@ -856,6 +919,18 @@ Play a game on an official server + + Feedback + + + + Play local network game + + + + Play official network game + + PageMultiplayer @@ -872,7 +947,7 @@ PageNetGame Control - コントロール + コントロール Edit game preferences @@ -882,6 +957,21 @@ Start スタート + + Update + 更新 + + + Room controls + + + + + PageNetServer + + Insert your address here + + PageOptions @@ -1069,11 +1159,11 @@ PageRoomsList Create - 作成 + 作成 Join - 接続 + 接続 Admin features @@ -1081,7 +1171,7 @@ Room Name: - ルーム名: + ルーム名: Rules: @@ -1091,20 +1181,36 @@ Weapons: - - Search: - - - - Clear - - %1 players online + + Search for a room: + + + + Create room + + + + Join room + + + + Room state + + + + Clear filters + + + + Open server administration page + + PageScheme @@ -1377,7 +1483,19 @@ Update - 更新 + 更新 + + + Restrict Unregistered Players Join + + + + Show games in lobby + + + + Show games in-progress + @@ -1478,14 +1596,6 @@ - In lobby - - - - In progress - - - Disabled @@ -1597,7 +1707,7 @@ Version - バーション + バーション Weapons @@ -1732,10 +1842,6 @@ - This program is distributed under the GNU General Public License v2 - - - There are videos that are currently being processed. Exiting now will abort them. Do you really want to quit? @@ -1825,6 +1931,14 @@ Type the security code: + + Revision + + + + This program is distributed under the %1 + + QLineEdit @@ -1847,6 +1961,10 @@ Hedgewars %1 Hedgewars %1 + + -r%1 (%2) + + QMessageBox @@ -1909,35 +2027,12 @@ - Main - Error - - - Cannot create directory %1 - フォルダー%1作成拒否 - - - Failed to open data directory: -%1 - -Please check your installation! - - - - TCP - Error - + フォルダー%1作成拒否 Unable to start the server: %1. - サーバー%1の起動は出来なかった - - - Unable to run engine at - - - - Error code: %1 - + サーバー%1の起動は出来なかった Video upload - Error @@ -2083,7 +2178,12 @@ - Hedgewars + Not all players are ready + + + + Are you sure you want to start this game? +Not all players are ready. @@ -2189,6 +2289,41 @@ Upload this video to your Youtube account + + Reset + + + + Set the default server port for Hedgewars + + + + Invite your friends to your server in just 1 click! + + + + 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. + + + + Start private server + + + + + RoomNamePrompt + + Enter a name for your room. + + + + Cancel + キャンセル + + + Create room + + RoomsListModel @@ -2284,6 +2419,25 @@ + TCPBase + + Unable to start server at %1. + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + At least two teams are required to play! + + + + TeamShowWidget %1's team @@ -2293,13 +2447,17 @@ ThemePrompt - Select a theme for this map - - - Cancel キャンセル + + Search for a theme: + + + + Use selected theme + + binds @@ -2881,4 +3039,119 @@ + + server + + Not room master + + + + Corrupted hedgehogs info + + + + too many teams + + + + too many hedgehogs + + + + There's already a team with same name in the list + + + + round in progress + + + + restricted + + + + REMOVE_TEAM: no such team + + + + Not team owner! + + + + Less than two clans! + + + + Room with such name already exists + + + + Nickname already chosen + + + + Illegal nickname + + + + Protocol already known + + + + Bad number + + + + Nickname is already in use + + + + No checker rights + + + + Authentication failed + + + + 60 seconds cooldown after kick + + + + kicked + + + + Ping timeout + + + + bye + + + + Illegal room name + + + + No such room + + + + Joining restricted + + + + Registered users only + + + + You are banned in this room + + + + Empty config entry + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_ko.ts --- a/share/hedgewars/Data/Locale/hedgewars_ko.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_ko.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,6 +2,13 @@ + About + + Unknown Compiler + + + + AbstractPage Go back @@ -91,6 +98,22 @@ Send Feedback + + Please give us feedback! + + + + We are always happy about suggestions, ideas, or bug reports. + + + + If you found a bug, you can see if it's already known here (english): + + + + Your email address is optional, but we may want to contact you. + + FreqSpinBox @@ -116,34 +139,63 @@ - Game Options - - - Game scheme will auto-select a weapon + + Map + + + + Game options + + HWApplication - + %1 minutes - - - + + + + + %1 hour - - - + + + + + %1 hours - - - + + + + + %1 day - - - + + + + + %1 days + + + + + + Scheme '%1' not supported + + + + Cannot create directory %1 + + + + Failed to open data directory: +%1 + +Please check your installation! @@ -386,10 +438,6 @@ - Largetunnels - - - Small islands @@ -433,6 +481,10 @@ All files + + Large tunnels + + HWNetServersModel @@ -506,6 +558,21 @@ Login + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + Nickname: + + + + Password: + + HWUploadVideoDialog @@ -528,14 +595,6 @@ HatPrompt - Select a hat - - - - Filter: - - - Cancel @@ -543,6 +602,10 @@ Use selected hat + + Search for a hat: + + KB @@ -856,6 +919,18 @@ Play a game on an official server + + Feedback + + + + Play local network game + + + + Play official network game + + PageMultiplayer @@ -871,10 +946,6 @@ PageNetGame - Control - - - Edit game preferences @@ -882,6 +953,21 @@ Start + + Update + + + + Room controls + + + + + PageNetServer + + Insert your address here + + PageOptions @@ -1068,22 +1154,10 @@ PageRoomsList - Create - - - - Join - - - Admin features - Room Name: - - - Rules: @@ -1091,20 +1165,36 @@ Weapons: - - Search: - - - - Clear - - %1 players online + + Search for a room: + + + + Create room + + + + Join room + + + + Room state + + + + Clear filters + + + + Open server administration page + + PageScheme @@ -1376,7 +1466,15 @@ - Update + Restrict Unregistered Players Join + + + + Show games in lobby + + + + Show games in-progress @@ -1478,14 +1576,6 @@ - In lobby - - - - In progress - - - Disabled @@ -1596,10 +1686,6 @@ - Version - - - Weapons @@ -1732,10 +1818,6 @@ - This program is distributed under the GNU General Public License v2 - - - There are videos that are currently being processed. Exiting now will abort them. Do you really want to quit? @@ -1825,6 +1907,14 @@ Type the security code: + + Revision + + + + This program is distributed under the %1 + + QLineEdit @@ -1847,6 +1937,10 @@ Hedgewars %1 + + -r%1 (%2) + + QMessageBox @@ -1909,37 +2003,6 @@ - Main - Error - - - - Cannot create directory %1 - - - - Failed to open data directory: -%1 - -Please check your installation! - - - - TCP - Error - - - - Unable to start the server: %1. - - - - Unable to run engine at - - - - Error code: %1 - - - Video upload - Error @@ -2083,7 +2146,12 @@ - Hedgewars + Not all players are ready + + + + Are you sure you want to start this game? +Not all players are ready. @@ -2189,6 +2257,41 @@ Upload this video to your Youtube account + + Reset + + + + Set the default server port for Hedgewars + + + + Invite your friends to your server in just 1 click! + + + + 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. + + + + Start private server + + + + + RoomNamePrompt + + Enter a name for your room. + + + + Cancel + + + + Create room + + RoomsListModel @@ -2284,6 +2387,25 @@ + TCPBase + + Unable to start server at %1. + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + At least two teams are required to play! + + + + TeamShowWidget %1's team @@ -2293,13 +2415,17 @@ ThemePrompt - Select a theme for this map - - - Cancel + + Search for a theme: + + + + Use selected theme + + binds @@ -2881,4 +3007,119 @@ + + server + + Not room master + + + + Corrupted hedgehogs info + + + + too many teams + + + + too many hedgehogs + + + + There's already a team with same name in the list + + + + round in progress + + + + restricted + + + + REMOVE_TEAM: no such team + + + + Not team owner! + + + + Less than two clans! + + + + Room with such name already exists + + + + Nickname already chosen + + + + Illegal nickname + + + + Protocol already known + + + + Bad number + + + + Nickname is already in use + + + + No checker rights + + + + Authentication failed + + + + 60 seconds cooldown after kick + + + + kicked + + + + Ping timeout + + + + bye + + + + Illegal room name + + + + No such room + + + + Joining restricted + + + + Registered users only + + + + You are banned in this room + + + + Empty config entry + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_lt.ts --- a/share/hedgewars/Data/Locale/hedgewars_lt.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_lt.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,6 +2,14 @@ + About + + + Unknown Compiler + + + + AbstractPage @@ -97,17 +105,37 @@ FeedbackDialog - + + Please give us feedback! + + + + + We are always happy about suggestions, ideas, or bug reports. + + + + + If you found a bug, you can see if it's already known here (english): + + + + + Your email address is optional, but we may want to contact you. + + + + View - + Cancel - + Send Feedback @@ -132,56 +160,99 @@ GameCFGWidget - - Game Options - - - - + + Map + + + + + Game options + + + + Edit schemes - + Edit weapons - + Game scheme will auto-select a weapon HWApplication - + %1 minutes - - - + + + + + + + %1 hour - - - + + + + + + + %1 hours - - - + + + + + + + %1 day - - - + + + + + + + %1 days + + + + + + + + + Scheme '%1' not supported + + + + + Cannot create directory %1 + + + + + Failed to open data directory: +%1 + +Please check your installation! @@ -196,52 +267,52 @@ HWChatWidget - + %1 has been removed from your ignore list - + %1 has been added to your ignore list - + %1 has been removed from your friends list - + %1 has been added to your friends list - + Stylesheet imported from %1 - - Enter %1 if you want to use the current StyleSheet in future, enter %2 to reset! - - - - - Couldn't read %1 - - - + Enter %1 if you want to use the current StyleSheet in future, enter %2 to reset! + + + + + Couldn't read %1 + + + + StyleSheet discarded - + StyleSheet saved to %1 - + Failed to save StyleSheet to %1 @@ -249,44 +320,44 @@ HWForm - + DefaultTeam - + Game aborted - + Nickname - - + + No nickname supplied. - + Someone already uses your nickname %1 on the server. Please pick another nickname: - + %1's Team - + Hedgewars - Nick registered - + This nick is registered, and you haven't specified a password. If this nick isn't yours, please register your own nick at www.hedgewars.org @@ -295,76 +366,76 @@ - + Your nickname is not registered. To prevent someone else from using it, please register it at www.hedgewars.org - + Your password wasn't saved either. - - + + Hedgewars - Empty nickname - + Hedgewars - Wrong password - + You entered a wrong password. - + Try Again - + Hedgewars - Connection error - + You reconnected too fast. Please wait a few seconds and try again. - - + + Cannot save record to file %1 - + Hedgewars Demo File File Types - + Hedgewars Save File File Types - + Demo name - + Demo name: @@ -372,13 +443,13 @@ HWGame - + en.txt lt.txt - + Cannot open demofile %1 @@ -426,113 +497,113 @@ - + Load map drawing - + Edit map drawing - - All - - - - - Small - - - - Medium + All - Large + Small - Cavern + Medium + Large + + + + + Cavern + + + + Wacky - - Largetunnels - - - - - Small islands - - - - Medium islands + Large tunnels + Small islands + + + + + Medium islands + + + + Large islands - + Map size: - + Maze style: - + Mission: - + Map: - - + + Theme: - + Load drawn map - + Drawn Maps - + All files - + Small tunnels - + Medium tunnels @@ -563,65 +634,65 @@ HWNewNet - + User quit - + Remote host has closed connection - + The host was not found. Please check the host name and port settings. - + Connection refused - + The server is too old. Disconnecting now. - + Room destroyed - + You got kicked - - + + %1 *** %2 has joined the room - + %1 *** %2 has joined - - + + %1 *** %2 has left - - + + %1 *** %2 has left (%3) - + Quit reason: @@ -633,6 +704,24 @@ Login + + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + + Nickname: + + + + + Password: + + HWUploadVideoDialog @@ -658,22 +747,17 @@ HatPrompt - - Select a hat - - - - - Filter: - - - - + + Search for a hat: + + + + Cancel - + Use selected hat @@ -726,7 +810,7 @@ MapModel - + No description available. @@ -1026,47 +1110,62 @@ - + + Play local network game + + + + Play a game across a local area network - + + Play official network game + + + + Play a game on an official server - + Read about who is behind the Hedgewars Project - + + Feedback + + + + Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars - + Downloadable Content - + Access the user created content downloadable from our website - + Exit game - + Manage videos recorded from game - + Edit game preferences @@ -1087,22 +1186,35 @@ PageNetGame - + + Update + + + + + Room controls + + + + Edit game preferences - - Control - - - - + Start + PageNetServer + + + Insert your address here + + + + PageOptions @@ -1332,47 +1444,52 @@ PageRoomsList - - Room Name: - - - - + + Search for a room: + + + + + Create room + + + + + Join room + + + + + Room state + + + + Rules: - + Weapons: - - Search: - - - - - Create - - - - - Join - - - - - Clear - - - - + + Clear filters + + + + Admin features + + + Open server administration page + + - + %1 players online @@ -1665,62 +1782,72 @@ QAction - + Info - + Kick - + Ban - + Follow - - + + Ignore - - + + Add friend - + Unignore - + Remove friend - - Update - - - - + Restrict Joins - + Restrict Team Additions + + + Restrict Unregistered Players Join + + + + + Show games in lobby + + + + + Show games in-progress + + QCheckBox @@ -1792,7 +1919,7 @@ - + Save password @@ -1916,22 +2043,11 @@ - - - + + Any - - - In lobby - - - - - In progress - - QGroupBox @@ -1966,7 +2082,7 @@ - + Playing teams @@ -1985,36 +2101,36 @@ QLabel - Version + Revision - This program is distributed under the GNU General Public License v2 - - - - + This program is distributed under the %1 + + + + Style - + Scheme - + Weapons - + Host: - + Port: @@ -2044,22 +2160,22 @@ - + Tip: - + 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! - + Server name: - + Server port: @@ -2231,27 +2347,27 @@ - + Your Email - + Summary - + Send system information - + Description - + Type the security code: @@ -2284,7 +2400,7 @@ QLineEdit - + unnamed @@ -2307,6 +2423,11 @@ Hedgewars %1 + + + -r%1 (%2) + + QMessageBox @@ -2321,80 +2442,92 @@ - + Cannot delete default scheme '%1'! - + Please select a record from the list - + Hedgewars - Nick not registered - + Unable to start server - + Connection to server is lost - + + Not all players are ready + + + + + Are you sure you want to start this game? +Not all players are ready. + + + + + Hedgewars - Error - + System Information Preview - - + + Failed to generate captcha - + Failed to download captcha - + Please fill out all fields. Email is optional. - - + + Hedgewars - Success - + All file associations have been set - + File association failed. - + Error - + Cannot use the ammo '%1'! @@ -2422,59 +2555,18 @@ - - - Main - Error - - - - - Cannot create directory %1 - - - - - Failed to open data directory: -%1 - -Please check your installation! - - - - - - TCP - Error - - - - - Unable to start the server: %1. - - - - - Unable to run engine at - - - - - Error code: %1 - - - - - + + Netgame - Error - + Please select a server from the list - - + Please enter room name @@ -2503,23 +2595,22 @@ - - + Room Name - Error - + Please select room from the list - + Room Name - Are you sure? - + The game you are trying to join has started. Do you still want to join the room? @@ -2568,7 +2659,7 @@ - + File error @@ -2579,7 +2670,7 @@ - + Cannot open '%1' for reading @@ -2610,36 +2701,30 @@ - + Hedgewars - Warning - + Hedgewars - Information - - - Hedgewars - - QPushButton - - + default - + OK - + Cancel @@ -2671,11 +2756,36 @@ - + + Reset + + + + + Set the default server port for Hedgewars + + + + + Invite your friends to your server in just 1 click! + + + + + 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. + + + + Start + + Start private server + + + Associate file extensions @@ -2762,6 +2872,24 @@ + RoomNamePrompt + + + Enter a name for your room. + + + + + Cancel + + + + + Create room + + + + RoomsListModel @@ -2837,7 +2965,7 @@ - + Close @@ -2878,6 +3006,28 @@ + TCPBase + + + Unable to start server at %1. + + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + + At least two teams are required to play! + + + + TeamShowWidget @@ -2888,15 +3038,20 @@ ThemePrompt - - Select a theme for this map - - - - + + Search for a theme: + + + + Cancel + + + Use selected theme + + binds @@ -3626,4 +3781,147 @@ + + server + + + Not room master + + + + + Corrupted hedgehogs info + + + + + too many teams + + + + + too many hedgehogs + + + + + There's already a team with same name in the list + + + + + round in progress + + + + + restricted + + + + + REMOVE_TEAM: no such team + + + + + Not team owner! + + + + + Less than two clans! + + + + + Room with such name already exists + + + + + Nickname already chosen + + + + + Illegal nickname + + + + + Protocol already known + + + + + Bad number + + + + + Nickname is already in use + + + + + No checker rights + + + + + Authentication failed + + + + + 60 seconds cooldown after kick + + + + + kicked + + + + + Ping timeout + + + + + bye + + + + + Illegal room name + + + + + No such room + + + + + Joining restricted + + + + + Registered users only + + + + + You are banned in this room + + + + + Empty config entry + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_ms.ts --- a/share/hedgewars/Data/Locale/hedgewars_ms.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_ms.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,6 +2,14 @@ + About + + + Unknown Compiler + + + + AbstractPage @@ -97,17 +105,37 @@ FeedbackDialog - + + Please give us feedback! + + + + + We are always happy about suggestions, ideas, or bug reports. + + + + + If you found a bug, you can see if it's already known here (english): + + + + + Your email address is optional, but we may want to contact you. + + + + View - + Cancel - + Send Feedback @@ -130,56 +158,89 @@ GameCFGWidget - - Game Options - - - - + + Map + + + + + Game options + + + + Edit schemes - + Edit weapons - + Game scheme will auto-select a weapon HWApplication - + %1 minutes - - - + + + + + %1 hour - - - + + + + + %1 hours - - - + + + + + %1 day - - - + + + + + %1 days + + + + + + + Scheme '%1' not supported + + + + + Cannot create directory %1 + + + + + Failed to open data directory: +%1 + +Please check your installation! @@ -194,52 +255,52 @@ HWChatWidget - + %1 has been removed from your ignore list - + %1 has been added to your ignore list - + %1 has been removed from your friends list - + %1 has been added to your friends list - + Stylesheet imported from %1 - - Enter %1 if you want to use the current StyleSheet in future, enter %2 to reset! - - - - - Couldn't read %1 - - - + Enter %1 if you want to use the current StyleSheet in future, enter %2 to reset! + + + + + Couldn't read %1 + + + + StyleSheet discarded - + StyleSheet saved to %1 - + Failed to save StyleSheet to %1 @@ -247,27 +308,27 @@ HWForm - + DefaultTeam - + %1's Team - + Game aborted - + Hedgewars - Nick registered - + This nick is registered, and you haven't specified a password. If this nick isn't yours, please register your own nick at www.hedgewars.org @@ -276,93 +337,93 @@ - + Your nickname is not registered. To prevent someone else from using it, please register it at www.hedgewars.org - + Your password wasn't saved either. - + Nickname - + Someone already uses your nickname %1 on the server. Please pick another nickname: - - + + No nickname supplied. - - + + Hedgewars - Empty nickname - + Hedgewars - Wrong password - + You entered a wrong password. - + Try Again - + Hedgewars - Connection error - + You reconnected too fast. Please wait a few seconds and try again. - - + + Cannot save record to file %1 - + Hedgewars Demo File File Types - + Hedgewars Save File File Types - + Demo name - + Demo name: @@ -370,13 +431,13 @@ HWGame - + en.txt ms.txt - + Cannot open demofile %1 @@ -424,113 +485,113 @@ - + Load map drawing - + Edit map drawing - - All - - - - - Small - - - - Medium + All - Large + Small - Cavern + Medium + Large + + + + + Cavern + + + + Wacky - - Largetunnels - - - - - Small islands - - - - Medium islands + Large tunnels + Small islands + + + + + Medium islands + + + + Large islands - + Map size: - + Maze style: - + Mission: - + Map: - - + + Theme: - + Load drawn map - + Drawn Maps - + All files - + Small tunnels - + Medium tunnels @@ -561,65 +622,65 @@ HWNewNet - + Quit reason: - + User quit - + Remote host has closed connection - + The host was not found. Please check the host name and port settings. - + Connection refused - + The server is too old. Disconnecting now. - + You got kicked - + %1 *** %2 has joined - - + + %1 *** %2 has left - - + + %1 *** %2 has left (%3) - - + + %1 *** %2 has joined the room - + Room destroyed @@ -631,6 +692,24 @@ Login + + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + + Nickname: + + + + + Password: + + HWUploadVideoDialog @@ -656,22 +735,17 @@ HatPrompt - - Select a hat - - - - - Filter: - - - - + + Search for a hat: + + + + Cancel - + Use selected hat @@ -724,7 +798,7 @@ MapModel - + No description available. @@ -1012,47 +1086,62 @@ - + + Play local network game + + + + Play a game across a local area network - + + Play official network game + + + + Play a game on an official server - + Read about who is behind the Hedgewars Project - + + Feedback + + + + Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars - + Downloadable Content - + Access the user created content downloadable from our website - + Exit game - + Manage videos recorded from game - + Edit game preferences @@ -1073,22 +1162,35 @@ PageNetGame - + + Update + + + + + Room controls + + + + Edit game preferences - - Control - - - - + Start + PageNetServer + + + Insert your address here + + + + PageOptions @@ -1318,47 +1420,52 @@ PageRoomsList - - Room Name: - - - - + + Search for a room: + + + + + Create room + + + + + Join room + + + + + Room state + + + + Rules: - + Weapons: - - Search: - - - - - Create - - - - - Join - - - - - Clear - - - - + + Clear filters + + + + Admin features + + + Open server administration page + + - + %1 players online @@ -1647,67 +1754,77 @@ QAction - - Update - - - - + Restrict Joins - + Restrict Team Additions - + + Restrict Unregistered Players Join + + + + Info - + Kick - + Ban - + Follow - - + + Ignore - - + + Add friend - + Unignore - + Remove friend + + + Show games in lobby + + + + + Show games in-progress + + QCheckBox - + Save password @@ -1898,22 +2015,11 @@ - - - + + Any - - - In lobby - - - - - In progress - - QGroupBox @@ -1958,7 +2064,7 @@ - + Playing teams @@ -1973,12 +2079,12 @@ - + Host: - + Port: @@ -2038,52 +2144,52 @@ - + Your Email - + Summary - + Send system information - + Description - + Type the security code: - - Tip: - - - + Tip: + + + + 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! - + Server name: - + Server port: - + Weapons @@ -2244,21 +2350,21 @@ - Version + Revision - This program is distributed under the GNU General Public License v2 - - - - + This program is distributed under the %1 + + + + Style - + Scheme @@ -2266,7 +2372,7 @@ QLineEdit - + unnamed @@ -2289,6 +2395,11 @@ Hedgewars %1 + + + -r%1 (%2) + + QMessageBox @@ -2303,114 +2414,86 @@ - + Cannot delete default scheme '%1'! - + Please select a record from the list - + Hedgewars - Nick not registered - + Unable to start server - + Connection to server is lost - + + Not all players are ready + + + + + Are you sure you want to start this game? +Not all players are ready. + + + + + Hedgewars - Error - + System Information Preview - - + + Failed to generate captcha - + Failed to download captcha - + Please fill out all fields. Email is optional. - - + + Hedgewars - Success - + All file associations have been set - + File association failed. - - - Main - Error - - - - - Cannot create directory %1 - - - - - Failed to open data directory: -%1 - -Please check your installation! - - - - - - TCP - Error - - - - - Unable to start the server: %1. - - - - - Unable to run engine at - - - - - Error code: %1 - - - Error while authenticating at google.com: @@ -2434,19 +2517,18 @@ - - + + Netgame - Error - + Please select a server from the list - - + Please enter room name @@ -2475,23 +2557,22 @@ - - + Room Name - Error - + Please select room from the list - + Room Name - Are you sure? - + The game you are trying to join has started. Do you still want to join the room? @@ -2538,7 +2619,7 @@ - + File error @@ -2549,17 +2630,17 @@ - + Cannot open '%1' for reading - + Error - + Cannot use the ammo '%1'! @@ -2590,20 +2671,15 @@ - + Hedgewars - Warning - + Hedgewars - Information - - - Hedgewars - - QPushButton @@ -2613,18 +2689,17 @@ - - + default - + OK - + Cancel @@ -2656,11 +2731,36 @@ - + + Reset + + + + + Set the default server port for Hedgewars + + + + + Invite your friends to your server in just 1 click! + + + + + 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. + + + + Start + + Start private server + + + Associate file extensions @@ -2742,6 +2842,24 @@ + RoomNamePrompt + + + Enter a name for your room. + + + + + Cancel + + + + + Create room + + + + RoomsListModel @@ -2817,7 +2935,7 @@ - + Close @@ -2858,6 +2976,28 @@ + TCPBase + + + Unable to start server at %1. + + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + + At least two teams are required to play! + + + + TeamShowWidget @@ -2868,15 +3008,20 @@ ThemePrompt - - Select a theme for this map - - - - + + Search for a theme: + + + + Cancel + + + Use selected theme + + binds @@ -3606,4 +3751,147 @@ + + server + + + Not room master + + + + + Corrupted hedgehogs info + + + + + too many teams + + + + + too many hedgehogs + + + + + There's already a team with same name in the list + + + + + round in progress + + + + + restricted + + + + + REMOVE_TEAM: no such team + + + + + Not team owner! + + + + + Less than two clans! + + + + + Room with such name already exists + + + + + Nickname already chosen + + + + + Illegal nickname + + + + + Protocol already known + + + + + Bad number + + + + + Nickname is already in use + + + + + No checker rights + + + + + Authentication failed + + + + + 60 seconds cooldown after kick + + + + + kicked + + + + + Ping timeout + + + + + bye + + + + + Illegal room name + + + + + No such room + + + + + Joining restricted + + + + + Registered users only + + + + + You are banned in this room + + + + + Empty config entry + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_nl.ts --- a/share/hedgewars/Data/Locale/hedgewars_nl.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_nl.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,6 +2,13 @@ + About + + Unknown Compiler + + + + AbstractPage Go back @@ -91,6 +98,22 @@ Send Feedback + + Please give us feedback! + + + + We are always happy about suggestions, ideas, or bug reports. + + + + If you found a bug, you can see if it's already known here (english): + + + + Your email address is optional, but we may want to contact you. + + FreqSpinBox @@ -117,34 +140,68 @@ - Game Options - - - Game scheme will auto-select a weapon + + Map + + + + Game options + + HWApplication - + %1 minutes - - - + + + + + + %1 hour - - - + + + + + + %1 hours - - - + + + + + + %1 day - - - + + + + + + %1 days + + + + + + + Scheme '%1' not supported + + + + Cannot create directory %1 + + + + Failed to open data directory: +%1 + +Please check your installation! @@ -387,10 +444,6 @@ - Largetunnels - - - Small islands @@ -434,6 +487,10 @@ All files + + Large tunnels + + HWNetServersModel @@ -507,6 +564,21 @@ Login + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + Nickname: + + + + Password: + + HWUploadVideoDialog @@ -529,14 +601,6 @@ HatPrompt - Select a hat - - - - Filter: - - - Cancel @@ -544,6 +608,10 @@ Use selected hat + + Search for a hat: + + KB @@ -863,6 +931,18 @@ Play a game on an official server + + Feedback + + + + Play local network game + + + + Play official network game + + PageMultiplayer @@ -878,10 +958,6 @@ PageNetGame - Control - - - Edit game preferences @@ -889,6 +965,21 @@ Start + + Update + + + + Room controls + + + + + PageNetServer + + Insert your address here + + PageOptions @@ -1075,22 +1166,10 @@ PageRoomsList - Create - - - - Join - - - Admin features - Room Name: - - - Rules: @@ -1098,14 +1177,6 @@ Weapons: - - Search: - - - - Clear - - %1 players online @@ -1113,6 +1184,30 @@ + + Search for a room: + + + + Create room + + + + Join room + + + + Room state + + + + Clear filters + + + + Open server administration page + + PageScheme @@ -1385,7 +1480,15 @@ - Update + Restrict Unregistered Players Join + + + + Show games in lobby + + + + Show games in-progress @@ -1487,14 +1590,6 @@ - In lobby - - - - In progress - - - Disabled @@ -1605,10 +1700,6 @@ - Version - - - Weapons @@ -1741,10 +1832,6 @@ - This program is distributed under the GNU General Public License v2 - - - There are videos that are currently being processed. Exiting now will abort them. Do you really want to quit? @@ -1834,6 +1921,14 @@ Type the security code: + + Revision + + + + This program is distributed under the %1 + + QLineEdit @@ -1856,6 +1951,10 @@ Hedgewars %1 + + -r%1 (%2) + + QMessageBox @@ -1918,37 +2017,6 @@ - Main - Error - - - - Cannot create directory %1 - - - - Failed to open data directory: -%1 - -Please check your installation! - - - - TCP - Error - - - - Unable to start the server: %1. - - - - Unable to run engine at - - - - Error code: %1 - - - Video upload - Error @@ -2093,7 +2161,12 @@ - Hedgewars + Not all players are ready + + + + Are you sure you want to start this game? +Not all players are ready. @@ -2199,6 +2272,41 @@ Upload this video to your Youtube account + + Reset + + + + Set the default server port for Hedgewars + + + + Invite your friends to your server in just 1 click! + + + + 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. + + + + Start private server + + + + + RoomNamePrompt + + Enter a name for your room. + + + + Cancel + + + + Create room + + RoomsListModel @@ -2294,6 +2402,25 @@ + TCPBase + + Unable to start server at %1. + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + At least two teams are required to play! + + + + TeamShowWidget %1's team @@ -2303,13 +2430,17 @@ ThemePrompt - Select a theme for this map - - - Cancel + + Search for a theme: + + + + Use selected theme + + binds @@ -2891,4 +3022,119 @@ + + server + + Not room master + + + + Corrupted hedgehogs info + + + + too many teams + + + + too many hedgehogs + + + + There's already a team with same name in the list + + + + round in progress + + + + restricted + + + + REMOVE_TEAM: no such team + + + + Not team owner! + + + + Less than two clans! + + + + Room with such name already exists + + + + Nickname already chosen + + + + Illegal nickname + + + + Protocol already known + + + + Bad number + + + + Nickname is already in use + + + + No checker rights + + + + Authentication failed + + + + 60 seconds cooldown after kick + + + + kicked + + + + Ping timeout + + + + bye + + + + Illegal room name + + + + No such room + + + + Joining restricted + + + + Registered users only + + + + You are banned in this room + + + + Empty config entry + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_pl.ts --- a/share/hedgewars/Data/Locale/hedgewars_pl.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_pl.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,6 +2,13 @@ + About + + Unknown Compiler + + + + AbstractPage Go back @@ -91,6 +98,22 @@ Send Feedback + + Please give us feedback! + + + + We are always happy about suggestions, ideas, or bug reports. + + + + If you found a bug, you can see if it's already known here (english): + + + + Your email address is optional, but we may want to contact you. + + FreqSpinBox @@ -119,34 +142,80 @@ Game Options - Opcje + Opcje Game scheme will auto-select a weapon + + Map + Mapa + + + Game options + + HWApplication - + %1 minutes - - - + + + + + + + %1 hour - - - + + + + + + + %1 hours - - - + + + + + + + %1 day + + + + + + + + %1 days + + + + + + + + Scheme '%1' not supported - %1 days - + Cannot create directory %1 + Nie można utworzyć katalogu %1 + + + Failed to open data directory: +%1 + +Please check your installation! + Nie można otworzyć katalogu z danymi: +%1 + +Sprawdź poprawność instalacji! @@ -389,10 +458,6 @@ - Largetunnels - - - Small islands @@ -436,6 +501,10 @@ All files Wszystkie pliki + + Large tunnels + + HWNetServersModel @@ -509,6 +578,21 @@ Login + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + Nickname: + + + + Password: + + HWUploadVideoDialog @@ -531,14 +615,6 @@ HatPrompt - Select a hat - - - - Filter: - - - Cancel Anuluj @@ -546,6 +622,10 @@ Use selected hat + + Search for a hat: + + KB @@ -871,6 +951,18 @@ Play a game on an official server + + Feedback + + + + Play local network game + + + + Play official network game + + PageMultiplayer @@ -887,7 +979,7 @@ PageNetGame Control - Kontrola + Kontrola Edit game preferences @@ -897,6 +989,21 @@ Start Start + + Update + + + + Room controls + + + + + PageNetServer + + Insert your address here + + PageOptions @@ -1084,11 +1191,11 @@ PageRoomsList Create - Stwórz + Stwórz Join - Dołącz + Dołącz Admin features @@ -1096,7 +1203,7 @@ Room Name: - Nazwa pokoju: + Nazwa pokoju: Rules: @@ -1108,11 +1215,11 @@ Search: - Szukaj: + Szukaj: Clear - Wyczyść + Wyczyść %1 players online @@ -1122,6 +1229,30 @@ %1 graczy online + + Search for a room: + + + + Create room + + + + Join room + + + + Room state + + + + Clear filters + + + + Open server administration page + + PageScheme @@ -1396,7 +1527,19 @@ Update - Zmień + Zmień + + + Restrict Unregistered Players Join + + + + Show games in lobby + + + + Show games in-progress + @@ -1498,11 +1641,11 @@ In lobby - W lobby + W lobby In progress - W toku + W toku Disabled @@ -1636,7 +1779,7 @@ Version - Wersja + Wersja Initial sound volume @@ -1752,7 +1895,7 @@ This program is distributed under the GNU General Public License v2 - Ten program jest rozprowadzany na zasadach GNU GPL v2 + Ten program jest rozprowadzany na zasadach GNU GPL v2 There are videos that are currently being processed. @@ -1846,6 +1989,14 @@ Type the security code: + + Revision + + + + This program is distributed under the %1 + + QLineEdit @@ -1868,6 +2019,10 @@ Hedgewars %1 Hedgewars %1 + + -r%1 (%2) + + QMessageBox @@ -1931,37 +2086,37 @@ Main - Error - Błąd + Błąd Cannot create directory %1 - Nie można utworzyć katalogu %1 + Nie można utworzyć katalogu %1 Failed to open data directory: %1 Please check your installation! - Nie można otworzyć katalogu z danymi: + Nie można otworzyć katalogu z danymi: %1 Sprawdź poprawność instalacji! TCP - Error - TCP - Błąd + TCP - Błąd Unable to start the server: %1. - Nie można uruchomić serwera: %1. + Nie można uruchomić serwera: %1. Unable to run engine at - Nie można uruchomić silnika na + Nie można uruchomić silnika na Error code: %1 - Kod błędu: %1 + Kod błędu: %1 Video upload - Error @@ -2110,7 +2265,12 @@ - Hedgewars + Not all players are ready + + + + Are you sure you want to start this game? +Not all players are ready. @@ -2216,6 +2376,41 @@ Upload this video to your Youtube account + + Reset + + + + Set the default server port for Hedgewars + + + + Invite your friends to your server in just 1 click! + + + + 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. + + + + Start private server + + + + + RoomNamePrompt + + Enter a name for your room. + + + + Cancel + Anuluj + + + Create room + + RoomsListModel @@ -2311,6 +2506,25 @@ + TCPBase + + Unable to start server at %1. + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + At least two teams are required to play! + + + + TeamShowWidget %1's team @@ -2320,13 +2534,17 @@ ThemePrompt - Select a theme for this map - - - Cancel Anuluj + + Search for a theme: + + + + Use selected theme + + binds @@ -2908,4 +3126,119 @@ DPad + + server + + Not room master + + + + Corrupted hedgehogs info + + + + too many teams + + + + too many hedgehogs + + + + There's already a team with same name in the list + + + + round in progress + + + + restricted + + + + REMOVE_TEAM: no such team + + + + Not team owner! + + + + Less than two clans! + + + + Room with such name already exists + + + + Nickname already chosen + + + + Illegal nickname + + + + Protocol already known + + + + Bad number + + + + Nickname is already in use + + + + No checker rights + + + + Authentication failed + + + + 60 seconds cooldown after kick + + + + kicked + + + + Ping timeout + + + + bye + + + + Illegal room name + + + + No such room + + + + Joining restricted + + + + Registered users only + + + + You are banned in this room + + + + Empty config entry + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_pt_BR.ts --- a/share/hedgewars/Data/Locale/hedgewars_pt_BR.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_pt_BR.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,6 +2,13 @@ + About + + Unknown Compiler + + + + AbstractPage Go back @@ -91,6 +98,22 @@ Send Feedback + + Please give us feedback! + + + + We are always happy about suggestions, ideas, or bug reports. + + + + If you found a bug, you can see if it's already known here (english): + + + + Your email address is optional, but we may want to contact you. + + FreqSpinBox @@ -117,34 +140,68 @@ Editar esquemas - Game Options - - - Game scheme will auto-select a weapon + + Map + Mapa + + + Game options + + HWApplication - + %1 minutes - - - + + + + + + %1 hour - - - + + + + + + %1 hours - - - + + + + + + %1 day - - - + + + + + + %1 days + + + + + + + Scheme '%1' not supported + + + + Cannot create directory %1 + Não foi possível criar o diretório %1 + + + Failed to open data directory: +%1 + +Please check your installation! @@ -388,10 +445,6 @@ - Largetunnels - - - Small islands @@ -435,6 +488,10 @@ All files + + Large tunnels + + HWNetServersModel @@ -508,6 +565,21 @@ Login + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + Nickname: + + + + Password: + + HWUploadVideoDialog @@ -530,14 +602,6 @@ HatPrompt - Select a hat - - - - Filter: - - - Cancel Cancelar @@ -545,6 +609,10 @@ Use selected hat + + Search for a hat: + + KB @@ -864,6 +932,18 @@ Play a game on an official server + + Feedback + + + + Play local network game + + + + Play official network game + + PageMultiplayer @@ -880,7 +960,7 @@ PageNetGame Control - Controle + Controle Edit game preferences @@ -890,6 +970,21 @@ Start + + Update + Atualizar + + + Room controls + + + + + PageNetServer + + Insert your address here + + PageOptions @@ -1077,11 +1172,11 @@ PageRoomsList Create - Criar + Criar Join - Entrar + Entrar Admin features @@ -1089,7 +1184,7 @@ Room Name: - Nome da Sala: + Nome da Sala: Rules: @@ -1101,11 +1196,11 @@ Search: - Procurar: + Procurar: Clear - Limpar + Limpar %1 players online @@ -1114,6 +1209,30 @@ + + Search for a room: + + + + Create room + + + + Join room + + + + Room state + + + + Clear filters + + + + Open server administration page + + PageScheme @@ -1387,7 +1506,19 @@ Update - Atualizar + Atualizar + + + Restrict Unregistered Players Join + + + + Show games in lobby + + + + Show games in-progress + @@ -1489,11 +1620,11 @@ In lobby - Em espera + Em espera In progress - Em progresso + Em progresso Disabled @@ -1627,7 +1758,7 @@ Version - Versão + Versão Initial sound volume @@ -1742,10 +1873,6 @@ - This program is distributed under the GNU General Public License v2 - - - There are videos that are currently being processed. Exiting now will abort them. Do you really want to quit? @@ -1835,6 +1962,14 @@ Type the security code: + + Revision + + + + This program is distributed under the %1 + + QLineEdit @@ -1857,6 +1992,10 @@ Hedgewars %1 Hedgewars %1 + + -r%1 (%2) + + QMessageBox @@ -1919,35 +2058,12 @@ - Main - Error - - - Cannot create directory %1 - Não foi possível criar o diretório %1 - - - Failed to open data directory: -%1 - -Please check your installation! - - - - TCP - Error - + Não foi possível criar o diretório %1 Unable to start the server: %1. - Não foi possível iniciar o servidor: %1. - - - Unable to run engine at - - - - Error code: %1 - + Não foi possível iniciar o servidor: %1. Video upload - Error @@ -2095,7 +2211,12 @@ - Hedgewars + Not all players are ready + + + + Are you sure you want to start this game? +Not all players are ready. @@ -2201,6 +2322,41 @@ Upload this video to your Youtube account + + Reset + + + + Set the default server port for Hedgewars + + + + Invite your friends to your server in just 1 click! + + + + 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. + + + + Start private server + + + + + RoomNamePrompt + + Enter a name for your room. + + + + Cancel + Cancelar + + + Create room + + RoomsListModel @@ -2297,6 +2453,25 @@ + TCPBase + + Unable to start server at %1. + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + At least two teams are required to play! + + + + TeamShowWidget %1's team @@ -2306,13 +2481,17 @@ ThemePrompt - Select a theme for this map - - - Cancel Cancelar + + Search for a theme: + + + + Use selected theme + + binds @@ -2899,4 +3078,119 @@ DPad + + server + + Not room master + + + + Corrupted hedgehogs info + + + + too many teams + + + + too many hedgehogs + + + + There's already a team with same name in the list + + + + round in progress + + + + restricted + + + + REMOVE_TEAM: no such team + + + + Not team owner! + + + + Less than two clans! + + + + Room with such name already exists + + + + Nickname already chosen + + + + Illegal nickname + + + + Protocol already known + + + + Bad number + + + + Nickname is already in use + + + + No checker rights + + + + Authentication failed + + + + 60 seconds cooldown after kick + + + + kicked + + + + Ping timeout + + + + bye + + + + Illegal room name + + + + No such room + + + + Joining restricted + + + + Registered users only + + + + You are banned in this room + + + + Empty config entry + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_pt_PT.ts --- a/share/hedgewars/Data/Locale/hedgewars_pt_PT.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_pt_PT.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,6 +2,13 @@ + About + + Unknown Compiler + + + + AbstractPage Go back @@ -91,6 +98,22 @@ Send Feedback + + Please give us feedback! + + + + We are always happy about suggestions, ideas, or bug reports. + + + + If you found a bug, you can see if it's already known here (english): + + + + Your email address is optional, but we may want to contact you. + + FreqSpinBox @@ -118,34 +141,75 @@ Game Options - Opções de Jogo + Opções de Jogo Game scheme will auto-select a weapon + + Map + Mapa + + + Game options + + HWApplication - + %1 minutes - - - + + + + + + %1 hour - - - + + + + + + %1 hours - - - + + + + + + %1 day + + + + + + + %1 days + + + + + + + Scheme '%1' not supported - %1 days - + Cannot create directory %1 + Não foi possível criar o diretório %1 + + + Failed to open data directory: +%1 + +Please check your installation! + Erro ao abrir o diretório: +%1 + +Por favor verifica a tua instalação! @@ -388,10 +452,6 @@ - Largetunnels - - - Small islands @@ -435,6 +495,10 @@ All files Todos os ficheiros + + Large tunnels + + HWNetServersModel @@ -508,6 +572,21 @@ Login + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + Nickname: + + + + Password: + + HWUploadVideoDialog @@ -530,14 +609,6 @@ HatPrompt - Select a hat - - - - Filter: - - - Cancel Cancelar @@ -545,6 +616,10 @@ Use selected hat + + Search for a hat: + + KB @@ -865,6 +940,18 @@ Play a game on an official server + + Feedback + + + + Play local network game + + + + Play official network game + + PageMultiplayer @@ -881,7 +968,7 @@ PageNetGame Control - Controlo + Controlo Edit game preferences @@ -891,6 +978,21 @@ Start Iniciar + + Update + Actualizar + + + Room controls + + + + + PageNetServer + + Insert your address here + + PageOptions @@ -1078,11 +1180,11 @@ PageRoomsList Create - Criar + Criar Join - Entrar + Entrar Admin features @@ -1090,7 +1192,7 @@ Room Name: - Nome da Sala: + Nome da Sala: Rules: @@ -1102,11 +1204,11 @@ Search: - Pesquisa: + Pesquisa: Clear - Limpar + Limpar %1 players online @@ -1115,6 +1217,30 @@ %1 jogadores online + + Search for a room: + + + + Create room + + + + Join room + + + + Room state + + + + Clear filters + + + + Open server administration page + + PageScheme @@ -1388,7 +1514,19 @@ Update - Actualizar + Actualizar + + + Restrict Unregistered Players Join + + + + Show games in lobby + + + + Show games in-progress + @@ -1490,11 +1628,11 @@ In lobby - No lobby + No lobby In progress - Em progresso + Em progresso Disabled @@ -1608,7 +1746,7 @@ Version - Versão + Versão Weapons @@ -1744,7 +1882,7 @@ This program is distributed under the GNU General Public License v2 - Esta aplicação é distribuída sob a GNU General Public License v2 + Esta aplicação é distribuída sob a GNU General Public License v2 There are videos that are currently being processed. @@ -1838,6 +1976,14 @@ Type the security code: + + Revision + + + + This program is distributed under the %1 + + QLineEdit @@ -1860,6 +2006,10 @@ Hedgewars %1 Hedgewars %1 + + -r%1 (%2) + + QMessageBox @@ -1925,37 +2075,37 @@ Main - Error - Main - Erro + Main - Erro Cannot create directory %1 - Não foi possível criar o diretório %1 + Não foi possível criar o diretório %1 Failed to open data directory: %1 Please check your installation! - Erro ao abrir o diretório: + Erro ao abrir o diretório: %1 Por favor verifica a tua instalação! TCP - Error - TCP - Erro + TCP - Erro Unable to start the server: %1. - Não foi possível iniciar o servidor: %1. + Não foi possível iniciar o servidor: %1. Unable to run engine at - Não foi possivel lançar o motor de jogo em + Não foi possivel lançar o motor de jogo em Error code: %1 - Código de erro: %1 + Código de erro: %1 Video upload - Error @@ -2103,7 +2253,12 @@ - Hedgewars + Not all players are ready + + + + Are you sure you want to start this game? +Not all players are ready. @@ -2209,6 +2364,41 @@ Upload this video to your Youtube account Enviar este vídeo para a tua conta do Youtube + + Reset + + + + Set the default server port for Hedgewars + + + + Invite your friends to your server in just 1 click! + + + + 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. + + + + Start private server + + + + + RoomNamePrompt + + Enter a name for your room. + + + + Cancel + Cancelar + + + Create room + + RoomsListModel @@ -2304,6 +2494,25 @@ + TCPBase + + Unable to start server at %1. + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + At least two teams are required to play! + + + + TeamShowWidget %1's team @@ -2313,13 +2522,17 @@ ThemePrompt - Select a theme for this map - - - Cancel Cancelar + + Search for a theme: + + + + Use selected theme + + binds @@ -2901,4 +3114,119 @@ DPad + + server + + Not room master + + + + Corrupted hedgehogs info + + + + too many teams + + + + too many hedgehogs + + + + There's already a team with same name in the list + + + + round in progress + + + + restricted + + + + REMOVE_TEAM: no such team + + + + Not team owner! + + + + Less than two clans! + + + + Room with such name already exists + + + + Nickname already chosen + + + + Illegal nickname + + + + Protocol already known + + + + Bad number + + + + Nickname is already in use + + + + No checker rights + + + + Authentication failed + + + + 60 seconds cooldown after kick + + + + kicked + + + + Ping timeout + + + + bye + + + + Illegal room name + + + + No such room + + + + Joining restricted + + + + Registered users only + + + + You are banned in this room + + + + Empty config entry + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_ro.ts --- a/share/hedgewars/Data/Locale/hedgewars_ro.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_ro.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,6 +2,13 @@ + About + + Unknown Compiler + + + + AbstractPage Go back @@ -91,6 +98,22 @@ Send Feedback + + Please give us feedback! + + + + We are always happy about suggestions, ideas, or bug reports. + + + + If you found a bug, you can see if it's already known here (english): + + + + Your email address is optional, but we may want to contact you. + + FreqSpinBox @@ -118,34 +141,73 @@ Edit schemes - Game Options - - - Game scheme will auto-select a weapon + + Map + Map + + + Game options + + HWApplication - + %1 minutes - - - + + + + + + + %1 hour - - - + + + + + + + %1 hours - - - + + + + + + + %1 day - - - + + + + + + + %1 days + + + + + + + + Scheme '%1' not supported + + + + Cannot create directory %1 + Cannot create directory %1 + + + Failed to open data directory: +%1 + +Please check your installation! @@ -388,10 +450,6 @@ - Largetunnels - - - Small islands @@ -435,6 +493,10 @@ All files + + Large tunnels + + HWNetServersModel @@ -508,6 +570,21 @@ Login + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + Nickname: + + + + Password: + + HWUploadVideoDialog @@ -530,14 +607,6 @@ HatPrompt - Select a hat - - - - Filter: - - - Cancel Cancel @@ -545,6 +614,10 @@ Use selected hat + + Search for a hat: + + KB @@ -870,6 +943,18 @@ Play a game on an official server + + Feedback + + + + Play local network game + + + + Play official network game + + PageMultiplayer @@ -886,7 +971,7 @@ PageNetGame Control - Control + Control Edit game preferences @@ -896,6 +981,21 @@ Start Start + + Update + Update + + + Room controls + + + + + PageNetServer + + Insert your address here + + PageOptions @@ -1083,11 +1183,11 @@ PageRoomsList Create - Create + Create Join - Join + Join Admin features @@ -1095,7 +1195,7 @@ Room Name: - Room Name: + Room Name: Rules: @@ -1105,14 +1205,6 @@ Weapons: - - Search: - - - - Clear - - %1 players online @@ -1121,6 +1213,30 @@ + + Search for a room: + + + + Create room + + + + Join room + + + + Room state + + + + Clear filters + + + + Open server administration page + + PageScheme @@ -1395,7 +1511,19 @@ Update - Update + Update + + + Restrict Unregistered Players Join + + + + Show games in lobby + + + + Show games in-progress + @@ -1496,14 +1624,6 @@ - In lobby - - - - In progress - - - Disabled @@ -1615,7 +1735,7 @@ Version - Version + Version Weapons @@ -1750,10 +1870,6 @@ - This program is distributed under the GNU General Public License v2 - - - There are videos that are currently being processed. Exiting now will abort them. Do you really want to quit? @@ -1843,6 +1959,14 @@ Type the security code: + + Revision + + + + This program is distributed under the %1 + + QLineEdit @@ -1865,6 +1989,10 @@ Hedgewars %1 Hedgewars %1 + + -r%1 (%2) + + QMessageBox @@ -1913,35 +2041,12 @@ - Main - Error - - - Cannot create directory %1 - Cannot create directory %1 - - - Failed to open data directory: -%1 - -Please check your installation! - - - - TCP - Error - + Cannot create directory %1 Unable to start the server: %1. - Unable to start the server: %1. - - - Unable to run engine at - - - - Error code: %1 - + Unable to start the server: %1. Error while authenticating at google.com: @@ -2104,7 +2209,12 @@ - Hedgewars + Not all players are ready + + + + Are you sure you want to start this game? +Not all players are ready. @@ -2210,6 +2320,41 @@ Cancel uploading + + Reset + + + + Set the default server port for Hedgewars + + + + Invite your friends to your server in just 1 click! + + + + 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. + + + + Start private server + + + + + RoomNamePrompt + + Enter a name for your room. + + + + Cancel + Cancel + + + Create room + + RoomsListModel @@ -2305,6 +2450,25 @@ + TCPBase + + Unable to start server at %1. + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + At least two teams are required to play! + + + + TeamShowWidget %1's team @@ -2314,13 +2478,17 @@ ThemePrompt - Select a theme for this map - - - Cancel Cancel + + Search for a theme: + + + + Use selected theme + + binds @@ -2902,4 +3070,119 @@ + + server + + Not room master + + + + Corrupted hedgehogs info + + + + too many teams + + + + too many hedgehogs + + + + There's already a team with same name in the list + + + + round in progress + + + + restricted + + + + REMOVE_TEAM: no such team + + + + Not team owner! + + + + Less than two clans! + + + + Room with such name already exists + + + + Nickname already chosen + + + + Illegal nickname + + + + Protocol already known + + + + Bad number + + + + Nickname is already in use + + + + No checker rights + + + + Authentication failed + + + + 60 seconds cooldown after kick + + + + kicked + + + + Ping timeout + + + + bye + + + + Illegal room name + + + + No such room + + + + Joining restricted + + + + Registered users only + + + + You are banned in this room + + + + Empty config entry + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_ru.ts --- a/share/hedgewars/Data/Locale/hedgewars_ru.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_ru.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,6 +2,13 @@ + About + + Unknown Compiler + + + + AbstractPage Go back @@ -91,6 +98,22 @@ Send Feedback + + Please give us feedback! + + + + We are always happy about suggestions, ideas, or bug reports. + + + + If you found a bug, you can see if it's already known here (english): + + + + Your email address is optional, but we may want to contact you. + + FreqSpinBox @@ -119,33 +142,76 @@ Game Options - Настройки игры + Настройки игры Game scheme will auto-select a weapon + + Map + Карта + + + Game options + + HWApplication - + %1 minutes - - - + + + + + + + %1 hour + + + + + + + + %1 hours + + + + + + + + %1 day + + + + + + + + %1 days + + + + + + + + Scheme '%1' not supported - %1 hours - - - - %1 day - - - - %1 days + Cannot create directory %1 + Не могу создать папку %1 + + + Failed to open data directory: +%1 + +Please check your installation! @@ -389,10 +455,6 @@ - Largetunnels - - - Small islands @@ -436,6 +498,10 @@ All files Все файлы + + Large tunnels + + HWNetServersModel @@ -509,6 +575,21 @@ Login + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + Nickname: + + + + Password: + + HWUploadVideoDialog @@ -531,14 +612,6 @@ HatPrompt - Select a hat - - - - Filter: - - - Cancel Отмена @@ -546,6 +619,10 @@ Use selected hat + + Search for a hat: + + KB @@ -871,6 +948,18 @@ Play a game on an official server + + Feedback + + + + Play local network game + + + + Play official network game + + PageMultiplayer @@ -887,7 +976,7 @@ PageNetGame Control - Управление + Управление Edit game preferences @@ -897,6 +986,21 @@ Start Старт + + Update + Обновить + + + Room controls + + + + + PageNetServer + + Insert your address here + + PageOptions @@ -1084,11 +1188,11 @@ PageRoomsList Create - Создать + Создать Join - Присоединиться + Присоединиться Admin features @@ -1096,7 +1200,7 @@ Room Name: - Название комнаты: + Название комнаты: Rules: @@ -1108,11 +1212,11 @@ Search: - Поиск: + Поиск: Clear - Очистить + Очистить %1 players online @@ -1122,6 +1226,30 @@ на сервере %1 игроков + + Search for a room: + + + + Create room + + + + Join room + + + + Room state + + + + Clear filters + + + + Open server administration page + + PageScheme @@ -1396,7 +1524,19 @@ Update - Обновить + Обновить + + + Restrict Unregistered Players Join + + + + Show games in lobby + + + + Show games in-progress + @@ -1498,11 +1638,11 @@ In lobby - Подготовка + Подготовка In progress - В игре + В игре Disabled @@ -1644,7 +1784,7 @@ Version - Версия + Версия Initial sound volume @@ -1752,7 +1892,7 @@ This program is distributed under the GNU General Public License v2 - Эта программа распространяется на условиях лицензии GNU General Public License, версия 2 + Эта программа распространяется на условиях лицензии GNU General Public License, версия 2 There are videos that are currently being processed. @@ -1846,6 +1986,14 @@ Type the security code: + + Revision + + + + This program is distributed under the %1 + + QLineEdit @@ -1868,6 +2016,10 @@ Hedgewars %1 Hedgewars %1 + + -r%1 (%2) + + QMessageBox @@ -1930,35 +2082,12 @@ - Main - Error - - - Cannot create directory %1 - Не могу создать папку %1 - - - Failed to open data directory: -%1 - -Please check your installation! - - - - TCP - Error - + Не могу создать папку %1 Unable to start the server: %1. - Ошибка запуска сервера: %1. - - - Unable to run engine at - - - - Error code: %1 - + Ошибка запуска сервера: %1. Video upload - Error @@ -2107,7 +2236,12 @@ - Hedgewars + Not all players are ready + + + + Are you sure you want to start this game? +Not all players are ready. @@ -2213,6 +2347,41 @@ Upload this video to your Youtube account + + Reset + + + + Set the default server port for Hedgewars + + + + Invite your friends to your server in just 1 click! + + + + 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. + + + + Start private server + + + + + RoomNamePrompt + + Enter a name for your room. + + + + Cancel + Отмена + + + Create room + + RoomsListModel @@ -2308,6 +2477,25 @@ + TCPBase + + Unable to start server at %1. + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + At least two teams are required to play! + + + + TeamShowWidget %1's team @@ -2317,13 +2505,17 @@ ThemePrompt - Select a theme for this map - - - Cancel Отмена + + Search for a theme: + + + + Use selected theme + + binds @@ -2905,4 +3097,119 @@ + + server + + Not room master + + + + Corrupted hedgehogs info + + + + too many teams + + + + too many hedgehogs + + + + There's already a team with same name in the list + + + + round in progress + + + + restricted + + + + REMOVE_TEAM: no such team + + + + Not team owner! + + + + Less than two clans! + + + + Room with such name already exists + + + + Nickname already chosen + + + + Illegal nickname + + + + Protocol already known + + + + Bad number + + + + Nickname is already in use + + + + No checker rights + + + + Authentication failed + + + + 60 seconds cooldown after kick + + + + kicked + + + + Ping timeout + + + + bye + + + + Illegal room name + + + + No such room + + + + Joining restricted + + + + Registered users only + + + + You are banned in this room + + + + Empty config entry + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_sk.ts --- a/share/hedgewars/Data/Locale/hedgewars_sk.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_sk.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,6 +2,13 @@ + About + + Unknown Compiler + + + + AbstractPage Go back @@ -91,6 +98,22 @@ Send Feedback + + Please give us feedback! + + + + We are always happy about suggestions, ideas, or bug reports. + + + + If you found a bug, you can see if it's already known here (english): + + + + Your email address is optional, but we may want to contact you. + + FreqSpinBox @@ -119,34 +142,80 @@ Game Options - Voľby hry + Voľby hry Game scheme will auto-select a weapon + + Map + Mapa + + + Game options + + HWApplication - + %1 minutes - - - + + + + + + + %1 hour - - - + + + + + + + %1 hours - - - + + + + + + + %1 day + + + + + + + + %1 days + + + + + + + + Scheme '%1' not supported - %1 days - + Cannot create directory %1 + Nepodarilo sa vytvoriť adresár %1 + + + Failed to open data directory: +%1 + +Please check your installation! + Chyba pri otváraní adresára s dátami: +%1 + +Skontrolujte, prosím, inštaláciu! @@ -388,10 +457,6 @@ - Largetunnels - - - Small islands @@ -435,6 +500,10 @@ All files Všetky súbory + + Large tunnels + + HWNetServersModel @@ -508,6 +577,21 @@ Login + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + Nickname: + + + + Password: + + HWUploadVideoDialog @@ -530,14 +614,6 @@ HatPrompt - Select a hat - - - - Filter: - - - Cancel Zrušiť @@ -545,6 +621,10 @@ Use selected hat + + Search for a hat: + + KB @@ -870,6 +950,18 @@ Play a game on an official server + + Feedback + + + + Play local network game + + + + Play official network game + + PageMultiplayer @@ -886,7 +978,7 @@ PageNetGame Control - Ovládanie + Ovládanie Edit game preferences @@ -896,6 +988,21 @@ Start + + Update + Obnoviť + + + Room controls + + + + + PageNetServer + + Insert your address here + + PageOptions @@ -1083,11 +1190,11 @@ PageRoomsList Create - Vytvoriť + Vytvoriť Join - Pripojiť sa + Pripojiť sa Admin features @@ -1095,7 +1202,7 @@ Room Name: - Názov miestnosti: + Názov miestnosti: Rules: @@ -1107,11 +1214,11 @@ Search: - Hľadať: + Hľadať: Clear - Vyčistiť + Vyčistiť %1 players online @@ -1121,6 +1228,30 @@ %1 hráčov online + + Search for a room: + + + + Create room + + + + Join room + + + + Room state + + + + Clear filters + + + + Open server administration page + + PageScheme @@ -1395,7 +1526,19 @@ Update - Obnoviť + Obnoviť + + + Restrict Unregistered Players Join + + + + Show games in lobby + + + + Show games in-progress + @@ -1497,11 +1640,11 @@ In lobby - V lobby + V lobby In progress - Prebieha + Prebieha Disabled @@ -1643,7 +1786,7 @@ Version - Verzia + Verzia Initial sound volume @@ -1751,7 +1894,7 @@ This program is distributed under the GNU General Public License v2 - Tento program je distribuovaný pod licenciou GNU General Public License v2 + Tento program je distribuovaný pod licenciou GNU General Public License v2 There are videos that are currently being processed. @@ -1843,6 +1986,14 @@ Type the security code: + + Revision + + + + This program is distributed under the %1 + + QLineEdit @@ -1865,6 +2016,10 @@ Hedgewars %1 Hedgewars %1 + + -r%1 (%2) + + QMessageBox @@ -1928,37 +2083,37 @@ Main - Error - Hlavné okno - Chyba + Hlavné okno - Chyba Cannot create directory %1 - Nepodarilo sa vytvoriť adresár %1 + Nepodarilo sa vytvoriť adresár %1 Failed to open data directory: %1 Please check your installation! - Chyba pri otváraní adresára s dátami: + Chyba pri otváraní adresára s dátami: %1 Skontrolujte, prosím, inštaláciu! TCP - Error - TCP - Chyba + TCP - Chyba Unable to start the server: %1. - Nepodarilo sa spustiť server: %1. + Nepodarilo sa spustiť server: %1. Unable to run engine at - Nepodarilo sa spustiť enginu na + Nepodarilo sa spustiť enginu na Error code: %1 - Kód chyby: %1 + Kód chyby: %1 Video upload - Error @@ -2107,7 +2262,12 @@ - Hedgewars + Not all players are ready + + + + Are you sure you want to start this game? +Not all players are ready. @@ -2213,6 +2373,41 @@ Upload this video to your Youtube account Uploadovať video na váš účet YouTube + + Reset + + + + Set the default server port for Hedgewars + + + + Invite your friends to your server in just 1 click! + + + + 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. + + + + Start private server + + + + + RoomNamePrompt + + Enter a name for your room. + + + + Cancel + Zrušiť + + + Create room + + RoomsListModel @@ -2308,6 +2503,25 @@ + TCPBase + + Unable to start server at %1. + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + At least two teams are required to play! + + + + TeamShowWidget %1's team @@ -2317,13 +2531,17 @@ ThemePrompt - Select a theme for this map - - - Cancel Zrušiť + + Search for a theme: + + + + Use selected theme + + binds @@ -2905,4 +3123,119 @@ Pravý joystick (Doľava) + + server + + Not room master + + + + Corrupted hedgehogs info + + + + too many teams + + + + too many hedgehogs + + + + There's already a team with same name in the list + + + + round in progress + + + + restricted + + + + REMOVE_TEAM: no such team + + + + Not team owner! + + + + Less than two clans! + + + + Room with such name already exists + + + + Nickname already chosen + + + + Illegal nickname + + + + Protocol already known + + + + Bad number + + + + Nickname is already in use + + + + No checker rights + + + + Authentication failed + + + + 60 seconds cooldown after kick + + + + kicked + + + + Ping timeout + + + + bye + + + + Illegal room name + + + + No such room + + + + Joining restricted + + + + Registered users only + + + + You are banned in this room + + + + Empty config entry + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_sv.ts --- a/share/hedgewars/Data/Locale/hedgewars_sv.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_sv.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,6 +2,13 @@ + About + + Unknown Compiler + + + + AbstractPage Go back @@ -91,6 +98,22 @@ Send Feedback + + Please give us feedback! + + + + We are always happy about suggestions, ideas, or bug reports. + + + + If you found a bug, you can see if it's already known here (english): + + + + Your email address is optional, but we may want to contact you. + + FreqSpinBox @@ -118,33 +141,71 @@ Game Options - Spelinställningar + Spelinställningar Game scheme will auto-select a weapon + + Map + Karta + + + Game options + + HWApplication - + %1 minutes - - - + + + + + + %1 hour - - - + + + + + + %1 hours - - - + + + + + + %1 day - - - + + + + + + %1 days + + + + + + + Scheme '%1' not supported + + + + Cannot create directory %1 + Kan inte skapa katalog %1 + + + Failed to open data directory: +%1 + +Please check your installation! @@ -387,10 +448,6 @@ - Largetunnels - - - Small islands @@ -434,6 +491,10 @@ All files Alla filer + + Large tunnels + + HWNetServersModel @@ -507,6 +568,21 @@ Login + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + Nickname: + + + + Password: + + HWUploadVideoDialog @@ -529,14 +605,6 @@ HatPrompt - Select a hat - - - - Filter: - - - Cancel Avbryt @@ -544,6 +612,10 @@ Use selected hat + + Search for a hat: + + KB @@ -863,6 +935,18 @@ Play a game on an official server + + Feedback + + + + Play local network game + + + + Play official network game + + PageMultiplayer @@ -879,7 +963,7 @@ PageNetGame Control - Kontroll + Kontroll Edit game preferences @@ -889,6 +973,21 @@ Start Starta + + Update + Uppdatera + + + Room controls + + + + + PageNetServer + + Insert your address here + + PageOptions @@ -1076,11 +1175,11 @@ PageRoomsList Create - Skapa + Skapa Join - Anslut + Anslut Admin features @@ -1088,7 +1187,7 @@ Room Name: - Rumnamn: + Rumnamn: Rules: @@ -1100,11 +1199,11 @@ Search: - Sök: + Sök: Clear - Rensa + Rensa %1 players online @@ -1113,6 +1212,30 @@ + + Search for a room: + + + + Create room + + + + Join room + + + + Room state + + + + Clear filters + + + + Open server administration page + + PageScheme @@ -1386,7 +1509,19 @@ Update - Uppdatera + Uppdatera + + + Restrict Unregistered Players Join + + + + Show games in lobby + + + + Show games in-progress + @@ -1488,11 +1623,11 @@ In lobby - I lobby + I lobby In progress - Pågår + Pågår Disabled @@ -1626,7 +1761,7 @@ Version - Version + Version Initial sound volume @@ -1741,10 +1876,6 @@ % flykttid - This program is distributed under the GNU General Public License v2 - - - There are videos that are currently being processed. Exiting now will abort them. Do you really want to quit? @@ -1834,6 +1965,14 @@ Type the security code: + + Revision + + + + This program is distributed under the %1 + + QLineEdit @@ -1856,6 +1995,10 @@ Hedgewars %1 Hedgewars %1 + + -r%1 (%2) + + QMessageBox @@ -1918,35 +2061,12 @@ - Main - Error - - - Cannot create directory %1 - Kan inte skapa katalog %1 - - - Failed to open data directory: -%1 - -Please check your installation! - - - - TCP - Error - + Kan inte skapa katalog %1 Unable to start the server: %1. - Kunde inte starta servern: %1. - - - Unable to run engine at - - - - Error code: %1 - + Kunde inte starta servern: %1. Video upload - Error @@ -2094,7 +2214,12 @@ - Hedgewars + Not all players are ready + + + + Are you sure you want to start this game? +Not all players are ready. @@ -2200,6 +2325,41 @@ Upload this video to your Youtube account + + Reset + + + + Set the default server port for Hedgewars + + + + Invite your friends to your server in just 1 click! + + + + 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. + + + + Start private server + + + + + RoomNamePrompt + + Enter a name for your room. + + + + Cancel + Avbryt + + + Create room + + RoomsListModel @@ -2295,6 +2455,25 @@ + TCPBase + + Unable to start server at %1. + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + At least two teams are required to play! + + + + TeamShowWidget %1's team @@ -2304,13 +2483,17 @@ ThemePrompt - Select a theme for this map - - - Cancel Avbryt + + Search for a theme: + + + + Use selected theme + + binds @@ -2892,4 +3075,119 @@ Styrkors + + server + + Not room master + + + + Corrupted hedgehogs info + + + + too many teams + + + + too many hedgehogs + + + + There's already a team with same name in the list + + + + round in progress + + + + restricted + + + + REMOVE_TEAM: no such team + + + + Not team owner! + + + + Less than two clans! + + + + Room with such name already exists + + + + Nickname already chosen + + + + Illegal nickname + + + + Protocol already known + + + + Bad number + + + + Nickname is already in use + + + + No checker rights + + + + Authentication failed + + + + 60 seconds cooldown after kick + + + + kicked + + + + Ping timeout + + + + bye + + + + Illegal room name + + + + No such room + + + + Joining restricted + + + + Registered users only + + + + You are banned in this room + + + + Empty config entry + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_tr_TR.ts --- a/share/hedgewars/Data/Locale/hedgewars_tr_TR.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_tr_TR.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,10 +2,17 @@ + About + + Unknown Compiler + Bilinmeyen Derleyici + + + AbstractPage Go back - + Geri Dön @@ -16,79 +23,95 @@ copy of - + kopya BanDialog IP - IP + IP Nick - + Takma Ad IP/Nick - + IP Reason - + Sebep Duration - + Süre Ok - + Tamam Cancel - İptal + İptal you know why - + biliyor musunuz Warning - + Uyarı Please, specify %1 - + Lütfen %1 belirtin nickname - + takmaad permanent - + kalıcı DataManager Use Default - + Varsayılanı Kullan FeedbackDialog View - + Göster Cancel - İptal + İptal Send Feedback + Geribildirim Gönder + + + Please give us feedback! + + + + We are always happy about suggestions, ideas, or bug reports. + + + + If you found a bug, you can see if it's already known here (english): + + + + Your email address is optional, but we may want to contact you. @@ -96,12 +119,12 @@ FreqSpinBox Never - + Asla Every %1 turn - - + + Her %1 turda @@ -116,84 +139,120 @@ Düzeni değiştir - Game Options - - - Game scheme will auto-select a weapon - + Oyun planı otomatik bir silah seçecek + + + Map + Harita + + + Game options + Oyun seçenekleri HWApplication - + %1 minutes - - - + + %1 dakika + + + %1 hour - - - + + %1 saat + + + %1 hours - - - + + %1 saat + + + %1 day + + %1 gün + + + + %1 days + + %1 gün + + + + Scheme '%1' not supported - %1 days - + Cannot create directory %1 + %1 dizini oluşturulamadı + + + Failed to open data directory: +%1 + +Please check your installation! + Veri dizini açılamadı: +%1 + +Lütfen kurulumunuzu denetleyin! HWAskQuitDialog Do you really want to quit? - + Gerçekten çıkmak istiyor musunuz? HWChatWidget %1 has been removed from your ignore list - - - - %1 has been added to your ignore list - + %1 yoksayma listenizden kaldırıldı + + + %1 has been added toINCOMPLETE your ignore list + %1 yoksayma listenize eklendi %1 has been removed from your friends list - + %1 arkadaş listenizden kaldırıldı %1 has been added to your friends list - + %1 arkadaş listenize eklendi Stylesheet imported from %1 - + %1 biçembelgesi aktarıldı Enter %1 if you want to use the current StyleSheet in future, enter %2 to reset! - + Geçerli BiçemBelgesini ileride kullanmak için %1, sıfırlamak için %3 girin! Couldn't read %1 - + %1 okunamadı StyleSheet discarded - + BiçemBelgesi silindi StyleSheet saved to %1 - + BiçemBelgesi %1 konumuna kaydedildi Failed to save StyleSheet to %1 + BiçemBelgesi %1 konumuna kaydedilemedi + + + %1 has been added to your ignore list @@ -205,50 +264,50 @@ DefaultTeam - + VarsayılanTakım Hedgewars Demo File File Types - + Hedgewars Gösteri Dosyası Hedgewars Save File File Types - + Hedgewars Kayıt Dosyası Demo name - + Gösteri adı Demo name: - + Gösteri adı: Game aborted - + Oyun sonlandı Nickname - + Takma ad No nickname supplied. - + Takma ad girilmedi. Someone already uses your nickname %1 on the server. Please pick another nickname: - + Sunucuda başka biri %1 takma adını kullanıyor. Başka bir isim girin: %1's Team - + %1 Oyuncusunun Takımı Hedgewars - Nick registered - + Hedgewars - Takma ad kayıtlı This nick is registered, and you haven't specified a password. @@ -256,44 +315,53 @@ If this nick isn't yours, please register your own nick at www.hedgewars.org Password: - + Bu takma ad kayıtlı ve bir parola belirtmediniz. + +Bu takma ad sizin değilse, lütfen kendi takma adınızı www.hedgewars.org adresinden kaydedin. + +Parola: Your nickname is not registered. To prevent someone else from using it, please register it at www.hedgewars.org - + Takma adınız kayıtlı değil. +Başkasının kullanmaması için lütfen, +www.hedgewars.org sitesinde kaydedin Your password wasn't saved either. - + + +Parolanız da kaydedilmedi. Hedgewars - Empty nickname - + Hedgewars - Boş takma ad Hedgewars - Wrong password - + Hedgewars - Hatalı parola You entered a wrong password. - + Hatalı parola girdiniz. Try Again - + Tekrar Dene Hedgewars - Connection error - + Hedgewars - Bağlantı hatası You reconnected too fast. Please wait a few seconds and try again. - + Çok hızlı yeniden bağlandınız. +Birkaç saniye bekleyin ve yeniden deneyin. @@ -335,103 +403,103 @@ Small tunnels - + Küçük tüneller Medium tunnels - + Orta tüneller Seed - + Besleme Map type: - + Harita türü: Image map - + Resim haritası Mission map - + Görev haritası Hand-drawn - + El çizimi Randomly generated - + Rastgele oluşturulmuş Random maze - + Rastgele labirent Random - Rastgele + Rastgele Map preview: - + Harita önizleme: Load map drawing - + Yerel harita çizimi Edit map drawing - - - - Largetunnels - + Harita çizimini düzenle Small islands - + Küçük adalar Medium islands - + Orta adalar Large islands - + Büyük adalar Map size: - + Harita boyutu: Maze style: - + Labirent biçemi: Mission: - + Görev: Map: - + Harita: Theme: - + Tema: Load drawn map - + Çizili harita yükle Drawn Maps - + Çizili Haritalar All files - + Tüm dosyalar + + + Large tunnels + Büyük tüneller @@ -465,7 +533,7 @@ Quit reason: - Çıkma sebebi: + Çıkma sebebi: You got kicked @@ -473,37 +541,52 @@ %1 *** %2 has joined the room - + %1 *** %2 odaya katıldı %1 *** %2 has joined - + %1 *** %2 katıldı %1 *** %2 has left - + %1 *** %2 ayrıldı %1 *** %2 has left (%3) - + %1 *** %2 ayrıldı (%3) User quit - + Kullanıcı çıktı Remote host has closed connection - + Uzak sunucu bağlantıyı kapattı The server is too old. Disconnecting now. - + Sunucu çok eski. Bağlantı kesiliyor. HWPasswordDialog Login + Oturum aç + + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + Nickname: + + + + Password: @@ -511,37 +594,33 @@ HWUploadVideoDialog Upload video - + Video yükle Upload - + Yükle HatButton Change hat (%1) - + Şapkayı değiştir (%1) HatPrompt - Select a hat - - - - Filter: - - - Cancel - İptal + İptal Use selected hat - + Seçili şapkayı kullan + + + Search for a hat: + Şapka ara: @@ -555,7 +634,7 @@ KeyBinder Category - + Kategori @@ -563,93 +642,94 @@ Duration: %1m %2s - + Süre: %1d %2s + Video: %1x%2, - + Video: %1x%2, %1 fps, - + %1 fps, Audio: - + Ses: unknown - + bilinmiyor MapModel No description available. - + Kullanılabilir açıklama yok. PageAdmin Clear Accounts Cache - + Hesap Belleğini Temizle Fetch data - + Veri getir Server message for latest version: - + Son sürüm için sunucu iletisi: Server message for previous versions: - + Önceki sürümler için sunucu iletisi: Latest version protocol number: - + En son sürüm protokol numarası: MOTD preview: - + MOTD önizleme: Set data - + Veri ayarla General - Genel + Genel Bans - + Engellemeler IP/Nick - + IP/Takma Ad Expiration - + Dolum Reason - + Sebep Refresh - + Yenile Add - + Ekle Remove - + Kaldır @@ -663,39 +743,39 @@ PageDrawMap Undo - + Geri al Clear - + Temizle Load - Yükle + Yükle Save - + Kaydet Load drawn map - + Çizili harita yükle Save drawn map - + Çizili haritayı kaydet Drawn Maps - + Çizili Haritalar All files - + Tüm dosyalar Eraser - + Silgi @@ -706,93 +786,93 @@ Select an action to choose a custom key bind for this team - + Bu takıma özel tuş ataması için bir eylem seçin Use my default - + Varsayılanı kullan Reset all binds - + Tüm atamaları sıfırla Custom Controls - + Özel Denetimler Hat - + Şapka Name - + İsim This hedgehog's name - + Bu kirpinin adı Randomize this hedgehog's name - + Kirpi adını rastgele ata Random Team - + Rastgele Takım PageGameStats Details - + Ayrıntılar Health graph - + Sağlık Grafiği Ranking - + Sıralama The best shot award was won by <b>%1</b> with <b>%2</b> pts. - + En iyi atış ödülü: <b>%2</b> puanla <b>%1</b> The best killer is <b>%1</b> with <b>%2</b> kills in a turn. - - + + En iyi öldürücü: <b>%1</b> bir turda <b>%2</b> öldürme. A total of <b>%1</b> hedgehog(s) were killed during this round. - - + + Bu turda toplam <b>%1</b> kirpi öldürüldü. (%1 kill) - - + + (%1 öldürme) <b>%1</b> thought it's good to shoot his own hedgehogs with <b>%2</b> pts. - - + + <b>%1</b> kendi kirpilerini <b>%2</b> puanla vurmanın güzel olduğunu düşündü <b>%1</b> killed <b>%2</b> of his own hedgehogs. - - + + <b>%1</b> kendi <b>%2</b> kirpisini öldürdü <b>%1</b> was scared and skipped turn <b>%2</b> times. - - + + <b>%1</b> korktu ve <b>%2</b> kez turu pas geçti. @@ -800,61 +880,73 @@ PageInGame In game... - + Oyunda... PageInfo Open the snapshot folder - + Ekran görüntü klasörünü aç PageMain Downloadable Content - + İndirilebilir İçerik Play a game on a single computer - + Tek bir bilgisayarda oyna Play a game across a network - + Ağ üzerinde oyna Read about who is behind the Hedgewars Project - + Hedgewars Projesinin arkasında kimlerin olduğunu göster Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars - + Sorunları bildirme, özellik önerme veya Hedgewars oyununu ne kadar sevdiğinizi söylemek için geri bildirim bırakın Access the user created content downloadable from our website - + Websitemizden kullanıcılar tarafından oluşturulmuş indirilebilir içeriğe bakın Exit game - + Oyundan çık Manage videos recorded from game - + Oyunda kayıtlı videolarınızı yönetin Edit game preferences - + Oyun tercihlerini düzenle Play a game across a local area network - + Yerel ağda bir oyun oyna Play a game on an official server - + Resmi bir sunucuda oyun oyna + + + Feedback + Geri Bildirim + + + Play local network game + Yerel ağ oyunu oyna + + + Play official network game + Resmi ağ oyunu oyna @@ -865,22 +957,37 @@ Edit game preferences - + Oyun tercihlerini düzenle PageNetGame Control - Kontrol + Denetim Edit game preferences - + Oyun tercihlerini düzenle Start - Başla + Başla + + + Update + Güncelle + + + Room controls + Oda denetimleri + + + + PageNetServer + + Insert your address here + @@ -895,111 +1002,111 @@ Delete team - + Takımı sil You can't edit teams from team selection. Go back to main menu to add, edit or delete teams. - + Takım seçiminden takımları düzenleyemezsiniz. Takım eklemek, düzenlemek ve silmek için ana menüye dönün. New scheme - + Yeni plan Edit scheme - + Planı düzenle Delete scheme - + Planı sil New weapon set - + Yeni silah seti Edit weapon set - + Silah setini düzenle Delete weapon set - + Silah setini sil Advanced - Gelişmiş + Gelişmiş Reset to default colors - + Varsayılan renklere sıfırla Proxy host - + Vekil sunucusu Proxy port - + Vekil portu Proxy login - + Vekil kullanıcı adı Proxy password - + Vekil parolası No proxy - + Vekil sunucu yok Socks5 proxy - + Socks5 vekil sunucusu HTTP proxy - + HTTp vekil sunucusu System proxy settings - + Sistem vekil ayarları Select an action to change what key controls it - + Denetimi kullanan tuşu değiştirmek için bir eylem seçin Reset to default - + Varsayılana sıfırla Reset all binds - + Tüm atamaları sıfırla Game - + Oyun Graphics - + Grafik Audio - + Ses Controls - + Denetimler Video Recording - + Video Kaydı Network - + Teams @@ -1007,7 +1114,7 @@ Schemes - + Planlar Weapons @@ -1015,43 +1122,43 @@ Frontend - + Ön Uç Custom colors - + Özel renkler Game audio - + Oyun sesi Frontend audio - + Ön uç sesi Account - + Hesap Proxy settings - + Vekil sunucu ayarları Miscellaneous - + Çeşitli Updates - + Güncellemeler Check for updates - + Güncellemeleri Denetle Video recording options - + Video kayıt seçenekleri @@ -1069,42 +1176,54 @@ PageRoomsList Create - Oluştur + Oluştur Join - Katıl + Katıl Admin features Yönetici görevleri - Room Name: - - - Rules: - + Kurallar: Weapons: - - - - Search: - - - - Clear - + Silahlar: %1 players online - + %1 oyuncu çevrimiçi + + Search for a room: + Bir oda ara: + + + Create room + Oda oluştur + + + Join room + Odaya katıl + + + Room state + Oda durumu + + + Clear filters + Süzgeçleri temizle + + + Open server administration page + Sunucu yönetim sayfasını aç + PageScheme @@ -1114,7 +1233,7 @@ Teams will start on opposite sides of the terrain, two team colours max! - Takımlar bölgenin faklı taraflarında başlarlar, en fazla iki takım rengi! + Takımlar bölgenin farklı taraflarında başlarlar, en fazla iki takım rengi! Land can not be destroyed! @@ -1134,7 +1253,7 @@ Gain 80% of the damage you do back in health - Verdiğin hasarın %%80'ini sağlık olarak kazan + Verdiğin hasarın %80'ini sağlık olarak kazan Share your opponents pain, share their damage @@ -1162,63 +1281,63 @@ Order of play is random instead of in room order. - + Oda sırası yerine oynama sırası rastgeledir. Play with a King. If he dies, your side dies. - + Bir Kralla oyna. O ölürse takımın ölür. Take turns placing your hedgehogs before the start of play. - + Oyuna başlamadan önce kirpileri sırayla yerleştirin. Ammo is shared between all teams that share a colour. - + Aynı rengi paylaşan tüm takımlar cephaneyi paylaşır. Disable girders when generating random maps. - + Rastgele haritalar oluştururken kirişleri devre dışı bırak. Disable land objects when generating random maps. - + Rastgele haritalar oluştururken zemin nesnelerini devre dışı bırak. AI respawns on death. - + Yapay zeka, öldükten sonra yeniden doğar All (living) hedgehogs are fully restored at the end of turn - + Tüm (yaşayan) kirpiler tur sonunda eski haline gelir Attacking does not end your turn. - + Saldırmak sıranı bitirmez. Weapons are reset to starting values each turn. - + Silahlar her turda başlangıç değerlerine sıfırlanır. Each hedgehog has its own ammo. It does not share with the team. - + Her kirpinin kendi cephanesi olur. Takımla paylaşmaz. You will not have to worry about wind anymore. - + Artık rüzgarı dert etmen gerekmiyor. Wind will affect almost everything. - + Rüzgar neredeyse her şeyi etkiler. Copy - + Kopyala Teams in each clan take successive turns sharing their turn time. - + Her klandaki takımlar kendi sıralarındaki zamanı paylaşarak değişirler. Add an indestructible border around the terrain @@ -1226,14 +1345,14 @@ Add an indestructible border along the bottom - + Alta yok edilemez bir sınır ekle PageSelectWeapon Default - Öntanımlı + Varsayılan Delete @@ -1245,92 +1364,94 @@ Copy - + Kopyala PageSinglePlayer Play a quick game against the computer with random settings - + Rastgele ayarlarla bilgisayara karşı hızlı bir oyun oyna Play a hotseat game against your friends, or AI teams - + Arkadaşlarınla veya Yapay Zeka takımlarıyla ayarlanmış bir oyun oyna Campaign Mode - + Mücadele Kipi Practice your skills in a range of training missions - + Yeteneklerini çeşitli eğitim görevleri ile geliştir Watch recorded demos - + Kayıtlı gösterileri izle Load a previously saved game - + Önceden kayıtlı bir oyun yükle PageTraining No description available - + Kullanılabilir açıklama yok Select a mission! - + Bir görev seç! Pick the mission or training to play - + Oynamak üzere bir görev veya eğitim seç Start fighting - + Dövüşe başla PageVideos Name - + İsim Size - + Boyut %1 bytes - + %1 bayt (in progress...) - + (yapım aşamasında...) encoding - + kodlanıyor uploading - + yükleniyor Date: %1 - + Tarih: %1 + Size: %1 - + Boyut: %1 + @@ -1357,27 +1478,39 @@ Follow - + Takip Et Ignore - + Yoksay Add friend - + Arkadaş ekle Unignore - + Yoksaymayı kapat Remove friend - + Arkadaş kaldır Update - Güncelle + Güncelle + + + Restrict Unregistered Players Join + Kayıtsız Oyuncuların Katılmasını Kısıtla + + + Show games in lobby + Lobideki oyunları göster + + + Show games in-progress + Süren oyunları göster @@ -1400,59 +1533,59 @@ Check for updates at startup - + Başlangıçta güncellemeleri denetle Show ammo menu tooltips - + Cephane menüsü araç ipuçlarını göster Save password - + Parolayı kaydet Save account name and password - + Hesap adı ve parolasını kaydet Video is private - + Video özel Record audio - + Sesi kaydet Use game resolution - + Oyun çözünürlüğünü kullan Visual effects - + Görsel efektler Sound - + Ses In-game sound effects - + Oyun ses efektleri Music - + Müzik In-game music - + Oyun içi müzik Frontend sound effects - + Ön uç ses efektleri Frontend music - + Ön uç müziği @@ -1463,87 +1596,79 @@ Level - Bilgisayar + Seviye (System default) - + (Sistem varsayılanı) Community - + Topluluk Any - - - - In lobby - - - - In progress - + Herhangi Disabled - + Kapalı Red/Cyan - + Kırmızı/Camgöbeği Cyan/Red - + Camgöbeği/Kırmızı Red/Blue - + Kırmızı/Mavi Blue/Red - + Mavi/Kırmızı Red/Green - + Kırmızı/Yeşil Green/Red - + Yeşil/Kırmızı Side-by-side - + Yan yana Top-Bottom - + Üst-Alt Red/Cyan grayscale - + Kırmızı/Camgöbeği gri Cyan/Red grayscale - + Camgöbeği/Kırmızı gri Red/Blue grayscale - + Kırmızı/Mavi gri Blue/Red grayscale - + Mavi/Kırmızı gri Red/Green grayscale - + Kırmızı/Yeşil gri Green/Red grayscale - + Yeşil/Kırmızı gri @@ -1574,15 +1699,15 @@ Team Settings - + Takım ayarları Videos - + Videolar Description - + Açıklama @@ -1597,7 +1722,7 @@ Version - Sürüm + Sürüm Weapons @@ -1657,145 +1782,143 @@ % Dud Mines - + Sahte Mayın % Name - + İsim Type - + Tür Grave - + Mezar taşı Flag - + Bayrak Voice - + Ses Locale - + Dil Explosives - + Patlayıcılar Tip: - + İpucu: Quality - + Kalite % Health Crates - + Sağlık Sandık %'si Health in Crates - + Sandıklardaki Sağlık Sudden Death Water Rise - + Ani Ölüm Su Yükselmesi Sudden Death Health Decrease - + Ani Ölüm Sağlık Azaltması % Rope Length - + Halat Uzunluk %'si Stereo rendering - + Stereo hazırlama Style - + Biçem Scheme - + Plan % Get Away Time - - - - This program is distributed under the GNU General Public License v2 - + Uzakta Zamanı %'si There are videos that are currently being processed. Exiting now will abort them. Do you really want to quit? - + Şu anda işlenen videolar var. +Çıkmak bu işlemi sonlandıracak. +Gerçekten çıkmak istiyor musunuz? Please provide either the YouTube account name or the email address associated with the Google Account. - + Lütfen YouTube hesap adını veya Google Hesabınız ile ilişkilendirmiş e-posta adresinizi girin. Account name (or email): - + Hesap adı (veya e-posta): Password: - + Parola: Video title: - + Video başlığı: Video description: - + Video açıklaması: Tags (comma separated): - + Etiketler (virgülle ayrılmış): Description - + Açıklama Nickname - + Takma ad Format - + Biçim Audio codec - + Ses kodlayıcı Video codec - + Video kodlayıcı Framerate - + Kare oranı Bitrate (Kbps) - + Bit oranı (Kbps) 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! - + Bu geliştirme derlemesi 'yapım aşamasındadır' ve oyunun diğer sürümleri ile uyumlu olmayabilir; bazı özellikler bozuk veya tamamlanmamış olabilir! Fullscreen @@ -1803,27 +1926,35 @@ Fullscreen Resolution - + Tam Ekran Çözünürlüğü Windowed Resolution - + Pencere Çözünürlüğü Your Email - + E-postanız Summary - + Özet Send system information - + Sistem bilgisi gönder Type the security code: - + Güvenlik kodunu yaz: + + + Revision + Gözden Geçirme + + + This program is distributed under the %1 + Bu program %1 altında dağıtılmaktadır @@ -1834,11 +1965,11 @@ hedgehog %1 - + kirpi %1 anonymous - + anonim @@ -1847,6 +1978,10 @@ Hedgewars %1 Hedgewars %1 + + -r%1 (%2) + -r%1 (%2) + QMessageBox @@ -1860,96 +1995,95 @@ File association failed. - + Dosya ilişkilendirme başarısız. Error while authenticating at google.com: - + Google.com ile kimlik açma başarısız Login or password is incorrect - + Kullanıcı adı veya parolası yanlış Error while sending metadata to youtube.com: - + Youtube.com üst verisi gönderilirken hata Teams - Are you sure? - + Takımlar - Emin misiniz? Do you really want to delete the team '%1'? - + '%1' takımını gerçekten silmek istiyor musunuz? Cannot delete default scheme '%1'! - + Varsayılan '%1' planı silinemez Please select a record from the list - + Lütfen listeden bir kayıt seçin Unable to start server - + Sunucu başlatılamadı Hedgewars - Error - + Hedgewars - Hata Hedgewars - Success - + Hedgewars - Başarılı All file associations have been set - - - - Main - Error - + Tüm dosya ilişkilendirmeleri ayarlandı Cannot create directory %1 - %1 dizini oluşturulamadı + %1 dizini oluşturulamadı Failed to open data directory: %1 Please check your installation! - + Veri dizini açılamadı: +%1 + +Lütfen kurulumunuzu denetleyin! TCP - Error - + TCP - Hata Unable to start the server: %1. - Sunucu başlatılamadı: %1. + Sunucu başlatılamadı: %1. Unable to run engine at - + Motor şurada başlatılamadı: Error code: %1 - + Hata kodu: %1 Video upload - Error - + Video yükleme - Hata Netgame - Error - + Ağ oyunu - Hata Please select a server from the list - + Lütfen listeden bir sunucu seçin Please enter room name @@ -1957,7 +2091,7 @@ Record Play - Error - + Oyunu Kaydet - Hata Please select record from the list @@ -1965,15 +2099,15 @@ Cannot rename to - + Adlandırma başarısız: Cannot delete file - + Dosya silinemedi: Room Name - Error - + Oda Adı - Hata Please select room from the list @@ -1981,117 +2115,128 @@ Room Name - Are you sure? - + Oda Adı - Emin misiniz? The game you are trying to join has started. Do you still want to join the room? - + Katılmaya çalıştığınız oyun başlamış. +Hala odaya katılmak istiyor musunuz? Schemes - Warning - + Planlar - Uyarı Schemes - Are you sure? - + Planlar - Emin misiniz? Do you really want to delete the game scheme '%1'? - + Gerçekten '%1' oyun planını silmek istiyor musunuz? Videos - Are you sure? - + Videolar - Emin misiniz? Do you really want to delete the video '%1'? - + Gerçekten '%1' videosunu silmek istiyor musunuz? Do you really want to remove %1 file(s)? - + Gerçekten %1 dosyayı kaldırmak istiyor musunuz? Do you really want to cancel uploading %1? - + Gerçekten %1 yüklemesini iptal etmek istiyor musunuz? File error - + Dosya hatası Cannot open '%1' for writing - + '%1' yazmak için açılamıyor Cannot open '%1' for reading - + '%1' okumak için açılamıyor Cannot use the ammo '%1'! - + '%1' cephanesi kullanılamıyor! Weapons - Warning - + Silahlar - Uyarı Cannot overwrite default weapon set '%1'! - + Varsayılan '%1' silah setinin üzerine yazılamaz! Cannot delete default weapon set '%1'! - + Varsayılan '%1' silah seti silinemez! Weapons - Are you sure? - + Silahlar - Emin misiniz? Do you really want to delete the weapon set '%1'? - + Gerçekten '%1' silah setini silmek istiyor musunuz? Hedgewars - Nick not registered - + Hedgewars - Takma ad kayıtlı değil System Information Preview - + Sistem Bilgi Önizlemesi Failed to generate captcha - + Captcha oluşturulamadı Failed to download captcha - + Captcha indirilemedi Please fill out all fields. Email is optional. - + Lütfen tüm alanları doldurun. E-posta isteğe bağlıdır. Hedgewars - Warning - + Hedgewars - Uyarı Hedgewars - Information - + Hedgewars - Bilgi Hedgewars - + Hedgewars + + + Not all players are ready + Tüm oyuncular hazır değil + + + Are you sure you want to start this game? +Not all players are ready. + Oyunu başlatmak istiyor musunuz? +Tüm oyuncular hazır değil. QPushButton default - öntanımlı + varsayılan OK @@ -2143,74 +2288,109 @@ Associate file extensions - + Dosya uzantılarını ilişkilendir More info - + Daha fazla bilgi Set default options - + Varsayılan seçenekleri ayarla Open videos directory - + Video dizinini aç Play - + Oynat Upload to YouTube - + YouTube'a Yükle Cancel uploading - + Yüklemeyi iptal et Restore default coding parameters - + Varsayılan kodlama parametrelerini geri al Open the video directory in your system - + Sisteminizdeki video dizinini aç Play this video - + Bu videoyu oynat Delete this video - + Bu videoyu sil Upload this video to your Youtube account + Bu videoyu Youtube hesabınıza yükle + + + Reset + + Set the default server port for Hedgewars + + + + Invite your friends to your server in just 1 click! + + + + 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. + + + + Start private server + + + + + RoomNamePrompt + + Enter a name for your room. + Odanız için bir ad girin. + + + Cancel + İptal + + + Create room + Oda oluştur + RoomsListModel In progress - + Sürüyor Room Name - + Oda Adı C - + K T - + T Owner - + Sahip Map @@ -2218,7 +2398,7 @@ Rules - + Kurallar Weapons @@ -2226,22 +2406,22 @@ Random Map - + Rastgele Harita Random Maze - + Rastgele Labirent Hand-drawn - + El Çizimi SeedPrompt The map seed is the basis for all random values generated by the game. - + Harita beslemesi, oyun tarafından oluşturulan tüm rastgele değerler için bir tabandır. Cancel @@ -2249,30 +2429,30 @@ Set seed - + Besleme ayarla Close - + Kapat SelWeaponWidget Weapon set - + Silah seti Probabilities - + Olasılıklar Ammo in boxes - + Kutulardaki cephane Delays - + Gecikmeler new @@ -2280,6 +2460,25 @@ copy of + kopya + + + + TCPBase + + Unable to start server at %1. + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + At least two teams are required to play! @@ -2287,19 +2486,23 @@ TeamShowWidget %1's team - + %1 takımı ThemePrompt - Select a theme for this map - - - Cancel İptal + + Search for a theme: + Tema arayın: + + + Use selected theme + Seçili temayı kullan + binds @@ -2425,7 +2628,7 @@ change mode - modu değiştir + kipi değiştir capture @@ -2437,23 +2640,23 @@ long jump - + uzun zıplama high jump - + yüksek zıplama zoom in - + yakınlaştırma zoom out - + uzaklaştırma reset zoom - + yakınlaştırmayı sıfırla slot 10 @@ -2461,22 +2664,22 @@ mute audio - + sesi kapat record - + kaydet hedgehog info - + kirpi bilgisi binds (categories) Movement - + Hareket Weapons @@ -2484,117 +2687,117 @@ Camera - + Kamera Miscellaneous - + Çeşitli binds (descriptions) Traverse gaps and obstacles by jumping: - + Boşluklardan ve engellerden zıplayarak kaçın: Fire your selected weapon or trigger an utility item: - + Seçili silahını ateşle veya bir yardımcı öge tetikle: Pick a weapon or a target location under the cursor: - + Bir silah seç veya imleç altında konum işaretle Switch your currently active hog (if possible): - + Geçerli kirpiyi değiştir (mümkünse): Pick a weapon or utility item: - + Bir silah veya yardımcı öge al: Set the timer on bombs and timed weapons: - + Bombalarda ve zamanlı silahlarda zamanlayıcıyı ayarla: Move the camera to the active hog: - + Kamerayı etkin kirpiye götür: Move the cursor or camera without using the mouse: - + Kamera veya imleci fare kullanmadan hareket ettir Modify the camera's zoom level: - + Kamera yakınlaştırma seviyesini değiştir: Talk to your team or all participants: - + Takımla veya tüm katılanlarla konuş Pause, continue or leave your game: - + Oyunu beklet, devam et veya oyundan ayrıl Modify the game's volume while playing: - + Oynarken oyunun sesini değiştir: Toggle fullscreen mode: - + Tam ekran kipini değiştir: Take a screenshot: - + Ekran görüntüsü al: Toggle labels above hedgehogs: - + Kirpilerin üzerindeki etiketleri aç/kapat Record video: - + Video kaydet: Hedgehog movement - + Kirpi hareketi binds (keys) Axis - + Eksen (Up) - + (Yukarı) (Down) - + (Aşağı) Hat - + Şapka (Left) - + (Sol) (Right) - + (Sağ) Button - + Düğme Keyboard - + Klavye Delete @@ -2602,283 +2805,398 @@ Mouse: Left button - + Fare: Sol düğme Mouse: Middle button - + Fare: Orta düğme Mouse: Right button - + Fare: Sağ düğme Mouse: Wheel up - + Fare: Tekerlek yukarı Mouse: Wheel down - + Fare: Tekerlek aşağı Backspace - + Backspace Tab - + Sekme Clear - + Temizle Return - + Enter Pause - + Pause Escape - + Escape Space - + Boşluk Numpad 0 - + Nümerik 0 Numpad 1 - + Nümerik 1 Numpad 2 - + Nümerik 2 Numpad 3 - + Nümerik 3 Numpad 4 - + Nümerik 4 Numpad 5 - + Nümerik 5 Numpad 6 - + Nümerik 6 Numpad 7 - + Nümerik 7 Numpad 8 - + Nümerik 8 Numpad 9 - + Nümerik 9 Numpad . - + Nümerik . Numpad / - + Nümerik / Numpad * - + Nümerik * Numpad - - + Nümerik - Numpad + - + Nümerik + Enter - + Enter Equals - + Eşittir Up - + Yukarı Down - + Aşağı Right - + Sağ Left - + Sol Insert - + Ekle Home - + Ev End - + Son Page up - + Sayfa yukarı Page down - + Sayfa aşağı Num lock - + Nümerik kilit Caps lock - + Büyük harf Scroll lock - + Kaydırma kilidi Right shift - + Sağ üst karakter Left shift - + Sol üst karakter Right ctrl - + Sağ kontrol Left ctrl - + Sol kontrol Right alt - + Sağ alt Left alt - + Sol alt Right meta - + Sağ meta Left meta - + Sol meta A button - + A düğmesi B button - + B düğmesi X button - + X düğmesi Y button - + Y düğmesi LB button - + LB düğmesi RB button - + RB düğmesi Back button - + Geri düğmesi Start button - + Start düğmesi Left stick - + Sol çubuk Right stick - + Sağ çubuk Left stick (Right) - + Sol çubuk (Sağ) Left stick (Left) - + Sol çubuk (Sol) Left stick (Down) - + Sol çubuk (Aşağı) Left stick (Up) - + Sol çubuk (Yukarı) Left trigger - + Sol tetik Right trigger - + Sağ tetik Right stick (Down) - + Sağ çubuk (Aşağı) Right stick (Up) - + Sağ çubuk (Yukarı) Right stick (Right) - + Sağ çubuk (Sağ) Right stick (Left) - + Sağ çubuk (Sol) DPad - + DPad + + + + server + + Not room master + Oda uzmanı değil + + + Corrupted hedgehogs info + Bozuk kirpi bilgisi + + + too many teams + çok fazla takım + + + too many hedgehogs + çok fazla kirpi + + + There's already a team with same name in the list + Listede aynı isimde başka bir takım var + + + round in progress + tur sürüyor + + + restricted + kısıtlı + + + REMOVE_TEAM: no such team + REMOVE_TEAM: böyle bir takım yok + + + Not team owner! + Takım sahibi değil! + + + Less than two clans! + İki klandan daha az! + + + Room with such name already exists + Oda adı zaten mevcut + + + Nickname already chosen + Takma ad zaten seçilmiş + + + Illegal nickname + Geçersiz takma ad + + + Protocol already known + Protokol zaten biliniyor + + + Bad number + Hatalı sayı + + + Nickname is already in use + Takma ad zaten kullanımda + + + No checker rights + Denetim hakları yok + + + Authentication failed + Kimlik doğrulama başarısız + + + 60 seconds cooldown after kick + Kovulduktan sonra 60 saniye sakinleşme + + + kicked + kovuldu + + + Ping timeout + Ping zaman aşımı + + + bye + hoşça kal + + + Illegal room name + Geçersiz oda adı + + + No such room + Böyle bir oda yok + + + Joining restricted + Katılma kısıtlı + + + Registered users only + Sadece kayıtlı kullanıcılar + + + You are banned in this room + Bu odadan engellendiniz + + + Empty config entry + Boş yapılandırma girdisi diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_uk.ts --- a/share/hedgewars/Data/Locale/hedgewars_uk.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_uk.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,6 +2,13 @@ + About + + Unknown Compiler + + + + AbstractPage Go back @@ -91,6 +98,22 @@ Send Feedback + + Please give us feedback! + + + + We are always happy about suggestions, ideas, or bug reports. + + + + If you found a bug, you can see if it's already known here (english): + + + + Your email address is optional, but we may want to contact you. + + FreqSpinBox @@ -119,33 +142,76 @@ Game Options - Параметри гри + Параметри гри Game scheme will auto-select a weapon + + Map + Мапа + + + Game options + + HWApplication - + %1 minutes - - - + + + + + + + %1 hour - - - + + + + + + + %1 hours - - - + + + + + + + %1 day - - - + + + + + + + %1 days + + + + + + + + Scheme '%1' not supported + + + + Cannot create directory %1 + Не можу створити директорію %1 + + + Failed to open data directory: +%1 + +Please check your installation! @@ -388,10 +454,6 @@ - Largetunnels - - - Small islands @@ -435,6 +497,10 @@ All files + + Large tunnels + + HWNetServersModel @@ -508,6 +574,21 @@ Login + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + Nickname: + + + + Password: + + HWUploadVideoDialog @@ -530,14 +611,6 @@ HatPrompt - Select a hat - - - - Filter: - - - Cancel Скасувати @@ -545,6 +618,10 @@ Use selected hat + + Search for a hat: + + KB @@ -870,6 +947,18 @@ Play a game on an official server + + Feedback + + + + Play local network game + + + + Play official network game + + PageMultiplayer @@ -886,7 +975,7 @@ PageNetGame Control - Керування + Керування Edit game preferences @@ -896,6 +985,21 @@ Start Старт + + Update + Оновити + + + Room controls + + + + + PageNetServer + + Insert your address here + + PageOptions @@ -1083,11 +1187,11 @@ PageRoomsList Create - Створити + Створити Join - Приєднатися + Приєднатися Admin features @@ -1095,7 +1199,7 @@ Room Name: - Назва Кімнати: + Назва Кімнати: Rules: @@ -1107,11 +1211,11 @@ Search: - Пошук: + Пошук: Clear - Очистити + Очистити %1 players online @@ -1121,6 +1225,30 @@ %1 гравців в мережі + + Search for a room: + + + + Create room + + + + Join room + + + + Room state + + + + Clear filters + + + + Open server administration page + + PageScheme @@ -1395,7 +1523,19 @@ Update - Оновити + Оновити + + + Restrict Unregistered Players Join + + + + Show games in lobby + + + + Show games in-progress + @@ -1497,11 +1637,11 @@ In lobby - В вестибюлі + В вестибюлі In progress - В процесі + В процесі Disabled @@ -1615,7 +1755,7 @@ Version - Версія + Версія Weapons @@ -1750,10 +1890,6 @@ % Час Тікати - This program is distributed under the GNU General Public License v2 - - - There are videos that are currently being processed. Exiting now will abort them. Do you really want to quit? @@ -1843,6 +1979,14 @@ Type the security code: + + Revision + + + + This program is distributed under the %1 + + QLineEdit @@ -1865,6 +2009,10 @@ Hedgewars %1 Hedgewars %1 + + -r%1 (%2) + + QMessageBox @@ -1927,35 +2075,12 @@ - Main - Error - - - Cannot create directory %1 - Не можу створити директорію %1 - - - Failed to open data directory: -%1 - -Please check your installation! - - - - TCP - Error - + Не можу створити директорію %1 Unable to start the server: %1. - Помилка запуску сервера: %1. - - - Unable to run engine at - - - - Error code: %1 - + Помилка запуску сервера: %1. Video upload - Error @@ -2104,7 +2229,12 @@ - Hedgewars + Not all players are ready + + + + Are you sure you want to start this game? +Not all players are ready. @@ -2210,6 +2340,41 @@ Upload this video to your Youtube account + + Reset + + + + Set the default server port for Hedgewars + + + + Invite your friends to your server in just 1 click! + + + + 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. + + + + Start private server + + + + + RoomNamePrompt + + Enter a name for your room. + + + + Cancel + Скасувати + + + Create room + + RoomsListModel @@ -2305,6 +2470,25 @@ + TCPBase + + Unable to start server at %1. + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + At least two teams are required to play! + + + + TeamShowWidget %1's team @@ -2314,13 +2498,17 @@ ThemePrompt - Select a theme for this map - - - Cancel Скасувати + + Search for a theme: + + + + Use selected theme + + binds @@ -2902,4 +3090,119 @@ + + server + + Not room master + + + + Corrupted hedgehogs info + + + + too many teams + + + + too many hedgehogs + + + + There's already a team with same name in the list + + + + round in progress + + + + restricted + + + + REMOVE_TEAM: no such team + + + + Not team owner! + + + + Less than two clans! + + + + Room with such name already exists + + + + Nickname already chosen + + + + Illegal nickname + + + + Protocol already known + + + + Bad number + + + + Nickname is already in use + + + + No checker rights + + + + Authentication failed + + + + 60 seconds cooldown after kick + + + + kicked + + + + Ping timeout + + + + bye + + + + Illegal room name + + + + No such room + + + + Joining restricted + + + + Registered users only + + + + You are banned in this room + + + + Empty config entry + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_zh_CN.ts --- a/share/hedgewars/Data/Locale/hedgewars_zh_CN.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_zh_CN.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,6 +2,14 @@ + About + + + Unknown Compiler + + + + AbstractPage @@ -97,17 +105,37 @@ FeedbackDialog - + + Please give us feedback! + + + + + We are always happy about suggestions, ideas, or bug reports. + + + + + If you found a bug, you can see if it's already known here (english): + + + + + Your email address is optional, but we may want to contact you. + + + + View - + Cancel 取消 - + Send Feedback @@ -130,56 +158,89 @@ GameCFGWidget - - Game Options - - - - + + Map + 地图 + + + + Game options + + + + Edit weapons - + Game scheme will auto-select a weapon - + Edit schemes 修改游戏设置 HWApplication - + %1 minutes - - - + + + + + %1 hour - - - + + + + + %1 hours - - - + + + + + %1 day - - - + + + + + %1 days + + + + + + + Scheme '%1' not supported + + + + + Cannot create directory %1 + + + + + Failed to open data directory: +%1 + +Please check your installation! @@ -194,52 +255,52 @@ HWChatWidget - + %1 has been removed from your ignore list - + %1 has been added to your ignore list - + %1 has been removed from your friends list - + %1 has been added to your friends list - + Stylesheet imported from %1 - - Enter %1 if you want to use the current StyleSheet in future, enter %2 to reset! - - - - - Couldn't read %1 - - - + Enter %1 if you want to use the current StyleSheet in future, enter %2 to reset! + + + + + Couldn't read %1 + + + + StyleSheet discarded - + StyleSheet saved to %1 - + Failed to save StyleSheet to %1 @@ -247,27 +308,27 @@ HWForm - + DefaultTeam - + %1's Team - + Game aborted - + Hedgewars - Nick registered - + This nick is registered, and you haven't specified a password. If this nick isn't yours, please register your own nick at www.hedgewars.org @@ -276,93 +337,93 @@ - + Your nickname is not registered. To prevent someone else from using it, please register it at www.hedgewars.org - + Your password wasn't saved either. - + Nickname - + Someone already uses your nickname %1 on the server. Please pick another nickname: - - + + No nickname supplied. - - + + Hedgewars - Empty nickname - + Hedgewars - Wrong password - + You entered a wrong password. - + Try Again - + Hedgewars - Connection error - + You reconnected too fast. Please wait a few seconds and try again. - + Hedgewars Demo File File Types - + Hedgewars Save File File Types - + Demo name - + Demo name: - - + + Cannot save record to file %1 无法录入文件 %1 @@ -370,13 +431,13 @@ HWGame - + en.txt zh_CN.txt - + Cannot open demofile %1 DEMO %1 打不开 @@ -384,12 +445,12 @@ HWMapContainer - + Small tunnels - + Medium tunnels @@ -439,103 +500,103 @@ - + Load map drawing - + Edit map drawing - - All - 全部 - - - - Small - 小型 - - - Medium - 中型 + All + 全部 - Large - 大型 + Small + 小型 - Cavern - 洞穴 + Medium + 中型 + Large + 大型 + + + + Cavern + 洞穴 + + + Wacky 曲折 - - Largetunnels - - - - - Small islands - - - - Medium islands + Large tunnels + Small islands + + + + + Medium islands + + + + Large islands - + Map size: - + Maze style: - + Mission: - + Map: - - + + Theme: - + Load drawn map - + Drawn Maps - + All files @@ -561,65 +622,65 @@ HWNewNet - + User quit - + Remote host has closed connection - + The host was not found. Please check the host name and port settings. 错误没找到这个主机。请检查主机名和端口设置。 - + Connection refused 连接被拒绝 - + The server is too old. Disconnecting now. - + %1 *** %2 has joined - - + + %1 *** %2 has left - - + + %1 *** %2 has left (%3) - - + + %1 *** %2 has joined the room - + Quit reason: 退出原因: - + Room destroyed 房间损坏 - + You got kicked 被踢出 @@ -631,6 +692,24 @@ Login + + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + + Nickname: + + + + + Password: + + HWUploadVideoDialog @@ -656,22 +735,17 @@ HatPrompt - - Select a hat - - - - - Filter: - - - - + + Search for a hat: + + + + Cancel 取消 - + Use selected hat @@ -724,7 +798,7 @@ MapModel - + No description available. @@ -1012,47 +1086,62 @@ - + + Play local network game + + + + Play a game across a local area network - + + Play official network game + + + + Play a game on an official server - + Read about who is behind the Hedgewars Project - + + Feedback + + + + Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars - + Downloadable Content - + Access the user created content downloadable from our website - + Exit game - + Manage videos recorded from game - + Edit game preferences @@ -1073,22 +1162,39 @@ PageNetGame - + + Update + 更新 + + + + Room controls + + + + Edit game preferences - Control - Ctrl - - - + Ctrl + + + Start 开始 + PageNetServer + + + Insert your address here + + + + PageOptions @@ -1318,49 +1424,62 @@ PageRoomsList - - Room Name: - - - - + + Search for a room: + + + + + Create room + + + + + Join room + + + + + Room state + + + + Rules: - + Weapons: - - Search: - - - - + + Clear filters + + + + + Open server administration page + + + Create - 建立 - - - + 建立 + + Join - 加入 - - - - Clear - + 加入 - + %1 players online - + Admin features 管理员功能 @@ -1647,62 +1766,76 @@ QAction - + Kick - Update - 更新 - - - + 更新 + + + Restrict Joins 限制参与 - + Restrict Team Additions 限制团队插件 - + + Restrict Unregistered Players Join + + + + Info 信息 - + Ban 屏蔽 - + Follow - - + + Ignore - - + + Add friend - + Unignore - + Remove friend + + + Show games in lobby + + + + + Show games in-progress + + QCheckBox @@ -1774,7 +1907,7 @@ 记录名称中包含具体时间日期 - + Save password @@ -1898,22 +2031,11 @@ - - - + + Any - - - In lobby - - - - - In progress - - QGroupBox @@ -1933,7 +2055,7 @@ 城堡模式 - + Playing teams 玩家队伍 @@ -2011,39 +2133,43 @@ FPS 上限 + + Revision + + + - This program is distributed under the GNU General Public License v2 - - - - + This program is distributed under the %1 + + + + Server name: 服务器名: - + Server port: 服务器端口: - + Host: 主机: - + Port: 端口: - + Weapons 武器 - Version - 版本 + 版本 @@ -2193,37 +2319,37 @@ - + Your Email - + Summary - + Send system information - + Description - + Type the security code: - - Tip: - - - + Tip: + + + + 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! @@ -2253,12 +2379,12 @@ - + Style - + Scheme @@ -2266,7 +2392,7 @@ QLineEdit - + unnamed 无名 @@ -2289,16 +2415,21 @@ Hedgewars %1 刺猬大作战 %1 + + + -r%1 (%2) + + QMessageBox - + Error 错误 - + Cannot use the ammo '%1'! @@ -2313,70 +2444,82 @@ - + Cannot delete default scheme '%1'! - + Please select a record from the list - + Hedgewars - Nick not registered - + Unable to start server - + Connection to server is lost 服务器连接丢失 - + + Not all players are ready + + + + + Are you sure you want to start this game? +Not all players are ready. + + + + + Hedgewars - Error - + System Information Preview - - + + Failed to generate captcha - + Failed to download captcha - + Please fill out all fields. Email is optional. - - + + Hedgewars - Success - + All file associations have been set - + File association failed. @@ -2404,59 +2547,18 @@ - - - Main - Error - - - - - Cannot create directory %1 - - - - - Failed to open data directory: -%1 - -Please check your installation! - - - - - - TCP - Error - - - - - Unable to start the server: %1. - - - - - Unable to run engine at - - - - - Error code: %1 - - - - - + + Netgame - Error - + Please select a server from the list - - + Please enter room name @@ -2485,23 +2587,22 @@ - - + Room Name - Error - + Please select room from the list - + Room Name - Are you sure? - + The game you are trying to join has started. Do you still want to join the room? @@ -2548,7 +2649,7 @@ - + File error @@ -2559,7 +2660,7 @@ - + Cannot open '%1' for reading @@ -2590,20 +2691,15 @@ - + Hedgewars - Warning - + Hedgewars - Information - - - Hedgewars - - QPushButton @@ -2625,11 +2721,36 @@ 上场! - + + Reset + + + + + Set the default server port for Hedgewars + + + + + Invite your friends to your server in just 1 click! + + + + + 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. + + + + Start 开始 + + Start private server + + + Start server 开始服务端 @@ -2650,8 +2771,7 @@ 指定 - - + default 默认 @@ -2661,12 +2781,12 @@ 重命名 - + OK 确定 - + Cancel 取消 @@ -2742,6 +2862,24 @@ + RoomNamePrompt + + + Enter a name for your room. + + + + + Cancel + 取消 + + + + Create room + + + + RoomsListModel @@ -2817,7 +2955,7 @@ - + Close @@ -2858,6 +2996,28 @@ + TCPBase + + + Unable to start server at %1. + + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + + At least two teams are required to play! + + + + TeamShowWidget @@ -2868,15 +3028,20 @@ ThemePrompt - - Select a theme for this map - - - - + + Search for a theme: + + + + Cancel 取消 + + + Use selected theme + + binds @@ -3606,4 +3771,147 @@ + + server + + + Not room master + + + + + Corrupted hedgehogs info + + + + + too many teams + + + + + too many hedgehogs + + + + + There's already a team with same name in the list + + + + + round in progress + + + + + restricted + + + + + REMOVE_TEAM: no such team + + + + + Not team owner! + + + + + Less than two clans! + + + + + Room with such name already exists + + + + + Nickname already chosen + + + + + Illegal nickname + + + + + Protocol already known + + + + + Bad number + + + + + Nickname is already in use + + + + + No checker rights + + + + + Authentication failed + + + + + 60 seconds cooldown after kick + + + + + kicked + + + + + Ping timeout + + + + + bye + + + + + Illegal room name + + + + + No such room + + + + + Joining restricted + + + + + Registered users only + + + + + You are banned in this room + + + + + Empty config entry + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/hedgewars_zh_TW.ts --- a/share/hedgewars/Data/Locale/hedgewars_zh_TW.ts Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/hedgewars_zh_TW.ts Tue Apr 02 21:00:57 2013 +0200 @@ -2,6 +2,13 @@ + About + + Unknown Compiler + + + + AbstractPage Go back @@ -91,6 +98,22 @@ Send Feedback + + Please give us feedback! + + + + We are always happy about suggestions, ideas, or bug reports. + + + + If you found a bug, you can see if it's already known here (english): + + + + Your email address is optional, but we may want to contact you. + + FreqSpinBox @@ -116,34 +139,63 @@ 修改遊戲設置 - Game Options - - - Game scheme will auto-select a weapon + + Map + 地圖 + + + Game options + + HWApplication - + %1 minutes - - - + + + + + %1 hour - - - + + + + + %1 hours - - - + + + + + %1 day - - - + + + + + %1 days + + + + + + Scheme '%1' not supported + + + + Cannot create directory %1 + 無法創建路徑 %1 + + + Failed to open data directory: +%1 + +Please check your installation! @@ -386,10 +438,6 @@ - Largetunnels - - - Small islands @@ -433,6 +481,10 @@ All files + + Large tunnels + + HWNetServersModel @@ -506,6 +558,21 @@ Login + + To connect to the server, please log in. + +If you don't have an account on www.hedgewars.org, +just enter your nickname. + + + + Nickname: + + + + Password: + + HWUploadVideoDialog @@ -528,14 +595,6 @@ HatPrompt - Select a hat - - - - Filter: - - - Cancel 取消 @@ -543,6 +602,10 @@ Use selected hat + + Search for a hat: + + KB @@ -856,6 +919,18 @@ Play a game on an official server + + Feedback + + + + Play local network game + + + + Play official network game + + PageMultiplayer @@ -872,7 +947,7 @@ PageNetGame Control - 房間管理 + 房間管理 Edit game preferences @@ -882,6 +957,21 @@ Start 開始 + + Update + 更新 + + + Room controls + + + + + PageNetServer + + Insert your address here + + PageOptions @@ -1069,11 +1159,11 @@ PageRoomsList Create - 建立 + 建立 Join - 加入 + 加入 Admin features @@ -1081,7 +1171,7 @@ Room Name: - 房間名: + 房間名: Rules: @@ -1092,12 +1182,8 @@ - Search: - - - Clear - 清除 + 清除 %1 players online @@ -1105,6 +1191,30 @@ + + Search for a room: + + + + Create room + + + + Join room + + + + Room state + + + + Clear filters + + + + Open server administration page + + PageScheme @@ -1377,7 +1487,19 @@ Update - 更新 + 更新 + + + Restrict Unregistered Players Join + + + + Show games in lobby + + + + Show games in-progress + @@ -1478,14 +1600,6 @@ - In lobby - - - - In progress - - - Disabled @@ -1617,7 +1731,7 @@ Version - 版本 + 版本 Initial sound volume @@ -1732,10 +1846,6 @@ - This program is distributed under the GNU General Public License v2 - - - There are videos that are currently being processed. Exiting now will abort them. Do you really want to quit? @@ -1825,6 +1935,14 @@ Type the security code: + + Revision + + + + This program is distributed under the %1 + + QLineEdit @@ -1847,6 +1965,10 @@ Hedgewars %1 刺蝟大作戰 %1 + + -r%1 (%2) + + QMessageBox @@ -1909,35 +2031,12 @@ - Main - Error - - - Cannot create directory %1 - 無法創建路徑 %1 - - - Failed to open data directory: -%1 - -Please check your installation! - - - - TCP - Error - + 無法創建路徑 %1 Unable to start the server: %1. - 無法開始服務端: %1. - - - Unable to run engine at - - - - Error code: %1 - + 無法開始服務端: %1. Video upload - Error @@ -2083,7 +2182,12 @@ - Hedgewars + Not all players are ready + + + + Are you sure you want to start this game? +Not all players are ready. @@ -2189,6 +2293,41 @@ Upload this video to your Youtube account + + Reset + + + + Set the default server port for Hedgewars + + + + Invite your friends to your server in just 1 click! + + + + 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. + + + + Start private server + + + + + RoomNamePrompt + + Enter a name for your room. + + + + Cancel + 取消 + + + Create room + + RoomsListModel @@ -2284,6 +2423,25 @@ + TCPBase + + Unable to start server at %1. + + + + Unable to run engine at %1 +Error code: %2 + + + + + TeamSelWidget + + At least two teams are required to play! + + + + TeamShowWidget %1's team @@ -2293,13 +2451,17 @@ ThemePrompt - Select a theme for this map - - - Cancel 取消 + + Search for a theme: + + + + Use selected theme + + binds @@ -2881,4 +3043,119 @@ + + server + + Not room master + + + + Corrupted hedgehogs info + + + + too many teams + + + + too many hedgehogs + + + + There's already a team with same name in the list + + + + round in progress + + + + restricted + + + + REMOVE_TEAM: no such team + + + + Not team owner! + + + + Less than two clans! + + + + Room with such name already exists + + + + Nickname already chosen + + + + Illegal nickname + + + + Protocol already known + + + + Bad number + + + + Nickname is already in use + + + + No checker rights + + + + Authentication failed + + + + 60 seconds cooldown after kick + + + + kicked + + + + Ping timeout + + + + bye + + + + Illegal room name + + + + No such room + + + + Joining restricted + + + + Registered users only + + + + You are banned in this room + + + + Empty config entry + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/it.lua --- a/share/hedgewars/Data/Locale/it.lua Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/it.lua Tue Apr 02 21:00:57 2013 +0200 @@ -1,81 +1,81 @@ locale = { ["..."] = "...", [":("] = ":(", - ["!!!"] = "!!!", --- ["011101000"] = "", -- A_Classic_Fairytale:dragon --- ["011101001"] = "", -- A_Classic_Fairytale:backstab, A_Classic_Fairytale:dragon, A_Classic_Fairytale:enemy, A_Classic_Fairytale:family, A_Classic_Fairytale:journey, A_Classic_Fairytale:queen, A_Classic_Fairytale:shadow, A_Classic_Fairytale:united --- ["30 minutes later..."] = "", -- A_Classic_Fairytale:shadow --- ["About a month ago, a cyborg came and told us that you're the cannibals!"] = "", -- A_Classic_Fairytale:enemy + ["!!!"] = "!!!", + ["011101000"] = "011101000", + ["011101001"] = "011101001", + ["30 minutes later..."] = "30 minuti più tardi...", + ["About a month ago, a cyborg came and told us that you're the cannibals!"] = "Circa un mese fa, è arrivato un cyborg e ci ha detto che siete voi i cannibali!", ["Accuracy Bonus!"] = "Bonus Precisione!", --- ["Ace"] = "", -- User_Mission_-_RCPlane_Challenge, User_Mission_-_Rope_Knock_Challenge - ["Achievement Unlocked"] = "Archivio Sbloccato", -- User_Mission_-_Bamboo_Thicket, User_Mission_-_That_Sinking_Feeling, Tumbler --- ["A Classic Fairytale"] = "", -- A_Classic_Fairytale:first_blood --- ["???"] = "", -- A_Classic_Fairytale:backstab --- ["Actually, you aren't worthy of life! Take this..."] = "", -- A_Classic_Fairytale:shadow --- ["A cy-what?"] = "", -- A_Classic_Fairytale:enemy --- ["Adventurous"] = "", -- A_Classic_Fairytale:journey --- ["Africa"] = "", -- Continental_supplies + ["Ace"] = "Asso", + ["Achievement Unlocked"] = "Archivio Sbloccato", + ["A Classic Fairytale"] = "Una favola classica", + ["???"] = "???", + ["Actually, you aren't worthy of life! Take this..."] = "In realtà, non siete degni di vivere! Prendete questo...", + ["A cy-what?"] = "Un cy-cosa?", + ["Adventurous"] = "Avventuroso", + ["Africa"] = "Africa", -- ["After Leaks A Lot betrayed his tribe, he joined the cannibals..."] = "", -- A_Classic_Fairytale:first_blood -- ["After the shock caused by the enemy spy, Leaks A Lot and Dense Cloud went hunting to relax."] = "", -- A_Classic_Fairytale:shadow --- ["Again with the 'cannibals' thing!"] = "", -- A_Classic_Fairytale:enemy --- ["a Hedgewars challenge"] = "", -- User_Mission_-_RCPlane_Challenge, User_Mission_-_Rope_Knock_Challenge - ["a Hedgewars mini-game"] = "un mini-gioco di Hedgewars", -- Space_Invasion, The_Specialists - ["Aiming Practice"] = "Pratica la tua mira", --Bazooka, Shotgun, SniperRifle + ["Again with the 'cannibals' thing!"] = "Ancora colla storia dei 'cannibali'!", + ["a Hedgewars challenge"] = "una sfida Hedgewars", + ["a Hedgewars mini-game"] = "un mini-gioco di Hedgewars", + ["Aiming Practice"] = "Pratica la tua mira", -- ["A leap in a leap"] = "", -- A_Classic_Fairytale:first_blood --- ["A little gift from the cyborgs"] = "", -- A_Classic_Fairytale:shadow --- ["All gone...everything!"] = "", -- A_Classic_Fairytale:enemy --- ["All right, we just need to get to the other side of the island!"] = "", -- A_Classic_Fairytale:journey --- ["All walls touched!"] = "", -- WxW + ["A little gift from the cyborgs"] = "Un piccolo regalo dai cyborg", + ["All gone...everything!"] = "E' finito... tutto!", + ["All right, we just need to get to the other side of the island!"] = "Va bene, dobbiamo solo raggiungere l'altro lato dell'isola!", + ["All walls touched!"] = "Tutti i muri toccati!", ["Ammo Depleted!"] = "Munizioni scarse!", ["ammo extended!"] = "Munizioni aggiuntive!", ["Ammo is reset at the end of your turn."] = "Le munizioni si azzeranno alla fine del tuo turno", ["Ammo Maniac!"] = "Maniaco delle munizioni!", ["Ammo"] = "Munizioni", --- ["And how am I alive?!"] = "", -- A_Classic_Fairytale:enemy + ["And how am I alive?!"] = "E com'è che sono vivo?!", -- ["And so happenned that Leaks A Lot failed to complete the challenge! He landed, pressured by shame..."] = "", -- A_Classic_Fairytale:first_blood --- ["And so it began..."] = "", -- A_Classic_Fairytale:first_blood --- ["...and so the cyborgs took over the world..."] = "", -- A_Classic_Fairytale:shadow --- ["And so they discovered that cyborgs weren't invulnerable..."] = "", -- A_Classic_Fairytale:journey + ["And so it began..."] = "E così ebbe inizio...", + ["...and so the cyborgs took over the world..."] = "... e così i cyborg conquistarono il mondo...", + ["And so they discovered that cyborgs weren't invulnerable..."] = "E così scoprirono che i cyborg non erano invulnerabili...", -- ["And where's all the weed?"] = "", -- A_Classic_Fairytale:dragon --- ["And you believed me? Oh, god, that's cute!"] = "", -- A_Classic_Fairytale:journey --- ["Anno 1032: [The explosion will make a strong push ~ wide range, wont affect hogs close to the target]"] = "", -- Continental_supplies --- ["Antarctica"] = "", -- Continental_supplies --- ["Are we there yet?"] = "", -- A_Classic_Fairytale:shadow --- ["Are you accusing me of something?"] = "", -- A_Classic_Fairytale:backstab --- ["Are you saying that many of us have died for your entertainment?"] = "", -- A_Classic_Fairytale:enemy + ["And you believed me? Oh, god, that's cute!"] = "E mi credi? Oddio, che bello!", + ["Anno 1032: [The explosion will make a strong push ~ wide range, wont affect hogs close to the target]"] = "Anno 1032: [L'esplosione genererà un forte colpo a lungo raggio, non influierà sui ricci vicini all'obiettivo]", + ["Antarctica"] = "Antartico", + ["Are we there yet?"] = "Siamo già lì?", + ["Are you accusing me of something?"] = "Mi stai accusando di qualcosa?", + ["Are you saying that many of us have died for your entertainment?"] = "Stai dicendo che molti di noi sono morti per il tuo divertimento?", -- ["Artur Detour"] = "", -- A_Classic_Fairytale:queen --- ["As a reward for your performance, here's some new technology!"] = "", -- A_Classic_Fairytale:dragon + ["As a reward for your performance, here's some new technology!"] = "Come ricompensa per le tue prestazioni, ecco della tecnologia nuova!", -- ["a shoppa minigame"] = "", -- WxW --- ["Asia"] = "", -- Continental_supplies --- ["Assault Team"] = "", -- A_Classic_Fairytale:backstab --- ["As the ammo is sparse, you might want to reuse ropes while mid-air.|"] = "", -- A_Classic_Fairytale:dragon + ["Asia"] = "Asia", + ["Assault Team"] = "Squadra d'assalto", + ["As the ammo is sparse, you might want to reuse ropes while mid-air.|"] = "Siccome ci sono poche munizioni, potreste voler riutilizzare le corde intanto che siete a mezz'aria.|", -- ["As the challenge was completed, Leaks A Lot set foot on the ground..."] = "", -- A_Classic_Fairytale:first_blood --- ["As you can see, there is no way to get on the other side!"] = "", -- A_Classic_Fairytale:dragon --- ["Attack From Rope"] = "", -- WxW --- ["Australia"] = "", -- Continental_supplies + ["As you can see, there is no way to get on the other side!"] = "Come potete vedere, non c'è modo di andare dall'altra parte!", + ["Attack From Rope"] = "Attacco dalla corda", + ["Australia"] = "Australia", ["Available points remaining: "] = "Punti disponibili rimasti: ", -- ["Back Breaker"] = "", -- A_Classic_Fairytale:backstab --- ["Back in the village, after telling the villagers about the threat..."] = "", -- A_Classic_Fairytale:united + ["Back in the village, after telling the villagers about the threat..."] = "Tornati al villaggio, dopo aver detto agli abitanti della minaccia...", ["[Backspace]"] = "[Cancella]", -- ["Backstab"] = "", -- A_Classic_Fairytale:backstab -- ["Bad Team"] = "", -- User_Mission_-_The_Great_Escape - ["Bamboo Thicket"] = "Boschetto di Bambu'", + ["Bamboo Thicket"] = "Boschetto di Bambù", ["Barrel Eater!"] = "Mangiatore di Barili!", ["Barrel Launcher"] = "Lanciatore di Barili", --- ["Baseballbat"] = "", -- Continental_supplies - ["Bat balls at your enemies and|push them into the sea!"] = "Lancia delle palline ai tuoi nemici|e spingili in acqua!", - ["Bat your opponents through the|baskets and out of the map!"] = "Manda (colpendoli) i tuoi nemici|in acqua attraverso i canestri laterali!", - ["Bazooka Training"] = "Addestramento sull'utilizzo del Bazooka", + ["Baseballbat"] = "Mazza da baseball", + ["Bat balls at your enemies and|push them into the sea!"] = "Lancia delle palline ai tuoi nemici|e spingili in acqua!", + ["Bat your opponents through the|baskets and out of the map!"] = "Manda (colpendoli) i tuoi nemici|in acqua attraverso i canestri laterali!", + ["Bazooka Training"] = "Addestramento sull'utilizzo del Bazooka", -- ["Beep Loopers"] = "", -- A_Classic_Fairytale:queen - ["Best laps per team: "] = "Tempo migliore per squadra: ", + ["Best laps per team: "] = "Tempo migliore per squadra: ", ["Best Team Times: "] = "Tempi della squadra migliore: ", --- ["Beware, though! If you are slow, you die!"] = "", -- A_Classic_Fairytale:dragon --- ["Biomechanic Team"] = "", -- A_Classic_Fairytale:family + ["Beware, though! If you are slow, you die!"] = "Attenzione, comunque! Se siete lenti, morirete!", + ["Biomechanic Team"] = "Squadra biomeccanica", -- ["Blender"] = "", -- A_Classic_Fairytale:family -- ["Bloodpie"] = "", -- A_Classic_Fairytale:backstab -- ["Bloodrocutor"] = "", -- A_Classic_Fairytale:shadow -- ["Bloodsucker"] = "", -- A_Classic_Fairytale:shadow - ["Bloody Rookies"] = "Reclute Sanguinose", -- 01#Boot_Camp, User_Mission_-_Dangerous_Ducklings, User_Mission_-_Diver, User_Mission_-_Spooky_Tree + ["Bloody Rookies"] = "Reclute Sanguinose", -- ["Bone Jackson"] = "", -- A_Classic_Fairytale:backstab -- ["Bonely"] = "", -- A_Classic_Fairytale:shadow ["Boom!"] = "Kaboom!", @@ -88,33 +88,33 @@ -- ["Brain Stu"] = "", -- A_Classic_Fairytale:united -- ["Brain Teaser"] = "", -- A_Classic_Fairytale:backstab -- ["Brutal Lily"] = "", -- A_Classic_Fairytale:enemy, A_Classic_Fairytale:epil --- ["Brutus"] = "", -- A_Classic_Fairytale:backstab + ["Brutus"] = "Bruto", ["Build a track and race."] = "Costruisci una pista e corri.", --- ["Bullseye"] = "", -- A_Classic_Fairytale:dragon --- ["But it proved to be no easy task!"] = "", -- A_Classic_Fairytale:dragon --- ["But that's impossible!"] = "", -- A_Classic_Fairytale:backstab --- ["But the ones alive are stronger in their heart!"] = "", -- A_Classic_Fairytale:enemy --- ["But...we died!"] = "", -- A_Classic_Fairytale:backstab --- ["But where can we go?"] = "", -- A_Classic_Fairytale:united --- ["But why would they help us?"] = "", -- A_Classic_Fairytale:backstab --- ["But you're cannibals. It's what you do."] = "", -- A_Classic_Fairytale:enemy --- ["But you said you'd let her go!"] = "", -- A_Classic_Fairytale:journey + ["Bullseye"] = "Bersaglio", -- A_Classic_Fairytale:dragon + ["But it proved to be no easy task!"] = "Ma si è dimostrato essere un compito non facile!", + ["But that's impossible!"] = "Ma è impossibile!", + ["But the ones alive are stronger in their heart!"] = "Ma i vivi sono più forti nel loro cuore!", + ["But...we died!"] = "Ma... siamo morti!", + ["But where can we go?"] = "Ma dove possiamo andare?", + ["But why would they help us?"] = "Ma perché dovrebbero aiutarci?", + ["But you're cannibals. It's what you do."] = "Ma voi siete cannibali. E' quello che fate.", + ["But you said you'd let her go!"] = "Avete detto che l'avreste lasciata andare!", -- ["Call me Beep! Well, 'cause I'm such a nice...person!"] = "", -- A_Classic_Fairytale:family --- ["Cannibals"] = "", -- A_Classic_Fairytale:enemy, A_Classic_Fairytale:epil, A_Classic_Fairytale:first_blood --- ["Cannibal Sentry"] = "", -- A_Classic_Fairytale:journey --- ["Cannibals?! You're the cannibals!"] = "", -- A_Classic_Fairytale:enemy - ["CAPTURE THE FLAG"] = "Cattura la Bandiera", + ["Cannibals"] = "Cannibali", + ["Cannibal Sentry"] = "Sentinella cannibale", + ["Cannibals?! You're the cannibals!"] = "Cannibali? Voi siete i cannibali!", + ["CAPTURE THE FLAG"] = "Cattura la Bandiera", ["Careless"] = "Incauto", -- ["Carol"] = "", -- A_Classic_Fairytale:family --- ["CHALLENGE COMPLETE"] = "", -- User_Mission_-_RCPlane_Challenge + ["CHALLENGE COMPLETE"] = "SFIDA COMPLETATA", ["Change Weapon"] = "Cambia Arma", --- ["Choose your side! If you want to join the strange man, walk up to him.|Otherwise, walk away from him. If you decide to att...nevermind..."] = "", -- A_Classic_Fairytale:shadow + ["Choose your side! If you want to join the strange man, walk up to him.|Otherwise, walk away from him. If you decide to att...nevermind..."] = "Scegli da che parte vuoi stare! Se vuoi stare con quell'uomo strano, vai con lui.|Altrimenti, allontanatene. Se decidi di attacc... niente...", ["Clumsy"] = "Goffo", -- ["Cluster Bomb MASTER!"] = "", -- Basic_Training_-_Cluster_Bomb --- ["Cluster Bomb Training"] = "", -- Basic_Training_-_Cluster_Bomb - ["Codename: Teamwork"] = "Nome in Codice: Lavoro di Squadra", --- ["Collateral Damage"] = "", -- A_Classic_Fairytale:journey --- ["Collateral Damage II"] = "", -- A_Classic_Fairytale:journey + ["Cluster Bomb Training"] = "Addestramento bomba a grappolo", + ["Codename: Teamwork"] = "Nome in Codice: Lavoro di Squadra", + ["Collateral Damage"] = "Danno collaterale", + ["Collateral Damage II"] = "Danno collaterale II", -- ["Collect all the crates, but remember, our time in this life is limited!"] = "", -- A_Classic_Fairytale:first_blood -- ["Collect or destroy all the health crates."] = "", -- User_Mission_-_RCPlane_Challenge -- ["Collect the crate on the right.|Hint: Select the rope, [Up] or [Down] to aim, [Space] to fire, directional keys to move.|Ropes can be fired again in the air!"] = "", -- A_Classic_Fairytale:first_blood @@ -123,29 +123,29 @@ -- ["Compete to use as few planes as possible!"] = "", -- User_Mission_-_RCPlane_Challenge ["Complete the track as fast as you can!"] = "Completa la pista più veloce che puoi!", -- ["COMPLETION TIME"] = "", -- User_Mission_-_Rope_Knock_Challenge --- ["Configuration accepted."] = "", -- WxW --- ["Congratulations"] = "", -- Basic_Training_-_Rope - ["Congratulations!"] = "Complimenti!", + ["Configuration accepted."] = "Configurazione accettata", + ["Congratulations"] = "Complimenti", + ["Congratulations!"] = "Complimenti!", -- ["Congratulations! You needed only half of time|to eliminate all targets."] = "", -- Basic_Training_-_Cluster_Bomb -- ["Congratulations! You've completed the Rope tutorial! |- Tutorial ends in 10 seconds!"] = "", -- Basic_Training_-_Rope - ["Congratulations! You've eliminated all targets|within the allowed time frame."] = "Complimenti! Hai distrutto tutti gli obiettivi|entro il tempo previsto.", --Bazooka, Shotgun, SniperRifle + ["Congratulations! You've eliminated all targets|within the allowed time frame."] = "Complimenti! Hai distrutto tutti gli obiettivi|entro il tempo previsto.", -- ["Continental supplies"] = "", -- Continental_supplies - ["Control pillars to score points."] = "Ottieni il controllo dei pilastri per guadagnare punti.", + ["Control pillars to score points."] = "Ottieni il controllo dei pilastri per guadagnare punti.", -- ["Corporationals"] = "", -- A_Classic_Fairytale:queen -- ["Corpsemonger"] = "", -- A_Classic_Fairytale:shadow --- ["Corpse Thrower"] = "", -- A_Classic_Fairytale:epil + ["Corpse Thrower"] = "Lanciatore di cadaveri", -- ["Crates Left:"] = "", -- User_Mission_-_RCPlane_Challenge - ["Cybernetic Empire"] = "Impero Cibernetico", --- ["Cyborg. It's what the aliens call themselves."] = "", -- A_Classic_Fairytale:enemy + ["Cybernetic Empire"] = "Impero Cibernetico", + ["Cyborg. It's what the aliens call themselves."] = "Cyborg. E' come gli alieni chiamano loro stessi.", -- ["Dahmer"] = "", -- A_Classic_Fairytale:backstab - ["DAMMIT, ROOKIE!"] = "ACCIDENTI, RECLUTA!", - ["DAMMIT, ROOKIE! GET OFF MY HEAD!"] = "MALEDIZIONE, RECLUTA! VIA DALLA MIA TESTA!", - ["Dangerous Ducklings"] = "Anatroccoli Pericolosi", + ["DAMMIT, ROOKIE!"] = "ACCIDENTI, RECLUTA!", + ["DAMMIT, ROOKIE! GET OFF MY HEAD!"] = "MALEDIZIONE, RECLUTA! VIA DALLA MIA TESTA!", + ["Dangerous Ducklings"] = "Anatroccoli Pericolosi", ["Deadweight"] = "Peso morto", --- ["Defeat the cannibals"] = "", -- A_Classic_Fairytale:backstab --- ["Defeat the cannibals!|"] = "", -- A_Classic_Fairytale:united + ["Defeat the cannibals"] = "Sconfiggi i cannibali", + ["Defeat the cannibals!|"] = "Sconfiggi i cannibali!|", -- ["Defeat the cannibals!|Grenade hint: set the timer with [1-5], aim with [Up]/[Down] and hold [Space] to set power"] = "", -- A_Classic_Fairytale:shadow --- ["Defeat the cyborgs!"] = "", -- A_Classic_Fairytale:enemy + ["Defeat the cyborgs!"] = "Sconfiggi i cyborg!", -- ["Defend yourself!|Hint: You can get tips on using weapons by moving your mouse over them in the weapon selection menu"] = "", -- A_Classic_Fairytale:shadow ["Demolition is fun!"] = "Demolire è divertente!", -- ["Dense Cloud"] = "", -- A_Classic_Fairytale:backstab, A_Classic_Fairytale:dragon, A_Classic_Fairytale:enemy, A_Classic_Fairytale:epil, A_Classic_Fairytale:family, A_Classic_Fairytale:journey, A_Classic_Fairytale:queen, A_Classic_Fairytale:shadow, A_Classic_Fairytale:united @@ -155,19 +155,19 @@ ["Destroy invaders to score points."] = "Distruggi gli invasori per guadagnare dei punti.", -- ["Destroy the targets!|Hint: Select the Shoryuken and hit [Space]|P.S. You can use it mid-air."] = "", -- A_Classic_Fairytale:first_blood -- ["Destroy the targets!|Hint: [Up], [Down] to aim, [Space] to shoot"] = "", -- A_Classic_Fairytale:first_blood --- ["Did anyone follow you?"] = "", -- A_Classic_Fairytale:united --- ["Did you see him coming?"] = "", -- A_Classic_Fairytale:shadow --- ["Did you warn the village?"] = "", -- A_Classic_Fairytale:shadow --- ["Die, die, die!"] = "", -- A_Classic_Fairytale:dragon + ["Did anyone follow you?"] = "Ti ha seguito qualcuno?", + ["Did you see him coming?"] = "L'hai visto arrivare?", + ["Did you warn the village?"] = "Hai avvisato il villaggio?", + ["Die, die, die!"] = "Muori, muori, muori!", -- ["Disguise as a Rockhopper Penguin: [Swap place with a random enemy hog in the circle]"] = "", -- Continental_supplies -- ["Dist: "] = "", -- Space_Invasion --- ["Do not laugh, inexperienced one, for he speaks the truth!"] = "", -- A_Classic_Fairytale:backstab + ["Do not laugh, inexperienced one, for he speaks the truth!"] = "Non ridere, pivello, perché lui dice la verità!", -- ["Do not let his words fool you, young one! He will stab you in the back as soon as you turn away!"] = "", -- A_Classic_Fairytale:first_blood -- ["Do the deed"] = "", -- A_Classic_Fairytale:first_blood ["Double Kill!"] = "Doppia Uccisione!", --- ["DOUBLE KILL"] = "", -- Mutant --- ["Do you have any idea how valuable grass is?"] = "", -- A_Classic_Fairytale:enemy --- ["Do you think you're some kind of god?"] = "", -- A_Classic_Fairytale:enemy + ["DOUBLE KILL"] = "DOPPIA UCCISIONE", + ["Do you have any idea how valuable grass is?"] = "Hai una pallida idea di quanto vale l'erba?", + ["Do you think you're some kind of god?"] = "Pensi di essere un qualche dio?", -- ["Dragon's Lair"] = "", -- A_Classic_Fairytale:dragon -- ["Drills"] = "", -- A_Classic_Fairytale:backstab ["Drone Hunter!"] = "Cacciatore di Droni!", @@ -177,42 +177,42 @@ -- ["Dude, can you see Ramon and Spiky?"] = "", -- A_Classic_Fairytale:journey -- ["Dude, that's so cool!"] = "", -- A_Classic_Fairytale:backstab -- ["Dude, we really need a new shaman..."] = "", -- A_Classic_Fairytale:shadow --- ["Dude, what's this place?!"] = "", -- A_Classic_Fairytale:dragon --- ["Dude, where are we?"] = "", -- A_Classic_Fairytale:backstab + ["Dude, what's this place?!"] = "Ehi, cos'è questo posto?", + ["Dude, where are we?"] = "Ehi, dove siamo?", -- ["Dude, wow! I just had the weirdest high!"] = "", -- A_Classic_Fairytale:backstab --- ["Duration"] = "", -- Continental_supplies + ["Duration"] = "Durata", -- ["Dust storm: [Deals 20 damage to all enemies in the circle]"] = "", -- Continental_supplies ["Each turn you get 1-3 random weapons"] = "In ogni turno hai da 1 a 3 armi casuali", ["Each turn you get one random weapon"] = "In ogno turno hai una sola arma casuale", --- ["Eagle Eye"] = "", -- A_Classic_Fairytale:backstab + ["Eagle Eye"] = "Occhio di falco", -- ["Eagle Eye: [Blink to the impact ~ one shot]"] = "", -- Continental_supplies -- ["Ear Sniffer"] = "", -- A_Classic_Fairytale:backstab, A_Classic_Fairytale:epil -- ["Elderbot"] = "", -- A_Classic_Fairytale:family -- ["Elimate your captor."] = "", -- User_Mission_-_The_Great_Escape - ["Eliminate all enemies"] = "Elimina tutti i nemici", - ["Eliminate all targets before your time runs out.|You have unlimited ammo for this mission."] = "Distruggi tutti gli obiettivi entro il tempo previsto.|Hai armi illimitate per questa missione.", --Bazooka, Shotgun, SniperRifle --- ["Eliminate enemy hogs and take their weapons."] = "", -- Highlander - ["Eliminate Poison before the time runs out"] = "Elimina Veleno prima che il tempo finisca", - ["Eliminate the Blue Team"] = "Elimina la Squadra Blu", - ["Eliminate the enemy before the time runs out"] = "Elimina il nemico prima che il tempo scada", -- User_Mission_-_Bamboo_Thicket, User_Mission_-_Newton_and_the_Hammock + ["Eliminate all enemies"] = "Elimina tutti i nemici", + ["Eliminate all targets before your time runs out.|You have unlimited ammo for this mission."] = "Distruggi tutti gli obiettivi entro il tempo previsto.|Hai armi illimitate per questa missione.", + ["Eliminate enemy hogs and take their weapons."] = "Elimina i ricci nemici e prendi le loro armi", + ["Eliminate Poison before the time runs out"] = "Elimina Veleno prima che il tempo finisca", + ["Eliminate the Blue Team"] = "Elimina la Squadra Blu", + ["Eliminate the enemy before the time runs out"] = "Elimina il nemico prima che il tempo scada", ["Eliminate the enemy hogs to win."] = "Elimina i ricci nemici per vincere.", ["Eliminate the enemy specialists."] = "Elimina tutti i nemici specialisti.", - ["- Eliminate Unit 3378 |- Feeble Resistance must survive"] = "- Elimina l'Unità 3378 |- La Resistenza Finale deve sopravvivere", --- ["Elmo"] = "", -- A_Classic_Fairytale:dragon, A_Classic_Fairytale:family, A_Classic_Fairytale:queen + ["- Eliminate Unit 3378 |- Feeble Resistance must survive"] = "- Elimina l'Unità 3378 |- La Resistenza Finale deve sopravvivere", + ["Elmo"] = "Elmo", ["Energetic Engineer"] = "Ingegnere Energetico", - ["Enjoy the swim..."] = "Spero che tu gradisca una nuotata...", + ["Enjoy the swim..."] = "Spero che tu gradisca una nuotata...", ["[Enter]"] = "[Enter]", --- ["Europe"] = "", -- Continental_supplies + ["Europe"] = "Europa", -- [" ever done to you?!"] = "", -- A_Classic_Fairytale:backstab --- ["Everyone knows this."] = "", -- A_Classic_Fairytale:enemy + ["Everyone knows this."] = "Lo sanno tutti.", -- ["Every single time!"] = "", -- A_Classic_Fairytale:dragon -- ["Everything looks OK..."] = "", -- A_Classic_Fairytale:enemy -- ["Exactly, man! That was my dream."] = "", -- A_Classic_Fairytale:backstab -- ["Eye Chewer"] = "", -- A_Classic_Fairytale:journey -- ["INSANITY"] = "", -- Mutant -- ["Family Reunion"] = "", -- A_Classic_Fairytale:family - ["Fastest lap: "] = "Giro migliore: ", - ["Feeble Resistance"] = "Resistenza Finale", + ["Fastest lap: "] = "Giro migliore: ", + ["Feeble Resistance"] = "Resistenza Finale", -- ["Fell From Grace"] = "", -- A_Classic_Fairytale:backstab, A_Classic_Fairytale:dragon, A_Classic_Fairytale:enemy, A_Classic_Fairytale:epil, A_Classic_Fairytale:family, A_Classic_Fairytale:queen -- ["Fell From Heaven"] = "", -- A_Classic_Fairytale:enemy, A_Classic_Fairytale:epil, A_Classic_Fairytale:family, A_Classic_Fairytale:first_blood, A_Classic_Fairytale:journey, A_Classic_Fairytale:queen -- ["Fell From Heaven is the best! Fell From Heaven is the greatest!"] = "", -- A_Classic_Fairytale:family @@ -222,14 +222,14 @@ -- ["Find your tribe!|Cross the lake!"] = "", -- A_Classic_Fairytale:dragon -- ["Finish your training|Hint: Animations can be skipped with the [Precise] key."] = "", -- A_Classic_Fairytale:first_blood -- ["Fire a mine: [Does what it says ~ Cant be dropped close to an enemy ~ 1 sec]"] = "", -- Continental_supplies - ["Fire"] = "Fuoco", --- ["First aid kits?!"] = "", -- A_Classic_Fairytale:united --- ["First Blood"] = "", -- A_Classic_Fairytale:first_blood + ["Fire"] = "Fuoco", + ["First aid kits?!"] = "Kit di pronto soccorso?!", + ["First Blood"] = "Primo sangue", -- ["FIRST BLOOD MUTATES"] = "", -- Mutant --- ["First Steps"] = "", -- A_Classic_Fairytale:first_blood - ["Flag captured!"] = "Bandiera catturata!", - ["Flag respawned!"] = "Bandiera restituita!", - ["Flag returned!"] = "Bandiera recuperata!", + ["First Steps"] = "Primi passi", + ["Flag captured!"] = "Bandiera catturata!", + ["Flag respawned!"] = "Bandiera restituita!", + ["Flag returned!"] = "Bandiera recuperata!", ["Flags, and their home base will be placed where each team ends their first turn."] = "Le bandiere saranno piazzate nel luogo in cui le squadre finiscono il loro primo turno.", ["Flamer"] = "Incendiario", -- ["Flaming Worm"] = "", -- A_Classic_Fairytale:backstab @@ -241,29 +241,29 @@ ["fuel extended!"] = "carburante aggiuntivo!", ["GAME BEGUN!!!"] = "IL GIOCO E' INIZIATO!!!", ["Game Modifiers: "] = "Modificatori di Gioco: ", - ["GAME OVER!"] = "GAME OVER!", - ["Game Started!"] = "Gioco Iniziato!", + ["GAME OVER!"] = "GAME OVER!", + ["Game Started!"] = "Gioco Iniziato!", -- ["Game? Was this a game to you?!"] = "", -- A_Classic_Fairytale:enemy -- ["GasBomb"] = "", -- Continental_supplies -- ["Gas Gargler"] = "", -- A_Classic_Fairytale:queen -- ["Get Dense Cloud out of the pit!"] = "", -- A_Classic_Fairytale:journey - ["Get on over there and take him out!"] = "Vai fuori da qui ed eliminalo!", + ["Get on over there and take him out!"] = "Vai fuori da qui ed eliminalo!", -- ["Get on the head of the mole"] = "", -- A_Classic_Fairytale:first_blood --- ["Get out of there!"] = "", -- User_Mission_-_The_Great_Escape + ["Get out of there!"] = "Fuori di lì!", -- ["Get that crate!"] = "", -- A_Classic_Fairytale:first_blood -- ["Get the crate on the other side of the island!|"] = "", -- A_Classic_Fairytale:journey -- ["Get to the target using your rope! |Controls: Left & Right to swing the rope - Up & Down to Contract and Expand!"] = "", -- Basic_Training_-_Rope -- ["Get your teammates out of their natural prison and save the princess!|Hint: Drilling holes should solve everything.|Hint: It might be a good idea to place a girder before starting to drill. Just saying.|Hint: All your hedgehogs need to be above the marked height!|Hint: Leaks A Lot needs to get really close to the princess!"] = "", -- A_Classic_Fairytale:family --- ["GG!"] = "", -- User_Mission_-_Rope_Knock_Challenge + ["GG!"] = "GG!", -- ["Gimme Bones"] = "", -- A_Classic_Fairytale:backstab -- ["Glark"] = "", -- A_Classic_Fairytale:shadow ["Goal"] = "Goal", - ["GO! GO! GO!"] = "VAI! VAI! VAI!", - ["Good birdy......"] = "Bell'uccellino......", --- ["Good Dude"] = "", -- User_Mission_-_The_Great_Escape + ["GO! GO! GO!"] = "VAI! VAI! VAI!", + ["Good birdy......"] = "Bell'uccellino......", + ["Good Dude"] = "Bravo ragazzo", -- ["Good idea, they'll never find us there!"] = "", -- A_Classic_Fairytale:united -- ["Good luck...or else!"] = "", -- A_Classic_Fairytale:journey - ["Good luck out there!"] = "Buona fortuna!", + ["Good luck out there!"] = "Buona fortuna!", ["Good so far!"] = "Molto bene finora!", ["Good to go!"] = "Vai!!", -- ["Go on top of the flower"] = "", -- A_Classic_Fairytale:first_blood @@ -276,19 +276,18 @@ -- ["Great work! Now hit it with your Baseball Bat! |Tip: You can change weapon with 'Right Click'!"] = "", -- Basic_Training_-_Rope -- ["Great! You will be contacted soon for assistance."] = "", -- A_Classic_Fairytale:shadow -- ["Green lipstick bullet: [Is poisonous]"] = "", -- Continental_supplies --- ["Greetings, "] = "", -- A_Classic_Fairytale:dragon + ["Greetings, "] = "Saluti, ", -- ["Greetings, cloudy one!"] = "", -- A_Classic_Fairytale:shadow -- ["Grenade Training"] = "", -- Basic_Training_-_Grenade -- ["Grenadiers"] = "", -- Basic_Training_-_Grenade -- ["Guys, do you think there's more of them?"] = "", -- A_Classic_Fairytale:backstab --- ["HAHA!"] = "", -- A_Classic_Fairytale:enemy --- ["Haha!"] = "", -- A_Classic_Fairytale:united - ["Hahahaha!"] = "Hahahaha!", + ["HAHA!"] = "AHAH!", + ["Haha!"] = "Ahah!", + ["Hahahaha!"] = "Ahahahah!", ["Haha, now THAT would be something!"] = "Haha, allora questa pioggia ha DAVVERO qualcosa di strano!", --- ["Hannibal"] = "", -- A_Classic_Fairytale:epil - [" Hapless Hogs left!"] = "Ricci Sfortunati rimanenti!", -- User_Mission_-_That_Sinking_Feeling + ["Hannibal"] = "Annibale", + [" Hapless Hogs left!"] = "Ricci Sfortunati rimanenti!", ["Hapless Hogs"] = "Ricci Sfortunati", - -- [" HAS MUTATED"] = "", -- Mutant -- ["Hatless Jerry"] = "", -- A_Classic_Fairytale:queen -- ["Have no illusions, your tribe is dead, indifferent of your choice."] = "", -- A_Classic_Fairytale:shadow @@ -298,21 +297,21 @@ ["Heavy"] = "Pesante", -- ["Hedge-cogs"] = "", -- A_Classic_Fairytale:enemy -- ["Hedgehog projectile: [fire your hog like a Sticky Bomb]"] = "", -- Continental_supplies - ["Hedgewars-Basketball"] = "Hedgewars-Pallacanestro", - ["Hedgewars-Knockball"] = "Hedgewars-Knockball", --- ["Hedgibal Lecter"] = "", -- A_Classic_Fairytale:backstab + ["Hedgewars-Basketball"] = "Hedgewars-Pallacanestro", + ["Hedgewars-Knockball"] = "Hedgewars-Knockball", + ["Hedgibal Lecter"] = "Riccibal Lecter", ["Heh, it's not that bad."] = "Beh, alla fine non piove così forte.", --- ["Hello again, "] = "", -- A_Classic_Fairytale:family + ["Hello again, "] = "Salve di nuovo, ", -- ["Help me, Leaks!"] = "", -- A_Classic_Fairytale:journey --- ["Help me, please!!!"] = "", -- A_Classic_Fairytale:journey --- ["Help me, please!"] = "", -- A_Classic_Fairytale:journey + ["Help me, please!!!"] = "Aiutami, per favore!!!", + ["Help me, please!"] = "Aiutami, per favore!", -- ["He moves like an eagle in the sky."] = "", -- A_Classic_Fairytale:first_blood -- ["He must be in the village already."] = "", -- A_Classic_Fairytale:journey -- ["Here, let me help you!"] = "", -- A_Classic_Fairytale:backstab -- ["Here, let me help you save her!"] = "", -- A_Classic_Fairytale:family -- ["Here...pick your weapon!"] = "", -- A_Classic_Fairytale:first_blood -- ["Hero Team"] = "", -- User_Mission_-_The_Great_Escape --- ["He's so brave..."] = "", -- A_Classic_Fairytale:first_blood + ["He's so brave..."] = "E' così coraggioso...", -- ["He won't be selling us out anymore!"] = "", -- A_Classic_Fairytale:backstab -- ["Hey, guys!"] = "", -- A_Classic_Fairytale:backstab -- ["Hey guys!"] = "", -- A_Classic_Fairytale:united @@ -323,18 +322,18 @@ -- ["Hint: Select the BlowTorch, aim and press [Fire]. Press [Fire] again to stop.|Don't blow up the crate."] = "", -- A_Classic_Fairytale:journey -- ["Hint: Select the LowGravity and press [Fire]."] = "", -- A_Classic_Fairytale:journey -- ["Hint: you might want to stay out of sight and take all the crates...|"] = "", -- A_Classic_Fairytale:journey --- ["His arms are so strong!"] = "", -- A_Classic_Fairytale:first_blood + ["His arms are so strong!"] = "Le sue braccia sono così forti!", ["Hit Combo!"] = "Hit Combo!", -- ["Hmmm...actually...I didn't either."] = "", -- A_Classic_Fairytale:enemy -- ["Hmmm, I'll have to find some way of moving him off this anti-portal surface..."] = "", -- portal --- ["Hmmm...it's a draw. How unfortunate!"] = "", -- A_Classic_Fairytale:enemy - ["Hmmm..."] = "Mmmmm...", + ["Hmmm...it's a draw. How unfortunate!"] = "Mmm... è un pareggio. Che sfortunato!", + ["Hmmm..."] = "Mmmmm...", -- ["Hmmm...perhaps a little more time will help."] = "", -- A_Classic_Fairytale:first_blood --- ["Hogminator"] = "", -- A_Classic_Fairytale:family --- ["Hogs in sight!"] = "", -- Continental_supplies --- ["HOLY SHYTE!"] = "", -- Mutant + ["Hogminator"] = "Ricc-minator", + ["Hogs in sight!"] = "Ricci in vista!", + ["HOLY SHYTE!"] = "SANTA POLENTA!", -- ["Honest Lee"] = "", -- A_Classic_Fairytale:enemy - ["Hooray!"] = "Hurrà!!!", + ["Hooray!"] = "Hurrà!!!", -- ["Hostage Situation"] = "", -- A_Classic_Fairytale:family -- ["How can I ever repay you for saving my life?"] = "", -- A_Classic_Fairytale:journey -- ["How come in a village full of warriors, it's up to me to save it?"] = "", -- A_Classic_Fairytale:dragon @@ -344,13 +343,13 @@ -- ["However, if you fail to do so, she dies a most violent death! Muahahaha!"] = "", -- A_Classic_Fairytale:journey -- ["However, my mates don't agree with me on letting you go..."] = "", -- A_Classic_Fairytale:dragon -- [" HP"] = "", -- Mutant - ["Hunter"] = "Cacciatore", --Bazooka, Shotgun, SniperRifle + ["Hunter"] = "Cacciatore", -- ["I believe there's more of them."] = "", -- A_Classic_Fairytale:backstab -- ["I can see you have been training diligently."] = "", -- A_Classic_Fairytale:first_blood --- ["I can't believe it worked!"] = "", -- A_Classic_Fairytale:shadow --- ["I can't believe this!"] = "", -- A_Classic_Fairytale:enemy --- ["I can't believe what I'm hearing!"] = "", -- A_Classic_Fairytale:backstab --- ["I can't wait any more, I have to save myself!"] = "", -- A_Classic_Fairytale:shadow + ["I can't believe it worked!"] = "Non posso credere che abbia funzionato!", + ["I can't believe this!"] = "Non posso crederci!", + ["I can't believe what I'm hearing!"] = "Non credo alle mie orecchie!", + ["I can't wait any more, I have to save myself!"] = "Non posso più aspettare, devo salvarmi!", -- ["I could just teleport myself there..."] = "", -- A_Classic_Fairytale:family -- ["I'd better get going myself."] = "", -- A_Classic_Fairytale:journey -- ["I didn't until about a month ago."] = "", -- A_Classic_Fairytale:enemy @@ -365,12 +364,11 @@ -- ["If you decide to help us, though, we will no longer need to find a new governor for the island."] = "", -- A_Classic_Fairytale:shadow -- ["If you get stuck, use your Desert Eagle or restart the mission!|"] = "", -- A_Classic_Fairytale:journey -- ["If you know what I mean..."] = "", -- A_Classic_Fairytale:shadow --- ["If you say so..."] = "", -- A_Classic_Fairytale:shadow - + ["If you say so..."] = "Se lo dici tu...", -- ["I guess you'll have to kill them."] = "", -- A_Classic_Fairytale:dragon -- ["I have come to make you an offering..."] = "", -- A_Classic_Fairytale:shadow -- ["I have no idea where that mole disappeared...Can you see it?"] = "", -- A_Classic_Fairytale:shadow --- ["I have to follow that alien."] = "", -- A_Classic_Fairytale:backstab + ["I have to follow that alien."] = "Devo seguire quell'alieno.", -- ["I have to get back to the village!"] = "", -- A_Classic_Fairytale:shadow -- ["I hope you are prepared for a small challenge, young one."] = "", -- A_Classic_Fairytale:first_blood -- ["I just don't want to sink to your level."] = "", -- A_Classic_Fairytale:backstab @@ -379,45 +377,45 @@ -- ["I'll hold them off while you return to the village!"] = "", -- A_Classic_Fairytale:shadow -- ["Imagine those targets are the wolves that killed your parents! Take your anger out on them!"] = "", -- A_Classic_Fairytale:first_blood -- ["I'm...alive? How? Why?"] = "", -- A_Classic_Fairytale:backstab --- ["I'm a ninja."] = "", -- A_Classic_Fairytale:dragon + ["I'm a ninja."] = "Sono un ninja.", -- ["I marked the place of their arrival. You're welcome!"] = "", -- A_Classic_Fairytale:backstab -- ["I'm certain that this is a misunderstanding, fellow hedgehogs!"] = "", -- A_Classic_Fairytale:first_blood --- ["I mean, none of you ceased to live."] = "", -- A_Classic_Fairytale:enemy --- ["I'm getting old for this!"] = "", -- A_Classic_Fairytale:family --- ["I'm getting thirsty..."] = "", -- A_Classic_Fairytale:family --- ["I'm here to help you rescue her."] = "", -- A_Classic_Fairytale:family --- ["I'm not sure about that!"] = "", -- A_Classic_Fairytale:united + ["I mean, none of you ceased to live."] = "Voglio dire, nessuno di voi ha cessato di vivere.", -- A_Classic_Fairytale:enemy + ["I'm getting old for this!"] = "Sto diventando vecchio per queste cose!", + ["I'm getting thirsty..."] = "Ho sete...", + ["I'm here to help you rescue her."] = "Sono qui per aiutarvi a salvarla.", + ["I'm not sure about that!"] = "Non sono sicuro di quello!", -- ["Impressive...you are still dry as the corpse of a hawk after a week in the desert..."] = "", -- A_Classic_Fairytale:first_blood --- ["I'm so scared!"] = "", -- A_Classic_Fairytale:united --- ["Incredible..."] = "", -- A_Classic_Fairytale:shadow --- ["I need to find the others!"] = "", -- A_Classic_Fairytale:backstab + ["I'm so scared!"] = "Ho tanta paura!", + ["Incredible..."] = "Incredibile...", + ["I need to find the others!"] = "Devo trovare gli altri!", -- ["I need to get to the other side of this island, fast!"] = "", -- A_Classic_Fairytale:journey --- ["I need to move the tribe!"] = "", -- A_Classic_Fairytale:united --- ["I need to prevent their arrival!"] = "", -- A_Classic_Fairytale:backstab --- ["I need to warn the others."] = "", -- A_Classic_Fairytale:backstab + ["I need to move the tribe!"] = "Devo spostare la tribù!", + ["I need to prevent their arrival!"] = "Devo prevenire il loro arrivo!", + ["I need to warn the others."] = "Devo avvisare gli altri.", -- ["In fact, you are the only one that's been acting strangely."] = "", -- A_Classic_Fairytale:backstab -- ["In order to get to the other side, you need to collect the crates first.|"] = "", -- A_Classic_Fairytale:dragon - ["Instructor"] = "Istruttore", -- 01#Boot_Camp, User_Mission_-_Dangerous_Ducklings --- ["Interesting idea, haha!"] = "", -- A_Classic_Fairytale:enemy + ["Instructor"] = "Istruttore", + ["Interesting idea, haha!"] = "Idea interessante, ahah!", -- ["Interesting! Last time you said you killed a cannibal!"] = "", -- A_Classic_Fairytale:backstab -- ["In the meantime, take these and return to your \"friend\"!"] = "", -- A_Classic_Fairytale:shadow ["invaders destroyed"] = "invasori distrutti", --- ["Invasion"] = "", -- A_Classic_Fairytale:united --- ["I saw it with my own eyes!"] = "", -- A_Classic_Fairytale:shadow --- ["I see..."] = "", -- A_Classic_Fairytale:shadow + ["Invasion"] = "Invasione", + ["I saw it with my own eyes!"] = "L'ho visto coi miei occhi!", + ["I see..."] = "Capisco...", -- ["I see you have already taken the leap of faith."] = "", -- A_Classic_Fairytale:first_blood -- ["I see you would like his punishment to be more...personal..."] = "", -- A_Classic_Fairytale:first_blood -- ["I sense another wave of cannibals heading my way!"] = "", -- A_Classic_Fairytale:backstab -- ["I sense another wave of cannibals heading our way!"] = "", -- A_Classic_Fairytale:backstab --- ["I shouldn't have drunk that last pint."] = "", -- A_Classic_Fairytale:dragon --- ["Is this place in my head?"] = "", -- A_Classic_Fairytale:dragon + ["I shouldn't have drunk that last pint."] = "Non avrei dovuto bere l'ultima pinta.", + ["Is this place in my head?"] = "Questo posto è nella mia testa?", -- ["It doesn't matter. I won't let that alien hurt my daughter!"] = "", -- A_Classic_Fairytale:dragon --- ["I think we are safe here."] = "", -- A_Classic_Fairytale:backstab + ["I think we are safe here."] = "Penso che qui siamo al sicuro.", -- ["I thought their shaman died when he tried our medicine!"] = "", -- A_Classic_Fairytale:shadow -- ["It is called 'Hogs of Steel'."] = "", -- A_Classic_Fairytale:enemy --- ["It is time to practice your fighting skills."] = "", -- A_Classic_Fairytale:first_blood --- ["It must be a childhood trauma..."] = "", -- A_Classic_Fairytale:family --- ["It must be the aliens!"] = "", -- A_Classic_Fairytale:backstab + ["It is time to practice your fighting skills."] = "E' ora di mettere in pratica le vostre abilità di combattimento.", + ["It must be a childhood trauma..."] = "Dev'essere un trauma infantile...", + ["It must be the aliens!"] = "Devono essere gli alieni!", -- ["It must be the aliens' deed."] = "", -- A_Classic_Fairytale:backstab -- ["It must be the cyborgs again!"] = "", -- A_Classic_Fairytale:enemy -- ["I told you, I just found them."] = "", -- A_Classic_Fairytale:backstab @@ -425,10 +423,10 @@ -- ["It's always up to women to clear up the mess men created!"] = "", -- A_Classic_Fairytale:dragon -- ["It's a shame, I forgot how to do that!"] = "", -- A_Classic_Fairytale:family -- ["It's impossible to communicate with the spirits without a shaman."] = "", -- A_Classic_Fairytale:shadow --- ["It's over..."] = "", -- A_Classic_Fairytale:shadow + ["It's over..."] = "E' finita...", -- ["It's time you learned that your actions have consequences!"] = "", -- A_Classic_Fairytale:journey -- ["It's worth more than wood!"] = "", -- A_Classic_Fairytale:enemy --- ["It wants our brains!"] = "", -- A_Classic_Fairytale:shadow + ["It wants our brains!"] = "Vuole i nostri cervelli!", -- ["It was not a dream, unwise one!"] = "", -- A_Classic_Fairytale:backstab -- ["I've seen this before. They just appear out of thin air."] = "", -- A_Classic_Fairytale:united -- ["I want to play a game..."] = "", -- A_Classic_Fairytale:journey @@ -437,19 +435,19 @@ -- ["I wonder where Dense Cloud is..."] = "", -- A_Classic_Fairytale:journey, A_Classic_Fairytale:shadow -- ["I wonder why I'm so angry all the time..."] = "", -- A_Classic_Fairytale:family -- ["I won't let you kill her!"] = "", -- A_Classic_Fairytale:journey --- ["Jack"] = "", -- A_Classic_Fairytale:dragon, A_Classic_Fairytale:family, A_Classic_Fairytale:queen --- ["Jeremiah"] = "", -- A_Classic_Fairytale:dragon --- ["John"] = "", -- A_Classic_Fairytale:journey --- ["Judas"] = "", -- A_Classic_Fairytale:backstab + ["Jack"] = "Giacomo", + ["Jeremiah"] = "Geremia", + ["John"] = "Giovanni", + ["Judas"] = "Giuda", ["Jumping is disabled"] = "Il salto è disattivato", -- ["Just kidding, none of you have died!"] = "", -- A_Classic_Fairytale:enemy -- ["Just on a walk."] = "", -- A_Classic_Fairytale:united -- ["Just wait till I get my hands on that trauma! ARGH!"] = "", -- A_Classic_Fairytale:family ["Kamikaze Expert!"] = "Kamikaze Esperto!", ["Keep it up!"] = "Mantienilo al sicuro!", --- ["Kerguelen"] = "", -- Continental_supplies + ["Kerguelen"] = "Kerguelen", ["Killing spree!"] = "Furia Omicida!", --- ["KILL IT!"] = "", -- A_Classic_Fairytale:first_blood + ["KILL IT!"] = "UCCIDILO!", ["KILLS"] = "UCCISIONI", -- ["Kill the aliens!"] = "", -- A_Classic_Fairytale:dragon -- ["Kill the cannibal!"] = "", -- A_Classic_Fairytale:first_blood @@ -473,7 +471,7 @@ -- ["Let them have a taste of my fury!"] = "", -- A_Classic_Fairytale:backstab -- ["Let us help, too!"] = "", -- A_Classic_Fairytale:backstab -- ["Light Cannfantry"] = "", -- A_Classic_Fairytale:united - ["Listen up, maggot!!"] = "Recluta, Attenzione!!", + ["Listen up, maggot!!"] = "Recluta, Attenzione!!", -- ["Little did they know that this hunt will mark them forever..."] = "", -- A_Classic_Fairytale:shadow ["Lively Lifeguard"] = "Bagnino Vivace", -- ["Lonely Cries: [Rise the water if no hog is in the circle and deal 1 damage to all hogs]"] = "", -- Continental_supplies @@ -488,13 +486,13 @@ -- ["MEGA KILL"] = "", -- Mutant -- ["Meiwes"] = "", -- A_Classic_Fairytale:backstab -- ["Mindy"] = "", -- A_Classic_Fairytale:united - ["Mine Deployer"] = "Spintore di Mine", + ["Mine Deployer"] = "Posatore di Mine", ["Mine Eater!"] = "Mangiatore di Mine!", - ["|- Mines Time:"] = "|- Timer delle mine:", -- User_Mission_-_Diver, User_Mission_-_Spooky_Tree, User_Mission_-_Teamwork - ["MISSION FAILED"] = "MISSIONE FALLITA", -- User_Mission_-_Dangerous_Ducklings, User_Mission_-_Diver, User_Mission_-_Spooky_Tree, User_Mission_-_Teamwork - ["MISSION SUCCESSFUL"] = "MISSIONE COMPLETATA CON SUCCESSO", -- User_Mission_-_Spooky_Tree, User_Mission_-_Teamwork - ["MISSION SUCCESS"] = "MISSIONE COMPLETATA", -- User_Mission_-_Diver, User_Mission_-_Spooky_Tree, User_Mission_-_Teamwork --- ["Molotov"] = "", -- Continental_supplies + ["|- Mines Time:"] = "|- Timer delle mine:", + ["MISSION FAILED"] = "MISSIONE FALLITA", + ["MISSION SUCCESSFUL"] = "MISSIONE COMPLETATA CON SUCCESSO", + ["MISSION SUCCESS"] = "MISSIONE COMPLETATA", + ["Molotov"] = "Molotov", -- ["MONSTER KILL"] = "", -- Mutant -- ["More Natives"] = "", -- A_Classic_Fairytale:epil ["Movement: [Up], [Down], [Left], [Right]"] = "Movimenti: [Su], [Giù], [Sinistra], [Destra]", @@ -510,7 +508,7 @@ -- ["Natives"] = "", -- A_Classic_Fairytale:backstab, A_Classic_Fairytale:dragon, A_Classic_Fairytale:enemy, A_Classic_Fairytale:epil, A_Classic_Fairytale:family, A_Classic_Fairytale:first_blood, A_Classic_Fairytale:journey, A_Classic_Fairytale:queen, A_Classic_Fairytale:shadow, A_Classic_Fairytale:united ["New Barrels Per Turn"] = "Nuovi Barili ad Ogni Turno", ["NEW CLAN RECORD: "] = "NUOVO RECORD DEL CLAN: ", - ["NEW fastest lap: "] = "Nuovo giro migliore: ", + ["NEW fastest lap: "] = "Nuovo giro migliore: ", ["New Mines Per Turn"] = "Nuove Mine ad Ogni Turno", ["NEW RACE RECORD: "] = "NUOVO RACE RECORD: ", ["Newton's Hammock"] = "Newton e l'Amaca", @@ -529,7 +527,7 @@ -- ["Not all hogs are born equal."] = "", -- Highlander ["NOT ENOUGH WAYPOINTS"] = "NON CI SONO ABBASTANZA PUNTI!", -- ["Not now, Fiery Water!"] = "", -- A_Classic_Fairytale:backstab - ["Not So Friendly Match"] = "Partita (quasi) amichevole", -- Basketball, Knockball + ["Not So Friendly Match"] = "Partita (quasi) amichevole", -- ["Not you again! My head still hurts from last time!"] = "", -- A_Classic_Fairytale:shadow -- ["No, we made sure of that!"] = "", -- A_Classic_Fairytale:united -- ["Now find the next target! |Tip: Normally you lose health by falling down, so be careful!"] = "", -- Basic_Training_-_Rope @@ -543,34 +541,32 @@ -- ["OH, COME ON!"] = "", -- A_Classic_Fairytale:journey -- ["Oh, my!"] = "", -- A_Classic_Fairytale:first_blood -- ["Oh, my! This is even more entertaining than I've expected!"] = "", -- A_Classic_Fairytale:backstab - ["Oh no! Just try again!"] = "Oh no! Prova ancora!", -- User_Mission_-_Diver, User_Mission_-_Spooky_Tree, User_Mission_-_Teamwork + ["Oh no! Just try again!"] = "Oh no! Prova ancora!", -- ["Oh no, not "] = "", -- A_Classic_Fairytale:backstab, A_Classic_Fairytale:united - ["Oh no! Time's up! Just try again."] = "Oh no! Tempo scaduto! Prova ancora!", --Bazooka, Shotgun, SniperRifle + ["Oh no! Time's up! Just try again."] = "Oh no! Tempo scaduto! Prova ancora!", -- ["Oh no! You failed! Just try again."] = "", -- Basic_Training_-_Cluster_Bomb -- ["Oh, silly me! I forgot that I'm the shaman."] = "", -- A_Classic_Fairytale:backstab -- ["Olive"] = "", -- A_Classic_Fairytale:united --- ["Omnivore"] = "", -- A_Classic_Fairytale:first_blood + ["Omnivore"] = "Onnivoro", -- ["Once upon a time, on an island with great natural resources, lived two tribes in heated conflict..."] = "", -- A_Classic_Fairytale:first_blood -- ["ONE HOG PER TEAM! KILLING EXCESS HEDGES"] = "", -- Mutant -- ["One tribe was peaceful, spending their time hunting and training, enjoying the small pleasures of life..."] = "", -- A_Classic_Fairytale:first_blood -- ["Oops...I dropped them."] = "", -- A_Classic_Fairytale:united -- ["Open that crate and we will continue!"] = "", -- A_Classic_Fairytale:first_blood - ["Operation Diver"] = "Operazione Sub", - ["Opposing Team: "] = "Squadra Nemica: ", + ["Operation Diver"] = "Operazione Sub", + ["Opposing Team: "] = "Squadra Nemica: ", -- ["Orlando Boom!"] = "", -- A_Classic_Fairytale:queen -- ["Ouch!"] = "", -- User_Mission_-_Rope_Knock_Challenge -- ["Our tribe, our beautiful island!"] = "", -- A_Classic_Fairytale:enemy -- ["Parachute"] = "", -- Continental_supplies - ["Pathetic Hog #%d"] = "Riccio Patetico #%d", - ["Pathetic Resistance"] = "Resistenza Patetica", -- User_Mission_-_Bamboo_Thicket, User_Mission_-_Newton_and_the_Hammock + ["Pathetic Hog #%d"] = "Riccio Patetico #%d", + ["Pathetic Resistance"] = "Resistenza Patetica", -- ["Perfect! Now try to get the next crate without hurting yourself!"] = "", -- A_Classic_Fairytale:first_blood ["Per-Hog Ammo"] = "Munizioni per Riccio", -- ["- Per team weapons|- 9 weaponschemes|- Unique new weapons| |Select continent first round with the Weapon Menu or by ([switch/tab]=Increase,[precise/left shift]=Decrease) on Skip|Some weapons have a second option. Find them with [switch/tab]"] = "", -- Continental_supplies - -- ["Pfew! That was close!"] = "", -- A_Classic_Fairytale:shadow --- ["Piñata bullet: [Contains some sweet candy!]"] = "", -- Continental_supplies +-- ["Piñata bullet: [Contains some sweet candy!]"] = "Proiettile pentolaccia: [Contiene alcune caramelle deliziose!]", -- Continental_supplies -- ["Pings left:"] = "", -- Space_Invasion - ["Place more waypoints using the 'Air Attack' weapon."] = "Piazza più punti usando l'Attacco Aereo", -- ["Planes Used:"] = "", -- User_Mission_-_RCPlane_Challenge -- ["Planes Used"] = "", -- User_Mission_-_RCPlane_Challenge @@ -579,11 +575,11 @@ -- ["Please place the way-point in the open, within the map boundaries."] = "", -- Racer -- ["Please, stop releasing your \"smoke signals\"!"] = "", -- A_Classic_Fairytale:shadow -- ["Point Blank Combo!"] = "", -- Space_Invasion - ["points"] = "punti", -- Control, Space_Invasion - ["Poison"] = "Veleno", + ["points"] = "punti", + ["Poison"] = "Veleno", -- ["Portal hint: one goes to the destination, and one is the entrance.|"] = "", -- A_Classic_Fairytale:dragon -- ["Portal mission"] = "", -- portal - ["Power Remaining"] = "Potenza Rimasta", + ["Power Remaining"] = "Potenza Rimasta", ["Prepare yourself"] = "Preparati", -- ["Press [Enter] to accept this configuration."] = "", -- WxW -- ["Press [Left] or [Right] to move around, [Enter] to jump"] = "", -- A_Classic_Fairytale:first_blood @@ -602,7 +598,7 @@ -- ["Reinforcements"] = "", -- A_Classic_Fairytale:backstab -- ["Remember: The rope only bend around objects, |if it doesn't hit anything it's always stright!"] = "", -- Basic_Training_-_Rope -- ["Remember this, pathetic animal: when the day comes, you will regret your blind loyalty!"] = "", -- A_Classic_Fairytale:shadow - [" - Return the enemy flag to your base to score | - First team to 3 captures wins | - You may only score when your flag is in your base | - Hogs will drop the flag if killed, or drowned | - Dropped flags may be returned or recaptured | - Hogs respawn when killed"] = " - Riporta la bandiera nemica alla tua base per guadagnare un punto| - La prima squadra a catturarne 3 vince! | - Puoi guadagnare punti solo quando la tua bandiera si trova nella tua base! | - I ricci lasceranno cadere la bandiera se uccisi o caduti in acqua! | - Le bandiere cadute possono essere restituite o ricatturate! | - I ricci risorgono dalla morte!", + [" - Return the enemy flag to your base to score | - First team to 3 captures wins | - You may only score when your flag is in your base | - Hogs will drop the flag if killed, or drowned | - Dropped flags may be returned or recaptured | - Hogs respawn when killed"] = " - Riporta la bandiera nemica alla tua base per guadagnare un punto| - La prima squadra a catturarne 3 vince! | - Puoi guadagnare punti solo quando la tua bandiera si trova nella tua base! | - I ricci lasceranno cadere la bandiera se uccisi o caduti in acqua! | - Le bandiere cadute possono essere restituite o ricatturate! | - I ricci risorgono dalla morte!", -- ["Return to Leaks A Lot! If you get stuck, press [Precise] to try again!"] = "", -- A_Classic_Fairytale:shadow -- ["Righteous Beard"] = "", -- A_Classic_Fairytale:backstab, A_Classic_Fairytale:dragon, A_Classic_Fairytale:enemy, A_Classic_Fairytale:epil, A_Classic_Fairytale:family, A_Classic_Fairytale:first_blood, A_Classic_Fairytale:queen, A_Classic_Fairytale:united -- ["ROPE-KNOCKING"] = "", -- User_Mission_-_Rope_Knock_Challenge @@ -612,7 +608,7 @@ ["Round Limit"] = "Limite del Round", ["Rounds Complete: "] = "Round Completati: ", ["Rounds Complete"] = "Round Completati", - ["RULES OF THE GAME [Press ESC to view]"] = "REGOLE DEL GIOCO (Premi ESC per visualizzarle)", + ["RULES OF THE GAME [Press ESC to view]"] = "REGOLE DEL GIOCO (Premi ESC per visualizzarle)", -- ["Rusty Joe"] = "", -- A_Classic_Fairytale:queen -- ["Sabotage: [Sabotage all hogs in the circle and deal ~10 dmg]"] = "", -- Continental_supplies -- ["Salivaslurper"] = "", -- A_Classic_Fairytale:united @@ -627,11 +623,11 @@ -- ["Score"] = "", -- Mutant ["SCORE"] = "PUNTEGGIO", -- ["Scream from a Walrus: [Deal 20 damage + 10% of your hogs health to all hogs around you and get half back]"] = "", -- Continental_supplies - ["sec"] = "sec", -- CTF_Blizzard, TrophyRace, Basic_Training_-_Bazooka, Basic_Training_-_Shotgun, Basic_Training_-_Sniper_Rifle, User_Mission_-_Diver, User_Mission_-_Spooky_Tree, User_Mission_-_Teamwork, Capture_the_Flag + ["sec"] = "sec", -- ["Seduction"] = "", -- Continental_supplies -- ["Seems like every time you take a \"walk\", the enemy find us!"] = "", -- A_Classic_Fairytale:backstab -- ["See that crate farther on the right?"] = "", -- A_Classic_Fairytale:first_blood - ["See ya!"] = "Ci vediamo!", + ["See ya!"] = "Ci vediamo!", -- ["Segmentation Paul"] = "", -- A_Classic_Fairytale:dragon -- ["Select continent!"] = "", -- Continental_supplies -- ["Select difficulty: [Left] - easier or [Right] - harder"] = "", -- A_Classic_Fairytale:first_blood @@ -641,20 +637,20 @@ ["Shield boosted! +30 power"] = "Scudo ricaricato! Potenza +30", ["Shield Depleted"] = "Scudo Esaurito", ["Shield is fully recharged!"] = "Lo scudo è stato completamente ricaricato!", - ["Shield Master!"] = "Shield Master!", - ["Shield Miser!"] = "Scudo Piccolo", - ["Shield OFF:"] = "Scudo OFF", - ["Shield ON:"] = "Scudo ON", - ["Shield Seeker!"] = "Cercatore di Scudi", --- ["Shotgun"] = "", -- Continental_supplies - ["Shotgun Team"] = "Squadra Shotgun", - ["Shotgun Training"] = "Addestramento sull'utilizzo del Fucile a Pompa", + ["Shield Master!"] = "Maestro di scudo!", + ["Shield Miser!"] = "Povero scudo!", + ["Shield OFF:"] = "Scudo OFF:", + ["Shield ON:"] = "Scudo ON:", + ["Shield Seeker!"] = "Cercatore di Scudi!", +-- ["Shotgun"] = "", + ["Shotgun Team"] = "Squadra Shotgun", + ["Shotgun Training"] = "Addestramento sull'utilizzo del Fucile a Pompa", ["shots remaining."] = "colpi rimasti.", ["Silly"] = "Stupido", ["Sinky"] = "Affondato", -- ["Sirius Lee"] = "", -- A_Classic_Fairytale:enemy - ["%s is out and Team %d|scored a penalty!| |Score:"] = "%s è fuori dal campo e la squadra %d|prende una penalità!| |Punteggio:", -- Basketball, Knockball - ["%s is out and Team %d|scored a point!| |Score:"] = "%s è fuori dal campo e la squadra %d|guadagna un punto!| |Puntuación:", -- Basketball, Knockball + ["%s is out and Team %d|scored a penalty!| |Score:"] = "%s è fuori dal campo e la squadra %d|prende una penalità!| |Punteggio:", + ["%s is out and Team %d|scored a point!| |Score:"] = "%s è fuori dal campo e la squadra %d|guadagna un punto!| |Puntuación:", -- ["Slippery"] = "", -- A_Classic_Fairytale:journey -- ["Smith 0.97"] = "", -- A_Classic_Fairytale:enemy -- ["Smith 0.98"] = "", -- A_Classic_Fairytale:enemy @@ -664,8 +660,8 @@ -- ["Smith 1.0"] = "", -- A_Classic_Fairytale:enemy -- ["Sniper Rifle"] = "", -- Continental_supplies -- ["Sniper!"] = "", -- Space_Invasion - ["Sniper Training"] = "Addestramento sull'utilizzo del Fucile di Precisione", - ["Sniperz"] = "Cecchini", + ["Sniper Training"] = "Addestramento sull'utilizzo del Fucile di Precisione", + ["Sniperz"] = "Cecchini", -- ["So humiliating..."] = "", -- A_Classic_Fairytale:first_blood -- ["South America"] = "", -- Continental_supplies -- ["So? What will it be?"] = "", -- A_Classic_Fairytale:shadow @@ -674,10 +670,10 @@ -- ["Spiky Cheese"] = "", -- A_Classic_Fairytale:enemy, A_Classic_Fairytale:epil, A_Classic_Fairytale:family, A_Classic_Fairytale:queen, A_Classic_Fairytale:shadow -- ["Spleenlover"] = "", -- A_Classic_Fairytale:united ["Sponge"] = "Spugna", - ["Spooky Tree"] = "Albero Stregato", + ["Spooky Tree"] = "Albero Stregato", ["s|"] = "s|", - ["s"] = "s", -- GaudyRacer, Space_Invasion - ["STATUS UPDATE"] = "STATUS AGGIORNATO", -- GaudyRacer, Space_Invasion + ["s"] = "s", + ["STATUS UPDATE"] = "STATUS AGGIORNATO", -- ["Steel Eye"] = "", -- A_Classic_Fairytale:queen -- ["Step By Step"] = "", -- A_Classic_Fairytale:first_blood -- ["Steve"] = "", -- A_Classic_Fairytale:dragon, A_Classic_Fairytale:family, A_Classic_Fairytale:queen @@ -693,31 +689,31 @@ ["Switched to "] = "Cambiato in", -- ["Syntax Errol"] = "", -- A_Classic_Fairytale:dragon -- ["Talk about mixed signals..."] = "", -- A_Classic_Fairytale:dragon - ["Team %d: "] = "Squadra %d: ", - ["Team Scores"] = "Punteggi della Squadra", -- Control, Space_Invasion + ["Team %d: "] = "Squadra %d: ", + ["Team Scores"] = "Punteggi della Squadra", -- ["Teleport hint: just use the mouse to select the destination!"] = "", -- A_Classic_Fairytale:dragon --- ["Thanks!"] = "", -- A_Classic_Fairytale:family --- ["Thank you, my hero!"] = "", -- A_Classic_Fairytale:family + ["Thanks!"] = "Grazie!", + ["Thank you, my hero!"] = "Grazie, mio eroe!", -- ["Thank you, oh, thank you, Leaks A Lot!"] = "", -- A_Classic_Fairytale:journey -- ["Thank you, oh, thank you, my heroes!"] = "", -- A_Classic_Fairytale:journey -- ["That is, indeed, very weird..."] = "", -- A_Classic_Fairytale:united -- ["That makes it almost invaluable!"] = "", -- A_Classic_Fairytale:enemy -- ["That ought to show them!"] = "", -- A_Classic_Fairytale:backstab --- ["That's for my father!"] = "", -- A_Classic_Fairytale:backstab + ["That's for my father!"] = "Questo è per mio padre!", -- ["That shaman sure knows what he's doing!"] = "", -- A_Classic_Fairytale:shadow ["That Sinking Feeling"] = "Quella Sensazione di Affogare...", -- ["That's not our problem!"] = "", -- A_Classic_Fairytale:enemy -- ["That's typical of you!"] = "", -- A_Classic_Fairytale:family --- ["That was just mean!"] = "", -- A_Classic_Fairytale:backstab, A_Classic_Fairytale:united + ["That was just mean!"] = "E' semplicemente penoso!", ["That was pointless."] = "Era senza senso.", -- ["The answer is...entertaintment. You'll see what I mean."] = "", -- A_Classic_Fairytale:backstab -- ["The anti-portal zone is all over the floor, and I have nothing to kill him...Droping something could hurt him enough to kill him..."] = "", -- portal -- ["The Bull's Eye"] = "", -- A_Classic_Fairytale:first_blood -- ["The caves are well hidden, they won't find us there!"] = "", -- A_Classic_Fairytale:united -- ["The Crate Frenzy"] = "", -- A_Classic_Fairytale:first_blood --- ["The Dilemma"] = "", -- A_Classic_Fairytale:shadow + ["The Dilemma"] = "Il dilemma", -- ["The enemy can't move but it might be a good idea to stay out of sight!|"] = "", -- A_Classic_Fairytale:dragon - ["The enemy is hiding out on yonder ducky!"] = "Il nemico si sta nascondendo dietro a quella papera!", + ["The enemy is hiding out on yonder ducky!"] = "Il nemico si sta nascondendo dietro a quella papera!", -- ["The Enemy Of My Enemy"] = "", -- A_Classic_Fairytale:enemy -- ["The First Blood"] = "", -- A_Classic_Fairytale:first_blood -- ["The First Encounter"] = "", -- A_Classic_Fairytale:shadow @@ -788,15 +784,15 @@ -- ["Torn Muscle"] = "", -- A_Classic_Fairytale:journey -- [" to save the village."] = "", -- A_Classic_Fairytale:dragon -- ["To the caves..."] = "", -- A_Classic_Fairytale:united - ["Toxic Team"] = "Team Velenoso", -- User_Mission_-_Diver, User_Mission_-_Spooky_Tree, User_Mission_-_Teamwork + ["Toxic Team"] = "Team Velenoso", -- User_Mission_-_Diver, User_Mission_-_Spooky_Tree, User_Mission_-_Teamwork ["TRACK COMPLETED"] = "PISTA COMPLETATA", ["TRACK FAILED!"] = "PISTA FALLITA!", --- ["training"] = "", -- portal --- ["Traitors"] = "", -- A_Classic_Fairytale:epil --- ["Tribe"] = "", -- A_Classic_Fairytale:backstab - ["TrophyRace"] = "TrophyRace", + ["training"] = "addestramento", + ["Traitors"] = "Traditori", + ["Tribe"] = "Tribù", + ["TrophyRace"] = "TrophyRace", -- ["Try to protect the chief! You won't lose if he dies, but it is advised that he survives."] = "", -- A_Classic_Fairytale:united - ["T_T"] = "T_T", + ["T_T"] = "T_T", ["Tumbling Time Extended!"] = "Tempo di Caduta Prolungato!", -- ["Turns until Sudden Death: "] = "", -- A_Classic_Fairytale:dragon -- [" turns until Sudden Death! Better hurry!"] = "", -- A_Classic_Fairytale:dragon @@ -809,7 +805,7 @@ -- ["Unexpected Igor"] = "", -- A_Classic_Fairytale:dragon -- ["Unit 0x0007"] = "", -- A_Classic_Fairytale:family -- ["Unit 334a$7%;.*"] = "", -- A_Classic_Fairytale:backstab, A_Classic_Fairytale:dragon, A_Classic_Fairytale:enemy, A_Classic_Fairytale:family, A_Classic_Fairytale:queen, A_Classic_Fairytale:united - ["Unit 3378"] = "Unità 3378", + ["Unit 3378"] = "Unità 3378", ["Unit 835"] = "Unità 835", -- ["United We Stand"] = "", -- A_Classic_Fairytale:united ["Unit"] = "Unità", @@ -825,11 +821,11 @@ -- ["Use the portal gun to get to the next crate, then use the new gun to get to the final destination!|"] = "", -- A_Classic_Fairytale:dragon -- ["Use the rope to get on the head of the mole, young one!"] = "", -- A_Classic_Fairytale:first_blood -- ["Use the rope to knock your enemies to their doom."] = "", -- User_Mission_-_Rope_Knock_Challenge - ["Use your rope to get from start to finish as fast as you can!"] = "Usa la tua corda per raggiungere il traguardo il più velocemente possibile!", + ["Use your rope to get from start to finish as fast as you can!"] = "Usa la tua corda per raggiungere il traguardo il più velocemente possibile!", -- ["Vedgies"] = "", -- A_Classic_Fairytale:journey -- ["Vegan Jack"] = "", -- A_Classic_Fairytale:enemy -- ["Victory!"] = "", -- Basic_Training_-_Rope - ["Victory for the "] = "La vittoria è di ", -- CTF_Blizzard, Capture_the_Flag + ["Victory for the "] = "La vittoria è di ", -- ["Violence is not the answer to your problems!"] = "", -- A_Classic_Fairytale:first_blood -- ["Walls Left"] = "", -- WxW -- ["Walls Required"] = "", -- WxW @@ -854,7 +850,7 @@ -- ["Welcome, Leaks A Lot!"] = "", -- A_Classic_Fairytale:journey ["Well done."] = "Ben fatto.", -- ["We'll give you a problem then!"] = "", -- A_Classic_Fairytale:enemy --- ["We'll spare your life for now!"] = "", -- A_Classic_Fairytale:backstab + ["We'll spare your life for now!"] = "Ti risparmieremo la vita per ora!", -- ["Well, that was a waste of time."] = "", -- A_Classic_Fairytale:dragon -- ["Well, well! Isn't that the cutest thing you've ever seen?"] = "", -- A_Classic_Fairytale:journey -- ["Well, yes. This was a cyborg television show."] = "", -- A_Classic_Fairytale:enemy @@ -863,13 +859,13 @@ -- ["We need to prevent their arrival!"] = "", -- A_Classic_Fairytale:backstab -- ["We need to warn the village."] = "", -- A_Classic_Fairytale:shadow -- ["We should head back to the village now."] = "", -- A_Classic_Fairytale:shadow --- ["We were trying to save her and we got lost."] = "", -- A_Classic_Fairytale:family --- ["We won't let you hurt her!"] = "", -- A_Classic_Fairytale:journey + ["We were trying to save her and we got lost."] = "Stavamo cercando di salvarla e ci siamo persi.", + ["We won't let you hurt her!"] = "Non vi lasceremo farle del male!", -- ["What?! A cannibal? Here? There is no time to waste! Come, you are prepared."] = "", -- A_Classic_Fairytale:first_blood -- ["What a douche!"] = "", -- A_Classic_Fairytale:enemy --- ["What am I gonna...eat, yo?"] = "", -- A_Classic_Fairytale:family --- ["What are you doing at a distance so great, young one?"] = "", -- A_Classic_Fairytale:first_blood --- ["What are you doing? Let her go!"] = "", -- A_Classic_Fairytale:journey + ["What am I gonna...eat, yo?"] = "Cosa mengerò... te?", + ["What are you doing at a distance so great, young one?"] = "Cosa state facendo a questa enorme distanza, voi?", + ["What are you doing? Let her go!"] = "Cosa state facendo? Lasciatela andare!", -- ["What a ride!"] = "", -- A_Classic_Fairytale:shadow -- ["What a strange cave!"] = "", -- A_Classic_Fairytale:dragon -- ["What a strange feeling!"] = "", -- A_Classic_Fairytale:backstab @@ -878,64 +874,64 @@ -- [" What !! For all of this struggle i just win some ... TIME o0"] = "", -- portal -- ["What has "] = "", -- A_Classic_Fairytale:backstab -- ["What? Here? How did they find us?!"] = "", -- A_Classic_Fairytale:backstab --- ["What is this place?"] = "", -- A_Classic_Fairytale:dragon, A_Classic_Fairytale:enemy + ["What is this place?"] = "Cos'è questo posto?", -- ["What shall we do with the traitor?"] = "", -- A_Classic_Fairytale:backstab -- ["WHAT?! You're the ones attacking us!"] = "", -- A_Classic_Fairytale:enemy -- ["When?"] = "", -- A_Classic_Fairytale:enemy -- ["When I find it..."] = "", -- A_Classic_Fairytale:dragon -- ["Where are all these crates coming from?!"] = "", -- A_Classic_Fairytale:shadow --- ["Where are they?!"] = "", -- A_Classic_Fairytale:backstab --- ["Where did that alien run?"] = "", -- A_Classic_Fairytale:dragon --- ["Where did you get the exploding apples?"] = "", -- A_Classic_Fairytale:shadow + ["Where are they?!"] = "Dove sono loro?!", + ["Where did that alien run?"] = "Dov'è corso quell'alieno?", + ["Where did you get the exploding apples?"] = "Dove avete preso le mele explosive?", -- ["Where did you get the exploding apples and the magic bow that shoots many arrows?"] = "", -- A_Classic_Fairytale:shadow -- ["Where did you get the magic bow that shoots many arrows?"] = "", -- A_Classic_Fairytale:shadow -- ["Where did you get the weapons in the forest, Dense Cloud?"] = "", -- A_Classic_Fairytale:backstab --- ["Where do you get that?!"] = "", -- A_Classic_Fairytale:enemy --- ["Where have you been?!"] = "", -- A_Classic_Fairytale:backstab --- ["Where have you been?"] = "", -- A_Classic_Fairytale:united --- ["? Why?"] = "", -- A_Classic_Fairytale:backstab --- ["Why "] = "", -- A_Classic_Fairytale:backstab --- ["! Why?!"] = "", -- A_Classic_Fairytale:backstab, A_Classic_Fairytale:united --- ["Why are you doing this?"] = "", -- A_Classic_Fairytale:journey --- ["Why are you helping us, uhm...?"] = "", -- A_Classic_Fairytale:family + ["Where do you get that?!"] = "Dove avete preso quello?!", + ["Where have you been?!"] = "Dove siete stati?!", + ["Where have you been?"] = "Dove siete stati?", + ["? Why?"] = "? Perché?", + ["Why "] = "Perché ", + ["! Why?!"] = "! Perché?!", + ["Why are you doing this?"] = "Perché stai facendo questo?", + ["Why are you helping us, uhm...?"] = "Perché ci stai aiutando, mmm...?", -- ["Why can't he just let her go?!"] = "", -- A_Classic_Fairytale:family -- ["Why do men keep hurting me?"] = "", -- A_Classic_Fairytale:first_blood --- ["Why do you not like me?"] = "", -- A_Classic_Fairytale:shadow + ["Why do you not like me?"] = "Perché non ti piaccio?", -- ["Why do you want to take over our island?"] = "", -- A_Classic_Fairytale:enemy --- ["Why me?!"] = "", -- A_Classic_Fairytale:backstab + ["Why me?!"] = "Perché io?!", -- ["Why would they do this?"] = "", -- A_Classic_Fairytale:backstab -- ["- Will Get 1-3 random weapons"] = "", -- Continental_supplies -- ["- Will refresh Parachute each turn."] = "", -- Continental_supplies -- ["- Will refresh portalgun each turn."] = "", -- Continental_supplies ["Will this ever end?"] = "Finirà mai?", --- ["WINNER IS "] = "", -- Mutant + ["WINNER IS "] = "IL VINCITORE E' ", ["WINNING TIME: "] = "TEMPO VINCENTE: ", -- ["Wise Oak"] = "", -- A_Classic_Fairytale:backstab, A_Classic_Fairytale:dragon, A_Classic_Fairytale:enemy, A_Classic_Fairytale:epil, A_Classic_Fairytale:family, A_Classic_Fairytale:queen -- ["With Dense Cloud on the land of shadows, I'm the village's only hope..."] = "", -- A_Classic_Fairytale:journey -- ["With the rest of the tribe gone, it was up to "] = "", -- A_Classic_Fairytale:dragon -- ["Worry not, for it is a peaceful animal! There is no reason to be afraid..."] = "", -- A_Classic_Fairytale:first_blood --- ["Wow, what a dream!"] = "", -- A_Classic_Fairytale:backstab --- ["Y3K1337"] = "", -- A_Classic_Fairytale:journey, A_Classic_Fairytale:shadow --- ["Yay, we won!"] = "", -- A_Classic_Fairytale:enemy --- ["Y Chwiliad"] = "", -- A_Classic_Fairytale:dragon + ["Wow, what a dream!"] = "Wow, che sogno!", + ["Y3K1337"] = "Y3K1337", -- A_Classic_Fairytale:journey, A_Classic_Fairytale:shadow + ["Yay, we won!"] = "Sì, abbiamo vinto!", + ["Y Chwiliad"] = "Y Cwhiliad", -- A_Classic_Fairytale:dragon -- ["Yeah...I think it's a 'he', lol."] = "", -- A_Classic_Fairytale:shadow --- ["Yeah, sure! I died. Hillarious!"] = "", -- A_Classic_Fairytale:backstab --- ["Yeah, take that!"] = "", -- A_Classic_Fairytale:dragon --- ["Yeah? Watcha gonna do? Cry?"] = "", -- A_Classic_Fairytale:journey --- ["Yes!"] = "", -- A_Classic_Fairytale:enemy --- ["Yes, yeees! You are now ready to enter the real world!"] = "", -- A_Classic_Fairytale:first_blood --- ["Yo, dude, we're here, too!"] = "", -- A_Classic_Fairytale:family + ["Yeah, sure! I died. Hillarious!"] = "Sì, davvero! Sono morto! Divertente!", -- A_Classic_Fairytale:backstab + ["Yeah, take that!"] = "Sì, prendilo!", -- A_Classic_Fairytale:dragon + ["Yeah? Watcha gonna do? Cry?"] = "Sì? Cosa pensate di fare? Piangere?", -- A_Classic_Fairytale:journey + ["Yes!"] = "Sì!", + ["Yes, yeees! You are now ready to enter the real world!"] = "S^, sìì! Ora siete pronti per entrare nel mondo reale!", + ["Yo, dude, we're here, too!"] = "Ehi, tu, ci siamo anche noi, qui!", -- ["You are given the chance to turn your life around..."] = "", -- A_Classic_Fairytale:shadow -- ["You are playing with our lives here!"] = "", -- A_Classic_Fairytale:enemy --- ["! You bastards!"] = "", -- A_Classic_Fairytale:backstab, A_Classic_Fairytale:united + ["! You bastards!"] = "! Bastardi!", -- ["You bear impressive skills, "] = "", -- A_Classic_Fairytale:dragon -- ["You can't fire a portal on the blue surface"] = "", -- portal -- ["You couldn't possibly believe that after refusing my offer I'd just let you go!"] = "", -- A_Classic_Fairytale:journey ["You'd almost swear the water was rising!"] = "Guarda, l'acqua si sta alzando rapidamente!", -- ["You'd better watch your steps..."] = "", -- A_Classic_Fairytale:journey --- ["You did not make it in time, try again!"] = "", -- Basic_Training_-_Rope + ["You did not make it in time, try again!"] = "Non hai fatto in tempo, prova ancora!", -- ["You have 7 turns until the next wave arrives.|Make sure the arriving cannibals are greeted appropriately!|If the hog dies, the cause is lost.|Hint: you might want to use some mines..."] = "", -- A_Classic_Fairytale:backstab --- ["You have "] = "", -- A_Classic_Fairytale:dragon + ["You have "] = "Hai ", -- ["You have been giving us out to the enemy, haven't you!"] = "", -- A_Classic_Fairytale:backstab -- ["You have been respawned, at your last checkpoint!"] = "", -- Basic_Training_-_Rope -- ["You have been respawned, be more carefull next time!"] = "", -- Basic_Training_-_Rope @@ -947,8 +943,8 @@ -- ["You have killed an innocent hedgehog!"] = "", -- A_Classic_Fairytale:backstab -- ["You have proven yourself worthy to see our most ancient secret!"] = "", -- A_Classic_Fairytale:first_blood -- ["You have proven yourselves worthy!"] = "", -- A_Classic_Fairytale:enemy - ["You have SCORED!!"] = "Hai guadagnato un PUNTO!!", --- ["You have to destroy 12 targets in 180 seconds"] = "", -- Basic_Training_-_Cluster_Bomb + ["You have SCORED!!"] = "Hai guadagnato un PUNTO!!", + ["You have to destroy 12 targets in 180 seconds"] = "Devi distruggere 12 bersagli in 180 secondi", -- ["You have won the game by proving true cooperative skills!"] = "", -- A_Classic_Fairytale:enemy -- ["You just appeared out of thin air!"] = "", -- A_Classic_Fairytale:backstab -- ["You just committed suicide..."] = "", -- A_Classic_Fairytale:shadow @@ -956,30 +952,30 @@ -- ["You know...taking a stroll."] = "", -- A_Classic_Fairytale:backstab -- ["You know what? I don't even regret anything!"] = "", -- A_Classic_Fairytale:backstab -- ["You'll see what I mean!"] = "", -- A_Classic_Fairytale:enemy --- ["You may only attack from a rope!"] = "", -- WxW + ["You may only attack from a rope!"] = "Puoi attaccare solo da una corda!", -- ["You meatbags are pretty slow, you know!"] = "", -- A_Classic_Fairytale:enemy -- ["You might want to find a way to instantly kill arriving cannibals!"] = "", -- A_Classic_Fairytale:backstab -- ["Young one, you are telling us that they can instantly change location without a shaman?"] = "", -- A_Classic_Fairytale:united -- ["You probably know what to do next..."] = "", -- A_Classic_Fairytale:first_blood -- ["Your deaths will be avenged, cannibals!"] = "", -- A_Classic_Fairytale:enemy -- ["Your death will not be in vain, Dense Cloud!"] = "", -- A_Classic_Fairytale:shadow --- ["You're...alive!? But we saw you die!"] = "", -- A_Classic_Fairytale:backstab --- ["You're a pathetic liar!"] = "", -- A_Classic_Fairytale:backstab --- ["You're funny!"] = "", -- A_Classic_Fairytale:journey + ["You're...alive!? But we saw you die!"] = "Sei...vivo!? Ma noi ti abbiamo visto morire!", + ["You're a pathetic liar!"] = "Sei un patetico bugiardo!", + ["You're funny!"] = "Sei divertente!", -- ["You're getting pretty good! |Tip: When you shorten you rope you move faster! |and when you lengthen it you move slower"] = "", -- Basic_Training_-_Rope -- ["You're pathetic! You are not worthy of my attention..."] = "", -- A_Classic_Fairytale:shadow -- ["You're probably wondering why I bought you back..."] = "", -- A_Classic_Fairytale:backstab -- ["You're terrorizing the forest...We won't catch anything like this!"] = "", -- A_Classic_Fairytale:shadow --- ["Your hogs must survive!"] = "", -- A_Classic_Fairytale:journey + ["Your hogs must survive!"] = "I vostri ricci devono sopravvivere!", -- ["Your movement skills will be evaluated now."] = "", -- A_Classic_Fairytale:first_blood ["You saved"] = "Hai salvato", -- ["You've been assaulting us, we have been just defending ourselves!"] = "", -- A_Classic_Fairytale:enemy - ["You've failed. Try again."] = "Hai fallito. Prova di nuovo.", - ["You've reached the goal!| |Time: "] = "Hai raggiunto il traguardo!| |Tempo: ", --- ["You will be avenged!"] = "", -- A_Classic_Fairytale:shadow --- ["You won't believe what happened to me!"] = "", -- A_Classic_Fairytale:backstab + ["You've failed. Try again."] = "Hai fallito. Prova di nuovo.", + ["You've reached the goal!| |Time: "] = "Hai raggiunto il traguardo!| |Tempo: ", + ["You will be avenged!"] = "Sarai vendicato!", + ["You won't believe what happened to me!"] = "Non crederete a quello che mi è successo!", -- ["Yuck! I bet they'll keep worshipping her even after I save the village!"] = "", -- A_Classic_Fairytale:family --- ["Zealandia"] = "", -- Continental_supplies - ["'Zooka Team"] = "Squadra 'Zooka", --- ["Zork"] = "", -- A_Classic_Fairytale:dragon, A_Classic_Fairytale:family, A_Classic_Fairytale:queen + ["Zealandia"] = "Zealandia", + ["'Zooka Team"] = "Squadra 'Zooka", + ["Zork"] = "Zork", } diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/it.txt --- a/share/hedgewars/Data/Locale/it.txt Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/it.txt Tue Apr 02 21:00:57 2013 +0200 @@ -54,10 +54,10 @@ 00:51=Palla di Fango 00:52=Nessuna Arma Selezionata 00:53=Macchina Spazio-Temporale -00:54=Attrezzi da Costruzione -00:55=Land Spray -00:56=Congelatore -00:57=Mannarino +; 00:54=Attrezzi da Costruzione +00:54=Terreno Spray +00:55=Congelatore +00:56=Mannarino 01:00=Combattiamo! 01:01=Round in parità diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/ja.txt --- a/share/hedgewars/Data/Locale/ja.txt Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/ja.txt Tue Apr 02 21:00:57 2013 +0200 @@ -54,8 +54,8 @@ 00:51=土地玉 00:52=武器を携えない 00:53=TARDIS -00:54=構造 -00:55=土地スプレー +; 00:54=構造 +00:54=土地スプレー 01:00=ヨシ、ファイト! 01:01=ドロー! @@ -470,62 +470,62 @@ 03:55=ユーティリティ ; Weapon Descriptions (use | as line breaks) -04:00=シンプルな手榴弾を使って敵を攻撃。そのタイマーがゼロに達するとそれが爆発する。1-5:セットグレネードのタイマー攻撃:より多くの電力をスローするようにホールド -04:01=クラスター爆弾を使用して敵を攻撃。そのタイマーがゼロに達すると、それは小さな爆弾に分割されます。1-5:セットグレネードのタイマー攻撃:より多くの電力をスローするようにホールド -04:02=風に影響されるかもしれない弾道発射体を使用して敵を攻撃。攻撃:より多くの電力を使って撮影するホールド -04:03=選択したターゲットにロックされ爆発的な蜂を起動します。その精度を向上させるためにフルパワーを使って撮影しないでください。カーソル:ピックターゲット攻撃:より多くの電力を使って撮影するホールド -04:04=2ショットでショットガンを使って敵を攻撃する。その広がりあなたのおかげで、あなたの対戦相手に危害を直接ヒットする必要はありません。攻撃:シュート(複数回) -04:05=地下に移動!地面に穴を開けると他の領域に到達するを使用しています。攻撃の開始または停止掘り -04:06=退屈?攻撃する方法はありません?あなたの弾薬を保存しますか?問題ありません!ちょうどあなたのターン、臆病者をスキップして!攻撃:戦闘せずにターンをスキップ -04:07=ロープでタイムアウトショットを使用して、巨大な距離を埋める。他の豚またはドロップ手榴弾およびそれらの他の武器にスライドするように勢いを使用しています。攻撃:ドロップ手榴弾または類似の武器:ロープロングジャンプシュートまたは解放 -04:08=狭い通路の右またはそれらの足の下鉱山をドロップすることで、離れてあなたの敵を保つ。あなた自身でそれをトリガする前に撤退してください!攻撃:あなたの足の隣に地雷を削除します。 -04:09=あなたの照準が分からない?4打差までを使用して攻撃するためにデザートイーグルを使用しています。攻撃:シュート(複数回) -04:10=ブルートフォースは常にオプションです。あなたの敵と後退の隣にあるこの古典的な爆発物をドロップします。攻撃:あなたの足の隣にあるドロップダイナマイト -04:11=マップの国境を越えてまたは水の中にそれらをバッティングして敵の豚を取り除く。またはどのようにお友達にいくつかの鉱山をノックでしょうか?攻撃:あなたの前にバットすべてを -04:12=このほとんど致命的な武道技術の力を解き放つに近いと個人的な取得します。攻撃:素晴らしいを実行します。 +04:00=シンプルな手榴弾を使って敵を攻撃。|そのタイマーがゼロに達するとそれが爆発する。|1-5:セットグレネードのタイマー攻撃:より多くの電力をスローするようにホールド +04:01=クラスター爆弾を使用して敵を攻撃。|そのタイマーがゼロに達すると、それは小さな爆弾に分割されます。|1-5:セットグレネードのタイマー攻撃:より多くの電力をスローするようにホールド +04:02=風に影響されるかもしれない弾道発射体を使用して敵を攻撃。|攻撃:より多くの電力を使って撮影するホールド +04:03=選択したターゲットにロックされ爆発的な蜂を起動します。|その精度を向上させるためにフルパワーを使って撮影しないでください。|カーソル:ピックターゲット攻撃:より多くの電力を使って撮影するホールド +04:04=2ショットでショットガンを使って敵を攻撃する。|その広がりあなたのおかげで、あなたの対戦相手に危害を直接ヒットする必要はありません。|攻撃:シュート(複数回) +04:05=地下に移動!|地面に穴を開けると他の領域に到達するを使用しています。|攻撃の開始または停止掘り +04:06=退屈?攻撃する方法はありません?あなたの弾薬を保存しますか?問題ありません!|ちょうどあなたのターン、臆病者をスキップして!|攻撃:戦闘せずにターンをスキップ +04:07=ロープでタイムアウトショットを使用して、巨大な距離を埋める。|他の豚またはドロップ手榴弾およびそれらの他の武器にスライドするように勢いを使用しています。|攻撃:ドロップ手榴弾または類似の武器:ロープロングジャンプシュートまたは解放 +04:08=狭い通路の右またはそれらの足の下鉱山をドロップすることで、離れてあなたの敵を保つ。|あなた自身でそれをトリガする前に撤退してください!|攻撃:あなたの足の隣に地雷を削除します。 +04:09=あなたの照準が分からない?4打差までを使用して攻撃するためにデザートイーグルを使用しています。|攻撃:シュート(複数回) +04:10=ブルートフォースは常にオプションです。|あなたの敵と後退の隣にあるこの古典的な爆発物をドロップします。|攻撃:あなたの足の隣にあるドロップダイナマイト +04:11=マップの国境を越えてまたは水の中にそれらをバッティングして敵の豚を取り除く。|またはどのようにお友達にいくつかの鉱山をノックでしょうか?攻撃:あなたの前にバットすべてを +04:12=このほとんど致命的な武道技術の力を解き放つに近いと個人的な取得します。|攻撃:素晴らしいを実行します。 04:13=UNUSED -04:14=高所恐怖症?優れたパラシュートをつかむ。それはあなたが遠すぎたら落ちる展開と秋のダメージを受けてから豚を保存します。攻撃:ドロップ手榴弾または類似の武器:パラシュートロングジャンプを伸ばし -04:15=爆撃の実行を使用して敵を攻撃する飛行機の中で呼び出します。左右:選択してターゲット領域:攻撃方向のカーソルを決定 -04:16=ターゲットエリアにいくつかの鉱山をドロップするには飛行機の中で呼び出します。左右:選択してターゲット領域:攻撃方向のカーソルを決定 -04:17=避難が必要ですか?あなたがカバー付与固体地面にトンネルを掘るためにブロートーチを使用しています。攻撃の開始または停止掘り -04:18=追加の保護が必要な場合、または地面を通過したいですか?好きなように、いくつかの桁に置きます。有効な位置に配置桁:左右:カーソルを配置する選択桁 -04:19=それはあなたが数秒以内に危険な状況から豚を保存することができますように、右瞬間テレポーテーションで使用するほぼすべての武器をより強力にすることができます。カーソル:選択してターゲット領域 -04:20=別の豚と、現在のターンを再生することができます。攻撃:スイッチング豚を有効にする -04:21=インパクト時に複数の爆弾を解放します手榴弾のような弾丸を撃つ。攻撃:フルパワーで撃つ -04:22=だけでなく、インディジョーンズのために!鞭は多くの状況で有用な武器である。あなたが崖から誰かを突き出すしたい場合は特に。攻撃:あなたの前にストライクのすべて -04:23=あなたが失うものは何もない場合、これはかなり便利かもしれません。彼の方法上のすべてを傷つけると終了時に爆発し、特定の方向に彼を起動することで、豚を生け贄に捧げる。攻撃:壊滅的な、致命的な攻撃を開始 -04:24=誕生日おめでとう!このケーキを起動し、それが右の敵の隣に歩いて、彼らが爆発的パーティを持たせてみましょう。ケーキは、ほぼすべての地形を通過することができますが、彼は以前、この方法を爆発させるかもしれません。攻撃:ケーキを起動するか、停止させると爆発する -04:25=(そして、いくつかのギャップや穴)が豚に向かってジャンプすることがあなたの敵を取得するには、この変装キットを使用しています。攻撃:キットを使用して、別の豚を誘惑しよう -04:26=あなたの敵で、このジューシーなスイカをスローします。タイマーの期限が切れると、それはいくつかの爆発的な断片に分割されます。1-5:セットスイカのタイマー攻撃:より多くの電力を使って撮影するホールド -04:27=この悪魔のよう爆発を使用して、あなたの対戦相手に業火の雨してみましょう。近すぎる小さな火災が長く続くかもしれないと爆発に得ることはありません。攻撃:より多くの電力を使って撮影するホールド -04:28=このロケットを打ち上げた後の短い時間、それは固体地面を掘削を開始し、そのヒューズがトリガされると爆発するか、再び再浮上します。攻撃:より多くの電力を使って撮影するホールド -04:29=これは小さな子供のためのものではありません!ボール銃は爆薬を充填した小さな色のボールのトンを発生させます。攻撃:アップダウン、フルパワーでシュートを目指して進みます -04:30=強力なナパームストライキを起動するには飛行機の中で呼び出します。適切にこの攻撃を目指してそこに座って不運な豚を含む風景の巨大な部分を根絶することができます。左右:選択してターゲット領域:攻撃方向のカーソルを決定 -04:31=RCプレーンは箱を収集したり、遠く離れた豚を攻撃するのに理想的な武器です。どちらの敵にそれを操縦するか、最初のいくつかの爆弾をドロップします。攻撃:ワルキューレが戦闘に乗りましょう左右:平面ステアジャンプ平面またはドロップロング爆弾を起動します。 -04:32=低重力はどんなダイエットよりも効果的です!高く、長い距離を飛び越えたり、敵がさらに飛ぶしましょう。攻撃:アクティブ -04:33=時には、いくつかのより多くのダメージを与えるためにその少し余分なブーストをちょうど必要があります。攻撃:アクティブ -04:34=私に触れることができない!攻撃:アクティブ -04:35=時には時間が早すぎる実行している。あなたの攻撃を完了するために、いくつかの余分な秒をつかむ。攻撃:アクティブ -04:36=さて、時にはあなたが目指すのはあまりにも悪いです。現代の技術を使用していくつかの支援を得る。攻撃:アクティブ -04:37=日光を恐れてはいけません。それはちょうど1ターン持続しますが、あなたが他の豚に何のダメージを吸収することができるようになります。攻撃:アクティブ -04:38=スナイパーライフルは、あなたの全体の兵器庫の中で最も壊滅的な武器になります、しかし、それは接近戦で非常に効果的です。ダメージは、そのターゲットまでの距離とともに増加を与えた。攻撃:シュート(回) -04:39=空飛ぶ円盤を使用してマップの他の部分に飛ぶ。これは、マスターユーティリティのハード戦場のほぼ任意の位置に行くことができるようになりました。攻撃:最大アクティブ左右:ドロップ手榴弾または類似の武器:一方向にロングジャンプ力を適用します。 -04:40=(すぐになる)、燃焼液で満たされたこのボトルを使用して、火災のいくつかの地を設定します。攻撃:より多くの電力を使って撮影するホールド -04:41=証拠の性質も、空飛ぶ円盤を上回るかもしれません。バーディは、豚を持ち歩くとあなたの敵に卵をドロップすることができます!バーディーを使用すると、あなたのターンの時間に食べるように、迅速である!攻撃:およびドロップ卵アップ左右:一方向にフラップ -04:42=この携帯ポータル装置は、瞬時に、あなたの敵、または地形上の2点間のあなたの武器あなたを輸送することが可能です。賢明にそれを使用して、キャンペーンがあります...大成功!攻撃:サイクルポータルの色:ポータルスイッチを撃つ -04:43=あなたの音楽デビュー爆発を成功させる!天からピアノをドロップしますが、注意してください...誰かがそれを再生する必要があり、それはあなたの人生を要するかもしれない!カーソル:選択してターゲット領域F1-F9キーを押して:ピアノを弾く -04:44=これはただのチーズではなく、生物兵器だ!タイマーがゼロに達すると、それは間違いなく臭いをタッチする誰もが不幸に毒されたら、それは被害の膨大な量が発生することはありません!1-5:セットグレネードのタイマー攻撃:より多くの電力をスローするようにホールド -04:45=すべてのそれらの物理学のクラスは最終的に報われている、あなたの敵に壊滅的な正弦波を起動します。気を付けろ、この武器は非常にキックをパックします。(この武器は不完全です)攻撃力:シュート -04:46=液体炎を非常に暑いとあなたの敵をカバーしています。ほのぼの!アタックを上下にアクティブにします。左右を目指して進みます:唾の電源を変更します。 -04:47=2先端のとがった、卑劣な、粘着地雷の楽しみを倍増。連鎖反応を設定するか(あるいは両方!)攻撃を守る:より多くの電力(倍)で撮影するホールド -04:48=なぜモルすべての虐待を取得する必要があります?豚をは、単に楽しみとしてすることができます!このハンマーから良い打撃は豚の健康状態の3分の1をオフに剃るし、それらを地下に突入します。攻撃:アクティブ -04:49=あなたの友人を復活させる!しかし、これはまたあなたの敵を復活させること注意してください。攻撃:ゆっくりと復活させるために押された攻撃に注意してください。復活を加速 -04:50=誰かが地下に隠れている?ドリルのストライキでそれらを掘る!タイマーは、それを掘る方法をはるかに制御します。 -04:51=泥のボールを投げつけることによって自由なショットで取得します。刺されは、ビット、豚をバックノックする。 +04:14=高所恐怖症?優れたパラシュートをつかむ。|それはあなたが遠すぎたら落ちる展開と秋のダメージを受けてから豚を保存します。|攻撃:ドロップ手榴弾または類似の武器:パラシュートロングジャンプを伸ばし +04:15=爆撃の実行を使用して敵を攻撃する飛行機の中で呼び出します。|左右:選択してターゲット領域:攻撃方向のカーソルを決定 +04:16=ターゲットエリアにいくつかの鉱山をドロップするには飛行機の中で呼び出します。|左右:選択してターゲット領域:攻撃方向のカーソルを決定 +04:17=避難が必要ですか?あなたがカバー付与固体地面にトンネルを掘るためにブロートーチを使用しています。|攻撃の開始または停止掘り +04:18=追加の保護が必要な場合、または地面を通過したいですか?好きなように、いくつかの桁に置きます。|有効な位置に配置桁:左右:カーソルを配置する選択桁 +04:19=それはあなたが数秒以内に危険な状況から豚を保存することができますように、右瞬間テレポーテーションで使用するほぼすべての武器をより強力にすることができます。|カーソル:選択してターゲット領域 +04:20=別の豚と、現在のターンを再生することができます。|攻撃:スイッチング豚を有効にする +04:21=インパクト時に複数の爆弾を解放します手榴弾のような弾丸を撃つ。|攻撃:フルパワーで撃つ +04:22=だけでなく、インディジョーンズのために!|鞭は多くの状況で有用な武器である。|あなたが崖から誰かを突き出すしたい場合は特に。|攻撃:あなたの前にストライクのすべて +04:23=あなたが失うものは何もない場合、これはかなり便利かもしれません。|彼の方法上のすべてを傷つけると終了時に爆発し、特定の方向に彼を起動することで、豚を生け贄に捧げる。|攻撃:壊滅的な、致命的な攻撃を開始 +04:24=誕生日おめでとう!|このケーキを起動し、それが右の敵の隣に歩いて、彼らが爆発的パーティを持たせてみましょう。|ケーキは、ほぼすべての地形を通過することができますが、彼は以前、この方法を爆発させるかもしれません。|攻撃:ケーキを起動するか、停止させると爆発する +04:25=(そして、いくつかのギャップや穴)が豚に向かってジャンプすることがあなたの敵を取得するには、この変装キットを使用しています。|攻撃:キットを使用して、別の豚を誘惑しよう +04:26=あなたの敵で、このジューシーなスイカをスローします。|タイマーの期限が切れると、それはいくつかの爆発的な断片に分割されます。|1-5:セットスイカのタイマー攻撃:より多くの電力を使って撮影するホールド +04:27=この悪魔のよう爆発を使用して、あなたの対戦相手に業火の雨してみましょう。|近すぎる小さな火災が長く続くかもしれないと爆発に得ることはありません。|攻撃:より多くの電力を使って撮影するホールド +04:28=このロケットを打ち上げた後の短い時間、それは固体地面を掘削を開始し、そのヒューズがトリガされると爆発するか、再び再浮上します。|攻撃:より多くの電力を使って撮影するホールド +04:29=これは小さな子供のためのものではありません!|ボール銃は爆薬を充填した小さな色のボールのトンを発生させます。|攻撃:アップダウン、フルパワーでシュートを目指して進みます +04:30=強力なナパームストライキを起動するには飛行機の中で呼び出します。|適切にこの攻撃を目指してそこに座って不運な豚を含む風景の巨大な部分を根絶することができます。|左右:選択してターゲット領域:攻撃方向のカーソルを決定 +04:31=RCプレーンは箱を収集したり、遠く離れた豚を攻撃するのに理想的な武器です。|どちらの敵にそれを操縦するか、最初のいくつかの爆弾をドロップします。|攻撃:ワルキューレが戦闘に乗りましょう左右:平面ステアジャンプ平面またはドロップロング爆弾を起動します。 +04:32=低重力はどんなダイエットよりも効果的です!|高く、長い距離を飛び越えたり、敵がさらに飛ぶしましょう。|攻撃:アクティブ +04:33=時には、いくつかのより多くのダメージを与えるためにその少し余分なブーストをちょうど必要があります。|攻撃:アクティブ +04:34=私に触れることができない!|攻撃:アクティブ +04:35=時には時間が早すぎる実行している。|あなたの攻撃を完了するために、いくつかの余分な秒をつかむ。|攻撃:アクティブ +04:36=さて、時にはあなたが目指すのはあまりにも悪いです。|現代の技術を使用していくつかの支援を得る。|攻撃:アクティブ +04:37=日光を恐れてはいけません。|それはちょうど1ターン持続しますが、あなたが他の豚に何のダメージを吸収することができるようになります。|攻撃:アクティブ +04:38=スナイパーライフルは、あなたの全体の兵器庫の中で最も壊滅的な武器になります、しかし、それは接近戦で非常に効果的です。|ダメージは、そのターゲットまでの距離とともに増加を与えた。|攻撃:シュート(回) +04:39=空飛ぶ円盤を使用してマップの他の部分に飛ぶ。|これは、マスターユーティリティのハード戦場のほぼ任意の位置に行くことができるようになりました。|攻撃:最大アクティブ左右:ドロップ手榴弾または類似の武器:一方向にロングジャンプ力を適用します。 +04:40=(すぐになる)、燃焼液で満たされたこのボトルを使用して、火災のいくつかの地を設定します。|攻撃:より多くの電力を使って撮影するホールド +04:41=証拠の性質も、空飛ぶ円盤を上回るかもしれません。|バーディは、豚を持ち歩くとあなたの敵に卵をドロップすることができます!|バーディーを使用すると、あなたのターンの時間に食べるように、迅速である!|攻撃:およびドロップ卵アップ左右:一方向にフラップ +04:42=この携帯ポータル装置は、瞬時に、あなたの敵、または地形上の2点間のあなたの武器あなたを輸送することが可能です。|賢明にそれを使用して、キャンペーンがあります...大成功!|攻撃:サイクルポータルの色:ポータルスイッチを撃つ +04:43=あなたの音楽デビュー爆発を成功させる!|天からピアノをドロップしますが、注意してください...誰かがそれを再生する必要があり、それはあなたの人生を要するかもしれない!|カーソル:選択してターゲット領域F1-F9キーを押して:ピアノを弾く +04:44=これはただのチーズではなく、生物兵器だ!|タイマーがゼロに達すると、それは間違いなく臭いをタッチする誰もが不幸に毒されたら、それは被害の膨大な量が発生することはありません!|1-5:セットグレネードのタイマー攻撃:より多くの電力をスローするようにホールド +04:45=すべてのそれらの物理学のクラスは最終的に報われている、あなたの敵に壊滅的な正弦波を起動します。|気を付けろ、この武器は非常にキックをパックします。|(この武器は不完全です)攻撃力:シュート +04:46=液体炎を非常に暑いとあなたの敵をカバーしています。|ほのぼの!|アタックを上下にアクティブにします。|左右を目指して進みます:唾の電源を変更します。 +04:47=2先端のとがった、卑劣な、粘着地雷の楽しみを倍増。|連鎖反応を設定するか(あるいは両方!|)攻撃を守る:より多くの電力(倍)で撮影するホールド +04:48=なぜモルすべての虐待を取得する必要があります?豚をは、単に楽しみとしてすることができます!|このハンマーから良い打撃は豚の健康状態の3分の1をオフに剃るし、それらを地下に突入します。|攻撃:アクティブ +04:49=あなたの友人を復活させる!|しかし、これはまたあなたの敵を復活させること注意してください。|攻撃:ゆっくりと復活させるために押された攻撃に注意してください。|復活を加速 +04:50=誰かが地下に隠れている?ドリルのストライキでそれらを掘る!|タイマーは、それを掘る方法をはるかに制御します。 +04:51=泥のボールを投げつけることによって自由なショットで取得します。|刺されは、ビット、豚をバックノックする。 04:52=UNUSED -04:53=あなたの仲間が単独で戦うために残しながら、時間と空間を介して冒険に出る。いつでも返すように準備する、または突然死の場合、または、それらはすべて敗北しています。免責事項。あなたは一人である場合は、突然死で機能するか、キングである場合ではありません。 +04:53=あなたの仲間が単独で戦うために残しながら、時間と空間を介して冒険に出る。|いつでも返すように準備する、または突然死の場合、または、それらはすべて敗北しています。|免責事項。|あなたは一人である場合は、突然死で機能するか、キングである場合ではありません。 04:54=INCOMPLETE -04:55=スティッキーフレークのストリームをスプレー。トンネルを封鎖、敵を埋める、ブリッジを構築します。あなたが上の任意のを取得しないように注意してください! +04:55=スティッキーフレークのストリームをスプレー。|トンネルを封鎖、敵を埋める、ブリッジを構築します。|あなたが上の任意のを取得しないように注意してください! ; Game goal strings 05:00=ゲームモード diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/lt.txt --- a/share/hedgewars/Data/Locale/lt.txt Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/lt.txt Tue Apr 02 21:00:57 2013 +0200 @@ -54,8 +54,8 @@ 00:51=Purvo Kamuolys 00:52=Joks Ginklas Nepasirinktas 00:53=TARDIS -00:54=Struktūra -00:55=Žemės Purškimas +; 00:54=Struktūra +00:54=Žemės Purškimas 01:00=Kaukimės! 01:01=Lygiosios diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/missions_it.txt --- a/share/hedgewars/Data/Locale/missions_it.txt Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/missions_it.txt Tue Apr 02 21:00:57 2013 +0200 @@ -4,7 +4,7 @@ Basic_Training_-_Grenade.name=Addestramento base sull'utilizzo delle Granate Basic_Training_-_Grenade.desc="Ricorda, toglierai PRIMA la sicura e POI lancerai la granata!" -Basic_Training_-_Cluster_Bomb.name=ddestramento base sull'utilizzo delle Granate a Grappolo +Basic_Training_-_Cluster_Bomb.name=Addestramento base sull'utilizzo delle Granate a Grappolo Basic_Training_-_Cluster_Bomb.desc="Qualcuno ha bisogno di una doccia (molto) calda!" Basic_Training_-_Shotgun.name=Addestramento base sull'utilizzo del Fucile a Pompa diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/pl.txt --- a/share/hedgewars/Data/Locale/pl.txt Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/pl.txt Tue Apr 02 21:00:57 2013 +0200 @@ -54,10 +54,10 @@ 00:51=Kula błotna 00:52=Nie wybrano broni 00:53=TARDIS -00:54=Budynek -00:55=Miotacz błota -00:56=Zamrażarka -00:57=Tasak +; 00:54=Budynek +00:54=Miotacz błota +00:55=Zamrażarka +00:56=Tasak 01:00=Walczmy! 01:01=Remis diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/pt_BR.txt --- a/share/hedgewars/Data/Locale/pt_BR.txt Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/pt_BR.txt Tue Apr 02 21:00:57 2013 +0200 @@ -54,10 +54,10 @@ 00:51=Bola de Lama 00:52=Arma não selecionada 00:53=Máquina do tempo -00:54=Estrutura -00:55=Spray de terra -00:56=Freezer -00:57=Machadinha +; 00:54=Estrutura +00:54=Spray de terra +00:55=Freezer +00:56=Machadinha 01:00=Hora de lutar! diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/pt_PT.txt --- a/share/hedgewars/Data/Locale/pt_PT.txt Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/pt_PT.txt Tue Apr 02 21:00:57 2013 +0200 @@ -54,10 +54,10 @@ 00:51=Bola de Lama 00:52=Nenhuma arma selecionada 00:53=Caixote do Tempo -00:54=Estrutura -00:55=Terreno-instantâneo -00:56=Congelador -00:57=Cutelo +; 00:54=Estrutura +00:54=Terreno-instantâneo +00:55=Congelador +00:56=Cutelo 01:00=Vamos lutar! 01:01=Ronda empatada diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/ro.txt --- a/share/hedgewars/Data/Locale/ro.txt Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/ro.txt Tue Apr 02 21:00:57 2013 +0200 @@ -54,8 +54,8 @@ 00:51=Bila de noroi 00:52=Nici o armă selectată 00:53=Cutia timpului -00:54=Structură -00:55=Spray de teren +; 00:54=Structură +00:54=Spray de teren 01:00=Hai să ne batem! 01:01=Remizăr diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/ru.txt --- a/share/hedgewars/Data/Locale/ru.txt Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/ru.txt Tue Apr 02 21:00:57 2013 +0200 @@ -54,10 +54,10 @@ 00:51=Комок грязи 00:52=Оружие не выбрано 00:53=Будка времени -00:54=Структура -00:55=Распылитель земли -00:56=Замораживатель -00:57=Секач +; 00:54=Структура +00:54=Распылитель земли +00:55=Замораживатель +00:56=Секач 01:00=Вперёд к победе! 01:01=Ничья diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/sk.txt --- a/share/hedgewars/Data/Locale/sk.txt Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/sk.txt Tue Apr 02 21:00:57 2013 +0200 @@ -54,10 +54,10 @@ 00:51=Blatová guľa 00:52=Žiadna zbraň nie je vybraná 00:53=TARDIS -00:54=Budova -00:55=Postrek zeme -00:56=Zmrazovač -00:57=Sekáčik +; 00:54=Budova +00:54=Postrek zeme +00:55=Zmrazovač +00:56=Sekáčik 01:00=Do boja! 01:01=Remíza diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/sv.txt --- a/share/hedgewars/Data/Locale/sv.txt Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/sv.txt Tue Apr 02 21:00:57 2013 +0200 @@ -54,8 +54,8 @@ 00:51=Jordboll 00:52=Inget vapen valt 00:53=Tidslåda -00:54=Struktur -00:55=Markspruta +; 00:54=Struktur +00:54=Markspruta 01:00=Nu kör vi! 01:01=Oavgjort diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Locale/uk.txt --- a/share/hedgewars/Data/Locale/uk.txt Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Locale/uk.txt Tue Apr 02 21:00:57 2013 +0200 @@ -54,8 +54,8 @@ 00:51=Грудка багна 00:52=Зброя не вибрана 00:53=Будка Часу -00:54=Структура -00:55=Земляний Спрей +; 00:54=Структура +00:54=Земляний Спрей 01:00=Вперед до перемоги! 01:01=Нічия diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Maps/Basketball/desc.txt --- a/share/hedgewars/Data/Maps/Basketball/desc.txt Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Maps/Basketball/desc.txt Tue Apr 02 21:00:57 2013 +0200 @@ -1,1 +1,1 @@ -en_US=Who said hedgehogs can't|play basketball? +en_US=Who said hedgehogs can't play basketball? diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Maps/Control/desc.txt --- a/share/hedgewars/Data/Maps/Control/desc.txt Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Maps/Control/desc.txt Tue Apr 02 21:00:57 2013 +0200 @@ -1,1 +1,1 @@ -en_US=Islands scattered everywhere\, full set of|weapons. +en_US=Islands scattered everywhere\, full set of weapons. diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Maps/Knockball/desc.txt --- a/share/hedgewars/Data/Maps/Knockball/desc.txt Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Maps/Knockball/desc.txt Tue Apr 02 21:00:57 2013 +0200 @@ -1,1 +1,1 @@ -en_US=Knock your opponents off the platforms|using only a bat! +en_US=Knock your opponents off the platforms using only a bat! diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Maps/TrophyRace/desc.txt --- a/share/hedgewars/Data/Maps/TrophyRace/desc.txt Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Maps/TrophyRace/desc.txt Tue Apr 02 21:00:57 2013 +0200 @@ -1,1 +1,1 @@ -en_US=Ready\, set\, go! Who is going to|be the first in this|crazy race? \ No newline at end of file +en_US=Ready\, set\, go! Who is going to be the first in this crazy race? \ No newline at end of file diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Missions/Training/Basic_Training_-_Bazooka.lua --- a/share/hedgewars/Data/Missions/Training/Basic_Training_-_Bazooka.lua Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Missions/Training/Basic_Training_-_Bazooka.lua Tue Apr 02 21:00:57 2013 +0200 @@ -22,7 +22,7 @@ -- This variable controls how many milliseconds/ticks we'd -- like to wait before we end the round once all targets -- have been destroyed. -local end_timer = 5000 -- 5000 ms = 5 s +local end_timer = 1000 -- 1000 ms = 1 s -- This variable is set to true if the game is lost (i.e. -- time runs out). local game_lost = false @@ -140,11 +140,11 @@ -- ... end the game ... EndGame() else - -- ... or just lower the timer by 1. - end_timer = end_timer - 20 + -- ... or just lower the timer by 20ms. -- Reset the time left to stop the timer TurnTimeLeft = time_goal end + end_timer = end_timer - 20 end end diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Missions/Training/Basic_Training_-_Cluster_Bomb.lua --- a/share/hedgewars/Data/Missions/Training/Basic_Training_-_Cluster_Bomb.lua Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Missions/Training/Basic_Training_-_Cluster_Bomb.lua Tue Apr 02 21:00:57 2013 +0200 @@ -2,7 +2,7 @@ local player = nil local scored = 0 -local end_timer = 5000 +local end_timer = 1000 local game_lost = false local time_goal = 0 @@ -76,9 +76,9 @@ if end_timer == 0 then EndGame() else - end_timer = end_timer - 20 TurnTimeLeft = time_goal end + end_timer = end_timer - 20 end end diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Missions/Training/Basic_Training_-_Shotgun.lua --- a/share/hedgewars/Data/Missions/Training/Basic_Training_-_Shotgun.lua Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Missions/Training/Basic_Training_-_Shotgun.lua Tue Apr 02 21:00:57 2013 +0200 @@ -22,7 +22,7 @@ -- This variable controls how many milliseconds/ticks we'd -- like to wait before we end the round once all targets -- have been destroyed. -local end_timer = 5000 -- 5000 ms = 5 s +local end_timer = 1000 -- 1000 ms = 1 s -- This variable is set to true if the game is lost (i.e. -- time runs out). local game_lost = false @@ -133,10 +133,10 @@ EndGame() else -- ... or just lower the timer by 1. - end_timer = end_timer - 20 -- Reset the time left to stop the timer TurnTimeLeft = time_goal end + end_timer = end_timer - 20 end end diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Missions/Training/Basic_Training_-_Sniper_Rifle.lua --- a/share/hedgewars/Data/Missions/Training/Basic_Training_-_Sniper_Rifle.lua Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Missions/Training/Basic_Training_-_Sniper_Rifle.lua Tue Apr 02 21:00:57 2013 +0200 @@ -22,7 +22,7 @@ -- This variable controls how many milliseconds/ticks we'd -- like to wait before we end the round once all targets -- have been destroyed. -local end_timer = 5000 -- 5000 ms = 5 s +local end_timer = 1000 -- 1000 ms = 1 s -- This variable is set to true if the game is lost (i.e. -- time runs out). local game_lost = false @@ -145,10 +145,10 @@ EndGame() else -- ... or just lower the timer by 1. - end_timer = end_timer - 20 -- Reset the time left to stop the timer TurnTimeLeft = time_goal end + end_timer = end_timer - 20 end end diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Scripts/Locale.lua --- a/share/hedgewars/Data/Scripts/Locale.lua Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Scripts/Locale.lua Tue Apr 02 21:00:57 2013 +0200 @@ -2,17 +2,8 @@ local lang = HedgewarsScriptLoad("Locale/" .. tostring(L) .. ".lua") -if lang ~= nil then - lang() -else - lang = HedgewarsScriptLoad("Locale/" .. tostring(L) .. ".lua") - if lang ~= nil then - lang() - end -end - function loc(text) - if lang ~= nil and locale ~= nil and locale[text] ~= nil then return locale[text] + if locale ~= nil and locale[text] ~= nil then return locale[text] else return text end end diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Scripts/Multiplayer/Continental_supplies.lua --- a/share/hedgewars/Data/Scripts/Multiplayer/Continental_supplies.lua Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Scripts/Multiplayer/Continental_supplies.lua Tue Apr 02 21:00:57 2013 +0200 @@ -1,5 +1,5 @@ --[[ -Continental Supplies version 1.1a +Version 1.1c Copyright (C) 2012 Vatten @@ -15,16 +15,24 @@ HedgewarsScriptLoad("/Scripts/Tracker.lua") function int_sqrt(num) - temp=num + local temp=num while(temp*temp-div(temp,2)>num) do temp=div((temp+div(num,temp)),2) end + return math.abs(temp) end function norm(xx,yy) - return int_sqrt((xx^2)+(yy^2)) + --to fix overflows + if(((math.abs(xx)^2)+(math.abs(yy)^2))>2^26) + then + local bitr=2^13 + return int_sqrt((div(math.abs(xx),bitr)^2)+(div(math.abs(yy),bitr)^2))*bitr + else + return int_sqrt((math.abs(xx)^2)+(math.abs(yy)^2)) + end end function positive(num) @@ -40,7 +48,7 @@ local wepcode_teams={} local swapweps=false ---run when game starts on real +--variables for seeing if you have swaped around on a weapon local australianSpecial=false local africanSpecial=0 local africaspecial2=0 @@ -51,32 +59,37 @@ local kergulenSpecial=1 local shotgun_s=false local europe_s=0 +local VampOn=0 local austmine=nil local inpara=false local asianflame=0 +local visualcircle=nil + local temp_val=0 ---f?r sabotage +--for sabotage local disallowattack=0 -local disallowleft=true local disable_moving={} +local disableoffsetai=0 +local onsabotageai=false ---skall bytas till f?r alla teams local continent = {} +local generalinfo=loc("- Per team weapons|- 9 weaponschemes|- Unique new weapons| |Select continent first round with the Weapon Menu or by ([switch/tab]=Increase,[presice/left shift]=Decrease) on Skip|Some weapons have a second option. Find them with [switch/tab]") + local weapontexts = { loc("Green lipstick bullet: [Is poisonous]"), loc("Piñata bullet: [Contains some sweet candy!]"), loc("Anno 1032: [The explosion will make a strong push ~ wide range, wont affect hogs close to the target]"), -loc("Dust storm: [Deals 20 damage to all enemies in the circle]"), +loc("Dust storm: [Deals 15 damage to all enemies in the circle]"), loc("Fire a mine: [Does what it says ~ Cant be dropped close to an enemy ~ 1 sec]"), -loc("Drop a bomb: [drop some heroic wind that will turn into a bomb on impact]"), +loc("Drop a bomb: [drop some heroic wind that will turn into a bomb on impact ~ once per turn]"), loc("Scream from a Walrus: [Deal 20 damage + 10% of your hogs health to all hogs around you and get half back]"), loc("Disguise as a Rockhopper Penguin: [Swap place with a random enemy hog in the circle]"), loc("Flare: [fire up some bombs depending on hogs depending on hogs in the circle"), -loc("Lonely Cries: [Rise the water if no hog is in the circle and deal 1 damage to all hogs]"), +loc("Lonely Cries: [Rise the water if no hog is in the circle and deal 7 damage to all enemy hogs]"), loc("Hedgehog projectile: [fire your hog like a Sticky Bomb]"), loc("Napalm rocket: [Fire a bomb with napalm!]"), loc("Eagle Eye: [Blink to the impact ~ one shot]"), @@ -90,31 +103,43 @@ {{amShotgun,100},{amDEagle,100},{amLaserSight,4},{amSniperRifle,100},{amCake,1},{amAirAttack,2},{amSwitch,6}}}, {loc("South America"),"Area: 17,840,000 km2, Population: 387,489,196 ",loc("Special Weapons:").."|"..loc("GasBomb")..": "..weapontexts[3],amGasBomb, -{{amBirdy,5},{amHellishBomb,1},{amBee,100},{amWhip,100},{amGasBomb,100},{amFlamethrower,100},{amNapalm,1},{amExtraDamage,2}}}, +{{amBirdy,6},{amHellishBomb,1},{amBee,100},{amWhip,100},{amGasBomb,100},{amFlamethrower,100},{amNapalm,1},{amExtraDamage,2}}}, {loc("Europe"),"Area: 10,180,000 km2, Population: 739,165,030",loc("Special Weapons:").."|"..loc("Molotov")..": "..weapontexts[14],amBazooka, {{amBazooka,100},{amGrenade,100},{amMortar,100},{amClusterBomb,5},{amMolotov,5},{amVampiric,4},{amPiano,1},{amResurrector,2},{amJetpack,2}}}, {loc("Africa"),"Area: 30,221,532 km2, Population: 1,032,532,974",loc("Special Weapons:").."|"..loc("Seduction")..": "..weapontexts[4].."|"..loc("Sticky Mine")..": "..weapontexts[11].."|"..loc("Sticky Mine")..": "..weapontexts[12],amSMine, -{{amSMine,6},{amWatermelon,1},{amDrillStrike,1},{amExtraTime,2},{amDrill,100},{amLandGun,3},{amSeduction,100}}}, +{{amSMine,100},{amWatermelon,1},{amDrillStrike,1},{amExtraTime,2},{amDrill,100},{amLandGun,3},{amSeduction,100}}}, -{loc("Asia"),"Area: 44,579,000 km2, Population: 3,879,000,000",loc("- Will refresh Parachute each turn.").."|"..loc("Special Weapons:").."|"..loc("Parachute")..": "..weapontexts[6],amRope, -{{amKamikaze,4},{amRope,100},{amFirePunch,100},{amParachute,1},{amKnife,4},{amDynamite,1}}}, +{loc("Asia"),"Area: 44,579,000 km2, Population: 3,879,000,000",loc("- Will give you a parachute each turn.").."|"..loc("Special Weapons:").."|"..loc("Parachute")..": "..weapontexts[6],amRope, +{{amKamikaze,4},{amRope,100},{amFirePunch,100},{amParachute,1},{amKnife,2},{amDynamite,1}}}, {loc("Australia"),"Area: 8,468,300 km2, Population: 31,260,000",loc("Special Weapons:").."|"..loc("Baseballbat")..": "..weapontexts[5],amBaseballBat, {{amBaseballBat,100},{amMine,100},{amLowGravity,6},{amBlowTorch,100},{amRCPlane,2},{amTardis,100}}}, -{loc("Antarctica"),"Area: 14,000,000 km2, Population: ~1,000",loc("- Will refresh portalgun each turn."),amTeleport, -{{amSnowball,4},{amTeleport,2},{amInvulnerable,6},{amPickHammer,100},{amSineGun,100},{amGirder,4},{amPortalGun,1}}}, +{loc("Antarctica"),"Area: 14,000,000 km2, Population: ~1,000",loc("- Will give you a portalgun every second turn."),amTeleport, +{{amSnowball,4},{amTeleport,2},{amInvulnerable,6},{amPickHammer,100},{amSineGun,100},{amGirder,3},{amPortalGun,2}}}, -{loc("Kerguelen"),"Area: 1,100,000 km2, Population: ~70",loc("Special Weapons:").."|"..loc("Structure")..": "..weapontexts[7].."|"..loc("Structure")..": "..weapontexts[8].." ("..loc("Duration")..": 2)|"..loc("Structure")..": "..weapontexts[9].."|"..loc("Structure")..": "..weapontexts[10],amStructure, -{{amHammer,100},{amMineStrike,2},{amBallgun,1},{amStructure,100}}}, ---no ,{amIceGun,4} for 0.9.18 +{loc("Kerguelen"),"Area: 1,100,000 km2, Population: ~70",loc("Special Weapons:").."|"..loc("Hammer")..": "..weapontexts[7].."|"..loc("Hammer")..": "..weapontexts[8].." ("..loc("Duration")..": 2)|"..loc("Hammer")..": "..weapontexts[9].."|"..loc("Hammer")..": "..weapontexts[10].."|"..loc("Hammer")..": "..weapontexts[15],amHammer, +{{amHammer,100},{amMineStrike,2},{amBallgun,1},{amIceGun,2}}}, {loc("Zealandia"),"Area: 3,500,000 km2, Population: 4,650,000",loc("- Will Get 1-3 random weapons"),amInvulnerable, {{amBazooka,1},{amBlowTorch,1},{amSwitch,1}}} } +local weaponsetssounds= +{ +{sndShotgunFire,sndCover}, +{sndEggBreak,sndLaugh}, +{sndExplosion,sndEnemyDown}, +{sndMelonImpact,sndHello}, +{sndRopeAttach,sndComeonthen}, +{sndBaseballBat,sndNooo}, +{sndSineGun,sndOops}, +{sndPiano5,sndStupid}, +{sndSplash,sndFirstBlood} +} + --weapontype,ammo,?,duration,*times your choice,affect on random team (should be placed with 1,0,1,0,1 on the 6th option for better randomness) local weapons_dmg = { {amKamikaze, 0, 1, 0, 1, 0}, @@ -152,8 +177,8 @@ {amSMine, 0, 1, 0, 1, 1}, {amHammer, 0, 1, 0, 1, 0}, {amDrillStrike, 0, 1, 4, 1, 2}, - {amSnowball, 0, 1, 0, 1, 0}, - {amStructure, 0, 0, 0, 1, 1} + {amSnowball, 0, 1, 0, 1, 0} + --{amStructure, 0, 0, 0, 1, 1} } local weapons_supp = { {amParachute, 0, 1, 0, 1, 0}, @@ -175,7 +200,8 @@ {amIceGun, 0, 1, 0, 1, 0}, {amKnife, 0, 1, 0, 1, 0} } - + +--will check after borders and stuff function validate_weapon(hog,weapon,amount) if(MapHasBorder() == false or (MapHasBorder() == true and weapon ~= amAirAttack and weapon ~= amMineStrike and weapon ~= amNapalm and weapon ~= amDrillStrike and weapon ~= amPiano)) then @@ -187,8 +213,8 @@ function cleanweps(hog) local i=1 - --+1 for skip - while(i<=table.getn(weapons_supp)+table.getn(weapons_dmg)+1) + --+1 for skip +1 for freezer + while(i<=table.maxn(weapons_supp)+table.maxn(weapons_dmg)+2) do AddAmmo(hog,i,0) i=i+1 @@ -197,6 +223,7 @@ AddAmmo(hog,amSkip,100) end +--get the weapons from a weaponset function load_weaponset(hog, num) for v,w in pairs(weaponsets[num][5]) do @@ -204,6 +231,7 @@ end end +--list up all weapons from the icons for each continent function load_continent_selection(hog) for v,w in pairs(weaponsets) do @@ -212,20 +240,27 @@ AddAmmo(hog,amSwitch) --random continent end -function show_continent_info(continent,time) +--shows the continent info +function show_continent_info(continent,time,generalinf) + local geninftext="" local ns=false if(time==-1) then time=0 ns=true end - ShowMission(weaponsets[continent][1],weaponsets[continent][2],weaponsets[continent][3], -weaponsets[continent][4], time) + if(generalinf) + then + geninftext="| |"..loc("General information")..": |"..generalinfo + end + ShowMission(weaponsets[continent][1],weaponsets[continent][2],weaponsets[continent][3]..geninftext, -weaponsets[continent][4], time) if(ns) then HideMission() end end +--will show a circle of gears (eye candy) function visual_gear_explosion(range,xpos,ypos,gear1,gear2) local degr=0 local lap=30 @@ -245,94 +280,97 @@ end end ---zealandia +--zealandia (generates weapons from the weaponinfo above function get_random_weapon(hog) - if(GetGearType(hog) == gtHedgehog) + if(GetGearType(hog) == gtHedgehog and continent[GetHogTeamName(hog)]==9 and getTeamValue(GetHogTeamName(hog), "rand-done-turn")==nil) then + cleanweps(hog) + local random_weapon = 0 local old_rand_weap = 0 local rand_weaponset_power = 0 - if(continent[GetHogTeamName(hog)]==9 and (getTeamValue(GetHogTeamName(hog), "rand-done-turn")==false or getTeamValue(GetHogTeamName(hog), "rand-done-turn")==nil)) - then - cleanweps(hog) + local numberof_weapons_supp=table.maxn(weapons_supp) + local numberof_weapons_dmg=table.maxn(weapons_dmg) + + local rand1=GetRandom(table.maxn(weapons_supp))+1 + local rand2=GetRandom(table.maxn(weapons_dmg))+1 + + random_weapon = GetRandom(table.maxn(weapons_dmg))+1 + + while(weapons_dmg[random_weapon][4]>TotalRounds) + do + if(random_weapon>=numberof_weapons_dmg) + then + random_weapon=0 + end + random_weapon = random_weapon+1 + end + validate_weapon(hog, weapons_dmg[random_weapon][1],1) + rand_weaponset_power=weapons_dmg[random_weapon][6] + old_rand_weap = random_weapon - random_weapon = GetRandom(table.getn(weapons_dmg))+1 - while(weapons_dmg[random_weapon][4]>TotalRounds) + if(rand_weaponset_power <2) + then + random_weapon = rand1 + while(weapons_supp[random_weapon][4]>TotalRounds or rand_weaponset_power+weapons_supp[random_weapon][6]>2) do - if(random_weapon>=table.getn(weapons_dmg)) + if(random_weapon>=numberof_weapons_supp) + then + random_weapon=0 + end + random_weapon = random_weapon+1 + end + validate_weapon(hog, weapons_supp[random_weapon][1],1) + rand_weaponset_power=rand_weaponset_power+weapons_supp[random_weapon][6] + end + --check again if the power is enough + if(rand_weaponset_power <1) + then + random_weapon = rand2 + while(weapons_dmg[random_weapon][4]>TotalRounds or old_rand_weap == random_weapon or weapons_dmg[random_weapon][6]>0) + do + if(random_weapon>=numberof_weapons_dmg) then random_weapon=0 end random_weapon = random_weapon+1 end validate_weapon(hog, weapons_dmg[random_weapon][1],1) - rand_weaponset_power=weapons_dmg[random_weapon][6] - old_rand_weap = random_weapon + end - if(rand_weaponset_power <2) - then - random_weapon = GetRandom(table.getn(weapons_supp))+1 - while(weapons_supp[random_weapon][4]>TotalRounds or rand_weaponset_power+weapons_supp[random_weapon][6]>2) - do - if(random_weapon>=table.getn(weapons_supp)) - then - random_weapon=0 - end - random_weapon = random_weapon+1 - end - validate_weapon(hog, weapons_supp[random_weapon][1],1) - rand_weaponset_power=rand_weaponset_power+weapons_supp[random_weapon][6] - end - --check again if the power is enough - if(rand_weaponset_power <1) - then - random_weapon = GetRandom(table.getn(weapons_dmg))+1 - while(weapons_dmg[random_weapon][4]>TotalRounds or old_rand_weap == random_weapon or weapons_dmg[random_weapon][6]>0) - do - if(random_weapon>=table.getn(weapons_dmg)) - then - random_weapon=0 - end - random_weapon = random_weapon+1 - end - validate_weapon(hog, weapons_dmg[random_weapon][1],1) - end - - setTeamValue(GetHogTeamName(hog), "rand-done-turn", true) - - if(GetHogTeamName(hog)==GetHogTeamName(CurrentHedgehog)) - then - temp_val=false - end - end + setTeamValue(GetHogTeamName(hog), "rand-done-turn", true) end end - -function setweapons(skipafter) +--this will take that hogs settings for the weapons and add them +function setweapons() cleanweps(CurrentHedgehog) load_weaponset(CurrentHedgehog,continent[GetHogTeamName(CurrentHedgehog)]) - if(skipafter==true) - then - ParseCommand("setweap " .. string.char(amSkip)) - end - - show_continent_info(continent[GetHogTeamName(CurrentHedgehog)],0) + + visualstuff=AddVisualGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog)-5, vgtDust,0, false) + v1, v2, v3, v4, v5, v6, v7, v8, v9, v10 = GetVisualGearValues(visualstuff) + SetVisualGearValues(visualstuff, v1, v2, v3, v4, v5, v6, v7, 2, v9, GetClanColor(GetHogClan(CurrentHedgehog))) + + show_continent_info(continent[GetHogTeamName(CurrentHedgehog)],0,false) end +--show health tag (will mostly be used when a hog is damaged) function show_damage_tag(hog,damage) healthtag=AddVisualGear(GetX(hog), GetY(hog), vgtHealthTag, damage, false) v1, v2, v3, v4, v5, v6, v7, v8, v9, v10 = GetVisualGearValues(healthtag) SetVisualGearValues(healthtag, v1, v2, v3, v4, v5, v6, v7, v8, v9, GetClanColor(GetHogClan(hog))) end +--will use int_sqrt function fire_gear(hedgehog,geartype,vx,vy,timer) - return AddGear(div((GetGearRadius(hedgehog)*2*vx),norm(vx,vy))+GetX(hedgehog), div((GetGearRadius(hedgehog)*2*vy),norm(vx,vy))+GetY(hedgehog), geartype, 0, vx, vy, timer) + local hypo=norm(vx,vy) + return AddGear(div((GetGearRadius(hedgehog)*2*vx),hypo)+GetX(hedgehog), div((GetGearRadius(hedgehog)*2*vy),hypo)+GetY(hedgehog), geartype, 0, vx, vy, timer) end --==========================run throw all hog/gear weapons ========================== +--will check if the mine is nicely placed function weapon_aust_check(hog) if(GetGearType(hog) == gtHedgehog) then @@ -343,16 +381,19 @@ end end +--african special on sedunction function weapon_duststorm(hog) if(GetGearType(hog) == gtHedgehog) then - local dmg=20 + local dmg=15 if(gearIsInCircle(hog,GetX(CurrentHedgehog), GetY(CurrentHedgehog), 250, false)==true and GetHogClan(hog) ~= GetHogClan(CurrentHedgehog)) then if(GetHealth(hog) > dmg) then + temp_val=temp_val+div(dmg*VampOn,100) SetHealth(hog, GetHealth(hog)-dmg) else + temp_val=temp_val+div(GetHealth(hog)*VampOn,100) SetHealth(hog, 0) end show_damage_tag(hog,dmg) @@ -360,6 +401,7 @@ end end +--kerguelen special on structure function weapon_scream_walrus(hog) if(GetGearType(hog) == gtHedgehog) then @@ -367,11 +409,11 @@ then if(GetHealth(hog)>(20+GetHealth(CurrentHedgehog)*0.1)) then + temp_val=temp_val+10+(GetHealth(CurrentHedgehog)*0.05)+div((20+GetHealth(CurrentHedgehog)*0.1)*VampOn,100) SetHealth(hog, GetHealth(hog)-(20+GetHealth(CurrentHedgehog)*0.1)) - temp_val=temp_val+10+GetHealth(CurrentHedgehog)*0.05 else + temp_val=temp_val+(GetHealth(hog)*0.5)+(GetHealth(CurrentHedgehog)*0.05)+div((GetHealth(hog)+(GetHealth(CurrentHedgehog)*0.1))*VampOn,100) SetHealth(hog, 0) - temp_val=temp_val+(GetHealth(hog)*0.5)+(GetHealth(CurrentHedgehog)*0.05) end show_damage_tag(hog,(20+GetHealth(CurrentHedgehog)*0.1)) AddVisualGear(GetX(hog), GetY(hog), vgtExplosion, 0, false) @@ -380,6 +422,7 @@ end end +--kerguelen special swap hog function weapon_swap_kerg(hog) if(GetGearType(hog) == gtHedgehog) then @@ -394,6 +437,7 @@ end end +--kerguelen special on structure function weapon_flare(hog) if(GetGearType(hog) == gtHedgehog) then @@ -414,6 +458,7 @@ end end +--kerguelen special will apply sabotage function weapon_sabotage(hog) if(GetGearType(hog) == gtHedgehog) then @@ -426,10 +471,12 @@ end end +--south american special (used fire gear) function weapon_anno_south(hog) - local power_radius_outer=250 - local power_radius_inner=40 + local power_radius_outer=230 + local power_radius_inner=45 local power_sa=500000 + local hypo=0 if(gearIsInCircle(hog,GetX(temp_val), GetY(temp_val), power_radius_outer, false) and gearIsInCircle(hog,GetX(temp_val), GetY(temp_val), power_radius_inner, false)==false) then if(hog == CurrentHedgehog) @@ -437,32 +484,41 @@ SetState(CurrentHedgehog, gstMoving) end SetGearPosition(hog, GetX(hog),GetY(hog)-3) - SetGearVelocity(hog, div((power_radius_outer-norm(math.abs(GetX(hog)-GetX(temp_val)),math.abs(GetY(hog)-GetY(temp_val))))*power_sa*positive(GetX(hog)-GetX(temp_val)),power_radius_outer), div((power_radius_outer-norm(math.abs(GetX(hog)-GetX(temp_val)),math.abs(GetY(hog)-GetY(temp_val))))*power_sa*positive(GetY(hog)-GetY(temp_val)),power_radius_outer)) + hypo=norm(math.abs(GetX(hog)-GetX(temp_val)),math.abs(GetY(hog)-GetY(temp_val))) + SetGearVelocity(hog, div((power_radius_outer-hypo)*power_sa*positive(GetX(hog)-GetX(temp_val)),power_radius_outer), div((power_radius_outer-hypo)*power_sa*positive(GetY(hog)-GetY(temp_val)),power_radius_outer)) + end +end + +--first part on kerguelen special (lonely cries) +function weapon_cries_a(hog) + if(GetGearType(hog) == gtHedgehog and hog ~= CurrentHedgehog and gearIsInCircle(hog,GetX(CurrentHedgehog), GetY(CurrentHedgehog), 500, false)) + then + kergulenSpecial=-1 end end -function weapon_cries_a(hog) - if(GetGearType(hog) == gtHedgehog) - then - if(GetHogClan(hog) ~= GetHogClan(CurrentHedgehog) and gearIsInCircle(hog,GetX(CurrentHedgehog), GetY(CurrentHedgehog), 500, false)) - then - kergulenSpecial=-1 - end - end -end - +--second part on kerguelen special (lonely cries) function weapon_cries_b(hog) if(GetGearType(hog) == gtHedgehog) then + local dmg=7 if(GetHogClan(hog) ~= GetHogClan(CurrentHedgehog)) then - SetHealth(hog, GetHealth(hog)-1) - show_damage_tag(hog,1) + if(GetHealth(hog) > dmg) + then + temp_val=temp_val+div(dmg*VampOn,100) + SetHealth(hog, GetHealth(hog)-dmg) + else + temp_val=temp_val+div(GetHealth(hog)*VampOn,100) + SetHealth(hog, 0) + end + show_damage_tag(hog,dmg) AddVisualGear(GetX(hog), GetY(hog)-30, vgtEvilTrace, 0, false) end end end +--north american special on sniper function weapon_lipstick(hog) if(GetGearType(hog) == gtHedgehog) then @@ -474,6 +530,7 @@ end end +--european special on molotov (used fire gear) function weapon_health(hog) if(GetGearType(hog) == gtHedgehog) then @@ -505,13 +562,14 @@ function onGameStart() --trackTeams() - ShowMission(loc("Continental supplies").." 1.1a",loc("Let a Continent provide your weapons!"), - loc("- Per team weapons|- 9 weaponschemes|- Unique new weapons| |Select continent first round with the Weapon Menu or by ([switch/tab]=Increase,[precise/left shift]=Decrease) on Skip|Some weapons have a second option. Find them with [switch/tab]"), -amLowGravity, 0) + ShowMission(loc("Continental supplies").." 1.1c",loc("Let a Continent provide your weapons!"), + loc(generalinfo), -amLowGravity, 0) end --what happen when a turn starts function onNewTurn() - + + --will refresh the info on each tab weapon australianSpecial=true asianSpecial=false austmine=nil @@ -524,13 +582,18 @@ shotgun_s=false sniper_s_in_use=false europe_s=0 + VampOn=0 temp_val=0 + --for sabotage disallowattack=0 - disallowleft=true + if(disable_moving[CurrentHedgehog]==true) + then + disableoffsetai=GetHogLevel(CurrentHedgehog) + end + --when all hogs are "placed" - if(GetCurAmmoType()~=amTeleport) then --will run once when the game really starts (after placing hogs and so on @@ -543,34 +606,42 @@ swapweps=true teams_ok[GetHogTeamName(CurrentHedgehog)] = 2 else + --if its not the initialization turn swapweps=false if(continent[GetHogTeamName(CurrentHedgehog)]==0) then - continent[GetHogTeamName(CurrentHedgehog)]=GetRandom(table.getn(weaponsets))+1 - setweapons(false) + continent[GetHogTeamName(CurrentHedgehog)]=GetRandom(table.maxn(weaponsets))+1 + setweapons() end - show_continent_info(continent[GetHogTeamName(CurrentHedgehog)],-1) + show_continent_info(continent[GetHogTeamName(CurrentHedgehog)],-1,true) + + --give zeelandia-teams new weapons so they can plan for the next turn + runOnGears(get_random_weapon) + + --some specials for some continents (temp_val is from get random weapons) + if(continent[GetHogTeamName(CurrentHedgehog)]==9) + then + setTeamValue(GetHogTeamName(CurrentHedgehog), "rand-done-turn", nil) + elseif(continent[GetHogTeamName(CurrentHedgehog)]==7) + then + if(getTeamValue(GetHogTeamName(CurrentHedgehog), "Antarctica-turntick")==nil) + then + setTeamValue(GetHogTeamName(CurrentHedgehog), "Antarctica-turntick", 1) + end + + if(getTeamValue(GetHogTeamName(CurrentHedgehog), "Antarctica-turntick")>=2) + then + AddAmmo(CurrentHedgehog,amPortalGun) + setTeamValue(GetHogTeamName(CurrentHedgehog), "Antarctica-turntick", 0) + end + setTeamValue(GetHogTeamName(CurrentHedgehog), "Antarctica-turntick", getTeamValue(GetHogTeamName(CurrentHedgehog), "Antarctica-turntick")+1) + + elseif(continent[GetHogTeamName(CurrentHedgehog)]==5) + then + AddAmmo(CurrentHedgehog,amParachute) + end end end - - if(continent[GetHogTeamName(CurrentHedgehog)]==7) - then - AddAmmo(CurrentHedgehog,amPortalGun,0) - AddAmmo(CurrentHedgehog,amPortalGun,1) - elseif(continent[GetHogTeamName(CurrentHedgehog)]==5) - then - AddAmmo(CurrentHedgehog,amParachute,0) - AddAmmo(CurrentHedgehog,amParachute,1) - end - - temp_val=true - runOnGears(get_random_weapon) - - if(temp_val==true and continent[GetHogTeamName(CurrentHedgehog)]==9 and getTeamValue(GetHogTeamName(CurrentHedgehog), "rand-done-turn")==true) - then - setTeamValue(GetHogTeamName(CurrentHedgehog), "rand-done-turn", false) - end - end --what happens when you press "tab" (common button) @@ -645,7 +716,7 @@ end end - --north america + --north america (sniper) if(GetCurAmmoType() == amSniperRifle and sniper_s_in_use==false) then if(namericanSpecial==3) @@ -663,6 +734,7 @@ end end + --north america (shotgun) if(GetCurAmmoType() == amShotgun and shotgun_s~=nil) then if(shotgun_s==false) @@ -675,6 +747,7 @@ end end + --europe if(GetCurAmmoType() == amMolotov) then if(europe_s==0) @@ -687,45 +760,52 @@ end end - if(swapweps==true and GetCurAmmoType() == amSkip) + --swap forward in the weaponmenu (1.0 style) + if(swapweps==true and (GetCurAmmoType() == amSkip or GetCurAmmoType() == amNothing)) then continent[GetHogTeamName(CurrentHedgehog)]=continent[GetHogTeamName(CurrentHedgehog)]+1 - if(continent[GetHogTeamName(CurrentHedgehog)]> table.getn(weaponsets)) + if(continent[GetHogTeamName(CurrentHedgehog)]> table.maxn(weaponsets)) then continent[GetHogTeamName(CurrentHedgehog)]=1 end - setweapons(true) + setweapons() end - if(GetCurAmmoType() == amStructure) + --kerguelen + if(GetCurAmmoType() == amHammer) then - if(kergulenSpecial==5) + if(kergulenSpecial==6) then kergulenSpecial = 1 - AddCaption("#"..weapontexts[7]) - elseif(kergulenSpecial==1 and TotalRounds>=1) + AddCaption("Normal") + elseif(kergulenSpecial==1) then kergulenSpecial = 2 - AddCaption("##"..weapontexts[8]) - elseif(kergulenSpecial==2 or (kergulenSpecial==1 and TotalRounds<1)) + AddCaption("#"..weapontexts[7]) + elseif(kergulenSpecial==2 and TotalRounds>=1) then kergulenSpecial = 3 - AddCaption("###"..weapontexts[9]) - elseif(kergulenSpecial==3) + AddCaption("##"..weapontexts[8]) + elseif(kergulenSpecial==3 or (kergulenSpecial==2 and TotalRounds<1)) then kergulenSpecial = 4 - AddCaption("####"..weapontexts[10]) + AddCaption("###"..weapontexts[9]) elseif(kergulenSpecial==4) then kergulenSpecial = 5 + AddCaption("####"..weapontexts[10]) + elseif(kergulenSpecial==5) + then + kergulenSpecial = 6 AddCaption("#####"..weapontexts[15]) end end end function onPrecise() - if(swapweps==true and GetCurAmmoType() == amSkip) + --swap backwards in the weaponmenu (1.0 style) + if(swapweps==true and (GetCurAmmoType() == amSkip or GetCurAmmoType() == amNothing)) then continent[GetHogTeamName(CurrentHedgehog)]=continent[GetHogTeamName(CurrentHedgehog)]-1 @@ -733,98 +813,55 @@ then continent[GetHogTeamName(CurrentHedgehog)]=9 end - setweapons(true) - end -end - -function onSlot() - if(continent[GetHogTeamName(CurrentHedgehog)]==0) then - ParseCommand("setweap " .. string.char(amSkip)) + setweapons() end end function onGameTick20() - - if(teams_ok[GetHogTeamName(CurrentHedgehog)] == 2) + --if you picked a weaponset from the weaponmenu (icon) + if(continent[GetHogTeamName(CurrentHedgehog)]==0) then - if(GetCurAmmoType()~=amTeleport and swapweps==true and TurnTime-TurnTimeLeft>=100) + if(GetCurAmmoType()==amSwitch) then - teams_ok[GetHogTeamName(CurrentHedgehog)] = true - ParseCommand("setweap " .. string.char(amSkip)) + continent[GetHogTeamName(CurrentHedgehog)]=GetRandom(table.maxn(weaponsets))+1 + setweapons() + PlaySound(sndMineTick) + else + for v,w in pairs(weaponsets) + do + if(GetCurAmmoType()==weaponsets[v][4]) + then + continent[GetHogTeamName(CurrentHedgehog)]=v + setweapons() + PlaySound(weaponsetssounds[v][1]) + PlaySound(weaponsetssounds[v][2],CurrentHedgehog) + end + end end end - if(continent[GetHogTeamName(CurrentHedgehog)]==0) + --show the kerguelen ring + if(kergulenSpecial > 1 and GetCurAmmoType() == amHammer) then - if(GetCurAmmoType()==amSniperRifle) then - continent[GetHogTeamName(CurrentHedgehog)]=1 - setweapons(false) - elseif(GetCurAmmoType()==amGasBomb) then - continent[GetHogTeamName(CurrentHedgehog)]=2 - setweapons(false) - elseif(GetCurAmmoType()==amBazooka) then - continent[GetHogTeamName(CurrentHedgehog)]=3 - setweapons(false) - elseif(GetCurAmmoType()==amSMine) then - continent[GetHogTeamName(CurrentHedgehog)]=4 - setweapons(false) - elseif(GetCurAmmoType()==amRope) then - continent[GetHogTeamName(CurrentHedgehog)]=5 - setweapons(false) - elseif(GetCurAmmoType()==amBaseballBat) then - continent[GetHogTeamName(CurrentHedgehog)]=6 - setweapons(false) - elseif(GetCurAmmoType()==amTeleport) then - continent[GetHogTeamName(CurrentHedgehog)]=7 - setweapons(false) - elseif(GetCurAmmoType()==amStructure) then - continent[GetHogTeamName(CurrentHedgehog)]=8 - setweapons(false) - elseif(GetCurAmmoType()==amInvulnerable) then - continent[GetHogTeamName(CurrentHedgehog)]=9 - setweapons(false) - elseif(GetCurAmmoType()==amSwitch) then - continent[GetHogTeamName(CurrentHedgehog)]=GetRandom(table.getn(weaponsets))+1 - setweapons(false) + if(visualcircle==nil) + then + visualcircle=AddVisualGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), vgtCircle, 0, false) end - end - - if(kergulenSpecial ~= 0 and GetCurAmmoType() == amStructure) - then - if(kergulenSpecial == 1) + + if(kergulenSpecial == 2) --walrus scream then - if(visualcircle==nil) - then - visualcircle=AddVisualGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), vgtCircle, 120, false) - end SetVisualGearValues(visualcircle, GetX(CurrentHedgehog), GetY(CurrentHedgehog),20, 200, 0, 0, 100, 120, 4, 0xff0000ee) - elseif(kergulenSpecial == 2) + elseif(kergulenSpecial == 3) --swap hog then - if(visualcircle==nil) - then - visualcircle=AddVisualGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), vgtCircle, 450, false) - end SetVisualGearValues(visualcircle, GetX(CurrentHedgehog), GetY(CurrentHedgehog),20, 200, 0, 0, 100, 450, 3, 0xffff00ee) - elseif(kergulenSpecial == 3) - then - if(visualcircle==nil) - then - visualcircle=AddVisualGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), vgtCircle, 45, false) - end - SetVisualGearValues(visualcircle, GetX(CurrentHedgehog), GetY(CurrentHedgehog),20, 200, 0, 0, 100, 45, 6, 0x00ff00ee) - elseif(kergulenSpecial == 4) + elseif(kergulenSpecial == 4) --flare then - if(visualcircle==nil) - then - visualcircle=AddVisualGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), vgtCircle, 500, false) - end + SetVisualGearValues(visualcircle, GetX(CurrentHedgehog), GetY(CurrentHedgehog),20, 200, 0, 0, 100, 45, 6, 0x00ff00ee) + elseif(kergulenSpecial == 5) --cries + then SetVisualGearValues(visualcircle, GetX(CurrentHedgehog), GetY(CurrentHedgehog),20, 200, 0, 0, 100, 500, 1, 0x0000ffee) - elseif(kergulenSpecial == 5) + elseif(kergulenSpecial == 6) --sabotage then - if(visualcircle==nil) - then - visualcircle=AddVisualGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), vgtCircle, 100, false) - end SetVisualGearValues(visualcircle, GetX(CurrentHedgehog), GetY(CurrentHedgehog),20, 200, 0, 0, 100, 100, 10, 0xeeeeeeee) end @@ -834,21 +871,25 @@ visualcircle=nil end + --sabotage if(disable_moving[CurrentHedgehog]==true) then if(TurnTimeLeft<=150) then disable_moving[CurrentHedgehog]=false - SetHogLevel(CurrentHedgehog,0) + SetHogLevel(CurrentHedgehog,disableoffsetai) + onsabotageai=false elseif(disallowattack>=15 and disallowattack >= 20) then disallowattack=0 + onsabotageai=true SetHogLevel(CurrentHedgehog,1) AddVisualGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), vgtSmokeWhite, 0, false) - elseif(GetHogLevel(CurrentHedgehog)==1) + elseif(onsabotageai==true) then - SetHogLevel(CurrentHedgehog,0) + SetHogLevel(CurrentHedgehog,disableoffsetai) + onsabotageai=false else disallowattack=disallowattack+1 end @@ -860,43 +901,48 @@ --if you used hogswitch or any similar weapon, dont enable any weaponchange function onAttack() swapweps=false - local around=false --african special if(africanSpecial == 1 and GetCurAmmoType() == amSeduction) then SetState(CurrentHedgehog, gstAttacked) + temp_val=0 runOnGears(weapon_duststorm) + SetHealth(CurrentHedgehog, GetHealth(CurrentHedgehog)+temp_val) --visual stuff visual_gear_explosion(250,GetX(CurrentHedgehog), GetY(CurrentHedgehog),vgtSmoke,vgtSmokeWhite) PlaySound(sndParachute) - end - + --Kerguelen specials - if(GetCurAmmoType() == amStructure) + elseif(GetCurAmmoType() == amHammer and kergulenSpecial > 1) then SetState(CurrentHedgehog, gstAttacked) - if(kergulenSpecial == 1) + --scream + if(kergulenSpecial == 2) then temp_val=0 runOnGears(weapon_scream_walrus) SetHealth(CurrentHedgehog, GetHealth(CurrentHedgehog)+temp_val) PlaySound(sndHellish) - - elseif(kergulenSpecial == 2 and TotalRounds>=1) + + --swap + elseif(kergulenSpecial == 3 and TotalRounds>=1) then runOnGears(weapon_swap_kerg) PlaySound(sndPiano3) - elseif(kergulenSpecial == 3) + + --flare + elseif(kergulenSpecial == 4) then runOnGears(weapon_flare) PlaySound(sndThrowRelease) AddVisualGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), vgtSmokeWhite, 0, false) - AddGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog)-20, gtCluster, 0, 0, -1000000, 30) - - elseif(kergulenSpecial == 4) + AddGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog)-20, gtCluster, 0, 0, -1000000, 34) + + --cries + elseif(kergulenSpecial == 5) then runOnGears(weapon_cries_a) if(kergulenSpecial~=-1) @@ -905,18 +951,25 @@ PlaySound(sndWarp) PlaySound(sndMolotov) + temp_val=0 runOnGears(weapon_cries_b) + SetHealth(CurrentHedgehog, GetHealth(CurrentHedgehog)+temp_val) else HogSay(CurrentHedgehog, loc("Hogs in sight!"), SAY_SAY) end - elseif(kergulenSpecial == 5) + + --sabotage + elseif(kergulenSpecial == 6) then runOnGears(weapon_sabotage) end DeleteVisualGear(visualcircle) visualcircle=nil + + elseif(GetCurAmmoType() == amVampiric) + then + VampOn=75 end - --Australian special if(GetGearType(austmine) == gtMine and austmine ~= nil) then @@ -933,10 +986,12 @@ austmine=nil end + --stop sabotage (avoiding a bug) if(disable_moving[CurrentHedgehog]==true) then disable_moving[CurrentHedgehog]=false - SetHogLevel(CurrentHedgehog,0) + onsabotageai=false + SetHogLevel(CurrentHedgehog,disableoffsetai) end australianSpecial=false @@ -945,6 +1000,7 @@ function onGearAdd(gearUid) swapweps=false + --track the gears im using if(GetGearType(gearUid) == gtHedgehog or GetGearType(gearUid) == gtMine or GetGearType(gearUid) == gtExplosives) then trackGear(gearUid) @@ -1010,7 +1066,8 @@ then trackDeletion(gearUid) end - --north american specials + + --north american lipstick if(GetGearType(gearUid)==gtSniperRifleShot ) then sniper_s_in_use=false @@ -1027,10 +1084,12 @@ SetGearMessage(pinata,1) end + --north american pinata elseif(GetGearType(gearUid)==gtCluster and GetGearMessage(gearUid)==1 and namericanSpecial==3) then AddGear(GetX(gearUid), GetY(gearUid), gtCluster, 0, 0, 0, 20) + --north american eagle eye elseif(GetGearType(gearUid)==gtShotgunShot and shotgun_s==true) then SetState(CurrentHedgehog, gstMoving) @@ -1043,11 +1102,13 @@ temp_val=gearUid runOnGears(weapon_anno_south) AddVisualGear(GetX(gearUid), GetY(gearUid), vgtExplosion, 0, false) - + + --asian special elseif(GetGearType(gearUid)==gtSnowball and GetGearMessage(gearUid)==1) then - AddGear(GetX(gearUid), GetY(gearUid)+3, gtCluster, 0, 0, 0, 22) - + AddGear(GetX(gearUid), GetY(gearUid), gtCluster, 0, 0, 0, 22) + + --europe special elseif(GetGearType(gearUid)==gtCluster and GetGearMessage(gearUid)==2) then temp_val=gearUid @@ -1055,9 +1116,16 @@ visual_gear_explosion(100,GetX(gearUid), GetY(gearUid),vgtSmokeWhite,vgtSmokeWhite) AddVisualGear(GetX(gearUid), GetY(gearUid), vgtExplosion, 0, false) PlaySound(sndGraveImpact) - + + --asia (using para) elseif(GetGearType(gearUid)==gtParachute) then inpara=false end end +--[[ +sources (populations & area): +Wikipedia +Own calculations +if you think they are wrong, then please tell me :) +]] \ No newline at end of file diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Scripts/Multiplayer/Highlander.cfg --- a/share/hedgewars/Data/Scripts/Multiplayer/Highlander.cfg Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Scripts/Multiplayer/Highlander.cfg Tue Apr 02 21:00:57 2013 +0200 @@ -1,2 +1,2 @@ Default -Default +locked diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Scripts/Multiplayer/Highlander.lua --- a/share/hedgewars/Data/Scripts/Multiplayer/Highlander.lua Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Scripts/Multiplayer/Highlander.lua Tue Apr 02 21:00:57 2013 +0200 @@ -1,6 +1,6 @@ -------------------------------- -- HIGHLANDER / HOGS OF WAR --- version 0.3c +-- version 0.4 -- by mikade -------------------------------- @@ -51,6 +51,37 @@ -- added napalm (whoops) to list of possible weapons you can get -- hogs no longer recieve airstrike-related weps on border maps +----------- +--0.4 +----------- +-- fix same name/blank weapon transfer bug (issue 541) +-- show next hog ammo set in full (issue 312) +-- allow mid-kill multi-shot weapon transfers (issue 503) +-- allow users to configure hog health +-- remove 'switched to' message +-- remove some extraeneous code +-- add more whitespace +-- break everything + +------------------------- +-- ideas for the future +------------------------- +-- add ice gun, structure +-- allow switcher, resurrector +-- add abuse +-- nerf teleport +-- allow more customization +-- poison hogs using the default team? :/ +-- balance weapon distribution across entire team / all teams +-- add other inequalities/bonuses like... ??? +-- some hogs start off with an extra 25 health? +-- some hogs start off poisoned? +-- some hogs start off with a rope and 2 drills but die after their turn? + +------------------------------- +-- derp, script follows +------------------------------- + HedgewarsScriptLoad("/Scripts/Locale.lua") HedgewarsScriptLoad("/Scripts/Tracker.lua") @@ -77,18 +108,42 @@ local wepArray = {} -local currName -local lastName +local currHog +local lastHog local started = false local switchStage = 0 +local lastWep = amNothing +local shotsFired = 0 + +function CheckForWeaponSwap() + if GetCurAmmoType() ~= lastWep then + shotsFired = 0 + end + lastWep = GetCurAmmoType() +end + +function onSlot() + CheckForWeaponSwap() +end + +function onSetWeapon() + CheckForWeaponSwap() +end + +function onHogAttack() + CheckForWeaponSwap() + shotsFired = shotsFired + 1 +end + function StartingSetUp(gear) for i = 1, #wepArray do setGearValue(gear,wepArray[i],0) end - setGearValue(gear,amKamikaze,1) + setGearValue(gear,amKamikaze,100) + setGearValue(gear,amSkip,100) i = 1 + GetRandom(#atkArray) setGearValue(gear,atkArray[i],1) @@ -96,13 +151,11 @@ i = 1 + GetRandom(#utilArray) setGearValue(gear,utilArray[i],1) - SetHealth(gear, 100) - end --[[function SaveWeapons(gear) +-- er, this has no 0 check so presumably if you use a weapon then when it saves you wont have it - - for i = 1, (#wepArray) do setGearValue(gear, wepArray[i], GetAmmoCount(gear, wepArray[i]) ) --AddAmmo(gear, wepArray[i], getGearValue(gear,wepArray[i]) ) @@ -116,10 +169,9 @@ AddAmmo(gear, wepArray[i], getGearValue(gear,wepArray[i]) ) end - end - +-- this is called when a hog dies function TransferWeps(gear) if CurrentHedgehog ~= nil then @@ -127,8 +179,17 @@ for i = 1, #wepArray do val = getGearValue(gear,wepArray[i]) if val ~= 0 then + setGearValue(CurrentHedgehog, wepArray[i], val) - AddAmmo(CurrentHedgehog, wepArray[i], val) + + -- if you are using multi-shot weapon, gimme one more + if (GetCurAmmoType() == wepArray[i]) and (shotsFired ~= 0) then + AddAmmo(CurrentHedgehog, wepArray[i], val+1) + -- assign ammo as per normal + else + AddAmmo(CurrentHedgehog, wepArray[i], val) + end + end end @@ -137,13 +198,12 @@ end function onGameInit() - GameFlags = gfInfAttack + gfRandomOrder + GameFlags = bor(GameFlags,gfInfAttack + gfRandomOrder + gfPerHogAmmo) HealthCaseProb = 100 end function onGameStart() - ShowMission ( loc("HIGHLANDER"), loc("Not all hogs are born equal."), @@ -156,10 +216,10 @@ ) if MapHasBorder() == false then - for i, w in pairs(airWeapons) do + for i, w in pairs(airWeapons) do table.insert(atkArray, w) end - end + end for i, w in pairs(atkArray) do table.insert(wepArray, w) @@ -169,33 +229,52 @@ table.insert(wepArray, w) end + table.insert(wepArray, amSkip) + table.insert(wepArray, amKamikaze) + runOnGears(StartingSetUp) runOnGears(ConvertValues) end ---function onNewTurn() --- ---end - - -function onGameTick20() +function CheckForHogSwitch() if (CurrentHedgehog ~= nil) then - currName = GetHogName(CurrentHedgehog) + currHog = CurrentHedgehog + + if currHog ~= lastHog then - if (currName ~= lastName) then - AddCaption(loc("Switched to ") .. currName .. "!") + -- re-assign ammo to this guy, so that his entire ammo set will + -- be visible during another player's turn + if lastHog ~= nil then + ConvertValues(lastHog) + end + + -- give the new hog what he is supposed to have, too ConvertValues(CurrentHedgehog) + end - lastName = currName + lastHog = currHog + end end +function onNewTurn() + CheckForHogSwitch() +end + +--function onGameTick20() +--CheckForHogSwitch() +-- if we use gfPerHogAmmo is this even needed? Err, well, weapons reset, so... yes? +-- orrrr, should we rather call the re-assignment of weapons onNewTurn()? probably not because +-- then you cant switch hogs... unless we add a thing in onSwitch or whatever +-- ye, that is probably better actually, but I'll add that when/if I add switch +--end + --[[function onHogHide(gear) -- waiting for Henek end @@ -226,8 +305,6 @@ end function onAmmoStoreInit() - SetAmmo(amSkip, 9, 0, 0, 0) - SetAmmo(amKamikaze, 9, 0, 0, 0) - --SetAmmo(amSwitch, 9, 0, 0, 0) -------1 + -- no, you can't set your own ammo scheme end diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/Themes/Brick/theme.cfg --- a/share/hedgewars/Data/Themes/Brick/theme.cfg Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/Themes/Brick/theme.cfg Tue Apr 02 21:00:57 2013 +0200 @@ -18,4 +18,4 @@ spray = spray2, 2 spray = spray3, 2 ;Should this theme have flakes? they where disabled -;flakes = 20, 30, 50, 50, 250 +flakes = 2, 0, 0, 15, 3000 diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/misc/CMakeLists.txt diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/misc/hedgewars-mimeinfo.xml --- a/share/hedgewars/Data/misc/hedgewars-mimeinfo.xml Wed Feb 20 02:21:58 2013 +0100 +++ b/share/hedgewars/Data/misc/hedgewars-mimeinfo.xml Tue Apr 02 21:00:57 2013 +0200 @@ -45,4 +45,14 @@ + + + + Hedgewars ServerAccess Scheme + + + + + + diff -r 404ddce27b23 -r c13ebed437cb share/hedgewars/Data/misc/hedgewars.desktop --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/hedgewars/Data/misc/hedgewars.desktop Tue Apr 02 21:00:57 2013 +0200 @@ -0,0 +1,24 @@ +[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 %U +Terminal=false +StartupNotify=false +Categories=Application;Game;StrategyGame; +MimeType=x-scheme-handler/hwplay diff -r 404ddce27b23 -r c13ebed437cb tools/CMakeLists.txt --- a/tools/CMakeLists.txt Wed Feb 20 02:21:58 2013 +0100 +++ b/tools/CMakeLists.txt Tue Apr 02 21:00:57 2013 +0200 @@ -13,10 +13,9 @@ find_package(SDL_net REQUIRED) find_package(SDL_ttf REQUIRED) find_package(SDL_mixer REQUIRED) - find_package(OGGVORBIS REQUIRED) + find_package(OggVorbis REQUIRED) if(NOT NOAUTOUPDATE) - #needed for SPARKLE_FOUND variable - find_package(Sparkle QUIET) + find_package(Sparkle) #needed for SPARKLE_FOUND variable #needed because the 'if' clause in the script prints silly policy warnings if(${SPARKLE_FOUND}) set(SPARKLE_FOUND 1) diff -r 404ddce27b23 -r c13ebed437cb tools/CreateMacBundle.cmake.in --- a/tools/CreateMacBundle.cmake.in Wed Feb 20 02:21:58 2013 +0100 +++ b/tools/CreateMacBundle.cmake.in Tue Apr 02 21:00:57 2013 +0200 @@ -7,9 +7,9 @@ if(NOT ${NOVIDEOREC}) # but macdeployqt will not work for 'hwengine'; luckily the dylibs were already updated before - execute_process(COMMAND install_name_tool -change ${FFMPEG_LIBAVCODEC} @executable_path/../Frameworks/libavcodec.dylib ${engine_full_path}) - execute_process(COMMAND install_name_tool -change ${FFMPEG_LIBAVFORMAT} @executable_path/../Frameworks/libavformat.dylib ${engine_full_path}) - execute_process(COMMAND install_name_tool -change ${FFMPEG_LIBAVUTIL} @executable_path/../Frameworks/libavutil.dylib ${engine_full_path}) + execute_process(COMMAND install_name_tool -change ${LIBAVCODEC_LIBRARY} @executable_path/../Frameworks/libavcodec.dylib ${engine_full_path}) + execute_process(COMMAND install_name_tool -change ${LIBAVFORMAT_LIBRARY} @executable_path/../Frameworks/libavformat.dylib ${engine_full_path}) + execute_process(COMMAND install_name_tool -change ${LIBAVUTIL_LIBRARY} @executable_path/../Frameworks/libavutil.dylib ${engine_full_path}) endif() if(NOT ${NOPNG}) diff -r 404ddce27b23 -r c13ebed437cb tools/build_windows.bat --- a/tools/build_windows.bat Wed Feb 20 02:21:58 2013 +0100 +++ b/tools/build_windows.bat Tue Apr 02 21:00:57 2013 +0200 @@ -39,7 +39,7 @@ echo Running cmake... set ERRORLEVEL= -cmake -G "MinGW Makefiles" -DPNG_LIBRARY="%CD%\misc\winutils\bin\libpng13.dll" . -DCMAKE_BUILD_TYPE=%BUILD_TYPE% +cmake . -G "MinGW Makefiles" -DCMAKE_PREFIX_PATH="%CD%\misc\winutils\" -DPNG_LIBRARY="%CD%\misc\winutils\bin\libpng13.dll" -DCMAKE_BUILD_TYPE="%BUILD_TYPE%" if %ERRORLEVEL% NEQ 0 goto exitpoint