mirror of
https://github.com/love2d/love-android.git
synced 2026-08-19 20:20:25 +02:00
updated physfs to inofficial 2.1 version
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
repo: 7672c9962ce627edaaa67ff54fe4ad8f9a46dc2b
|
||||
node: aae614cdd00544e929bef29249aef979b8a076b8
|
||||
branch: default
|
||||
latesttag: release-2.0.0
|
||||
latesttagdistance: 291
|
||||
@@ -0,0 +1,2 @@
|
||||
syntax:glob
|
||||
cmake-build
|
||||
@@ -0,0 +1,14 @@
|
||||
0bb92a5f0fffd2452cc737346e8b796c213a5688 release-0.1.1
|
||||
2f2afcbd8abd784f738ac45b0368044763d63748 release-0.1.0
|
||||
3c7cf50a58fbf220154acd4bdfdf00a21f259eb7 release-0.1.8
|
||||
473b50402f55b2340fc286775d1b78d18a810362 release-0.1.3
|
||||
60b5f566a2585d78b2ffadd8d9c16299d0340820 release-1.0.0
|
||||
67aff4091bf129f7167ed87f937b15f31093e19e release-0.1.9
|
||||
6ad1722bbcaec1265cb74c9b7be13fe02a547d37 release-0.1.7
|
||||
8f3ccaaea1cd5dc19235882494d6102e5e9176fb release-0.1.2
|
||||
c966316c89981bea6ccaa2c2909bb303bfeeb82b release-0.1.6
|
||||
d2f04ab4b4127757234af6b30bfc98ad4ee9cb15 release-0.1.4
|
||||
d94f1ccac8095509c57ad640d54796aea0d260f0 release-0.1.5
|
||||
fe0c1d6f40afa6fca09a277a1ade59231f16c66f release-1.1.1
|
||||
5d70fca3be361258edfb59c3edaba5abe75a1e88 release-2.0.0
|
||||
df04959950eb3830c39adfa983789f70f86062d7 release-1.1.0
|
||||
@@ -0,0 +1,32 @@
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
# libogg
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := libphysfs
|
||||
LOCAL_CFLAGS := -fexceptions -g -Dlinux -Dunix \
|
||||
-DPHYSFS_NO_CDROM_SUPPORT=1 \
|
||||
-DHAVE_GCC_DESTRUCTOR=1 -DOPT_GENERIC -DREAL_IS_FLOAT \
|
||||
-DPHYSFS_SUPPORTS_ZIP=1 -DPHYSFS_SUPPORTS_7Z=1 \
|
||||
-DPHYSFS_SUPPORTS_GRP=1 -DPHYSFS_SUPPORTS_QPAK=1 \
|
||||
-DPHYSFS_SUPPORTS_HOG=1 -DPHYSFS_SUPPORTS_MVL=1 \
|
||||
-DPHYSFS_SUPPORTS_WAD=1
|
||||
|
||||
LOCAL_CPPFLAGS := ${LOCAL_CFLAGS}
|
||||
|
||||
LOCAL_C_INCLUDES := \
|
||||
${LOCAL_PATH}/src
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
$(filter-out \
|
||||
, $(subst $(LOCAL_PATH)/,,\
|
||||
${LOCAL_PATH}/src/lzma/C/7zCrc.c \
|
||||
${LOCAL_PATH}/src/lzma/C/Compress/Lzma/LzmaDecode.c \
|
||||
$(wildcard ${LOCAL_PATH}/src/*.c) \
|
||||
$(wildcard ${LOCAL_PATH}/src/lzma/C/Archive/7z/*.c) \
|
||||
$(wildcard ${LOCAL_PATH}/src/lzma/C/Compress/Branch/*.c)))
|
||||
|
||||
# $(info libphysfs: include dirs $(LOCAL_C_INCLUDES))
|
||||
# $(info libphysfs: src files $(LOCAL_SRC_FILES))
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
@@ -0,0 +1,400 @@
|
||||
# PhysicsFS; a portable, flexible file i/o abstraction.
|
||||
#
|
||||
# Please see the file LICENSE.txt in the source's root directory.
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.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()
|
||||
|
||||
# Bleh, let's do it for "APPLE" too.
|
||||
if(APPLE AND NOT MACOSX)
|
||||
set(MACOSX TRUE)
|
||||
endif()
|
||||
|
||||
# For now, Haiku and BeOS are the same, as far as the build system cares.
|
||||
if(HAIKU AND NOT BEOS)
|
||||
set(BEOS TRUE)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
|
||||
set(SOLARIS TRUE)
|
||||
endif()
|
||||
|
||||
include(CheckIncludeFile)
|
||||
include(CheckLibraryExists)
|
||||
include(CheckCSourceCompiles)
|
||||
|
||||
include_directories(./src)
|
||||
|
||||
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()
|
||||
|
||||
# Need these everywhere...
|
||||
add_definitions(-fno-common)
|
||||
set(OTHER_LDFLAGS ${OTHER_LDFLAGS} "-framework Carbon -framework IOKit")
|
||||
endif()
|
||||
|
||||
# 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()
|
||||
|
||||
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()
|
||||
endif()
|
||||
|
||||
# Don't use -rpath.
|
||||
set(CMAKE_SKIP_RPATH ON CACHE BOOL "Skip RPATH" FORCE)
|
||||
endif()
|
||||
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "SunPro")
|
||||
add_definitions(-erroff=E_EMPTY_TRANSLATION_UNIT)
|
||||
add_definitions(-xldscope=hidden)
|
||||
endif()
|
||||
|
||||
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()
|
||||
|
||||
# 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()
|
||||
|
||||
# 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_slb.c
|
||||
src/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()
|
||||
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()
|
||||
|
||||
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()
|
||||
|
||||
# !!! 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 <stdio.h>
|
||||
#include <sys/mnttab.h>
|
||||
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()
|
||||
|
||||
check_include_file(pthread.h HAVE_PTHREAD_H)
|
||||
if(HAVE_PTHREAD_H)
|
||||
set(PHYSFS_HAVE_THREAD_SUPPORT TRUE)
|
||||
find_library(PTHREAD_LIBRARY pthread)
|
||||
if(PTHREAD_LIBRARY)
|
||||
set(OPTIONAL_LIBRARY_LIBS ${OPTIONAL_LIBRARY_LIBS} ${PTHREAD_LIBRARY})
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WINDOWS)
|
||||
set(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
|
||||
set(PHYSFS_HAVE_THREAD_SUPPORT TRUE)
|
||||
endif()
|
||||
|
||||
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()
|
||||
|
||||
if(PHYSFS_HAVE_THREAD_SUPPORT)
|
||||
add_definitions(-D_REENTRANT -D_THREAD_SAFE)
|
||||
else()
|
||||
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()
|
||||
|
||||
|
||||
# Archivers ...
|
||||
|
||||
option(PHYSFS_ARCHIVE_ZIP "Enable ZIP support" TRUE)
|
||||
if(PHYSFS_ARCHIVE_ZIP)
|
||||
add_definitions(-DPHYSFS_SUPPORTS_ZIP=1)
|
||||
endif()
|
||||
|
||||
option(PHYSFS_ARCHIVE_7Z "Enable 7zip support" TRUE)
|
||||
if(PHYSFS_ARCHIVE_7Z)
|
||||
add_definitions(-DPHYSFS_SUPPORTS_7Z=1)
|
||||
# !!! FIXME: rename to 7z.c?
|
||||
set(PHYSFS_SRCS ${PHYSFS_SRCS} ${LZMA_SRCS})
|
||||
endif()
|
||||
|
||||
option(PHYSFS_ARCHIVE_GRP "Enable Build Engine GRP support" TRUE)
|
||||
if(PHYSFS_ARCHIVE_GRP)
|
||||
add_definitions(-DPHYSFS_SUPPORTS_GRP=1)
|
||||
endif()
|
||||
|
||||
option(PHYSFS_ARCHIVE_WAD "Enable Doom WAD support" TRUE)
|
||||
if(PHYSFS_ARCHIVE_WAD)
|
||||
add_definitions(-DPHYSFS_SUPPORTS_WAD=1)
|
||||
endif()
|
||||
|
||||
option(PHYSFS_ARCHIVE_HOG "Enable Descent I/II HOG support" TRUE)
|
||||
if(PHYSFS_ARCHIVE_HOG)
|
||||
add_definitions(-DPHYSFS_SUPPORTS_HOG=1)
|
||||
endif()
|
||||
|
||||
option(PHYSFS_ARCHIVE_MVL "Enable Descent I/II MVL support" TRUE)
|
||||
if(PHYSFS_ARCHIVE_MVL)
|
||||
add_definitions(-DPHYSFS_SUPPORTS_MVL=1)
|
||||
endif()
|
||||
|
||||
option(PHYSFS_ARCHIVE_QPAK "Enable Quake I/II QPAK support" TRUE)
|
||||
if(PHYSFS_ARCHIVE_QPAK)
|
||||
add_definitions(-DPHYSFS_SUPPORTS_QPAK=1)
|
||||
endif()
|
||||
|
||||
option(PHYSFS_ARCHIVE_SLB "Enable I-War / Independence War SLB support" TRUE)
|
||||
if(PHYSFS_ARCHIVE_SLB)
|
||||
add_definitions(-DPHYSFS_SUPPORTS_SLB=1)
|
||||
endif()
|
||||
|
||||
option(PHYSFS_ARCHIVE_ISO9660 "Enable ISO9660 support" TRUE)
|
||||
if(PHYSFS_ARCHIVE_ISO9660)
|
||||
add_definitions(-DPHYSFS_SUPPORTS_ISO9660=1)
|
||||
endif()
|
||||
|
||||
|
||||
option(PHYSFS_BUILD_STATIC "Build static library" TRUE)
|
||||
if(PHYSFS_BUILD_STATIC)
|
||||
add_library(physfs-static STATIC ${PHYSFS_SRCS})
|
||||
set_target_properties(physfs-static PROPERTIES OUTPUT_NAME "physfs")
|
||||
set(PHYSFS_LIB_TARGET physfs-static)
|
||||
set(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";physfs-static")
|
||||
endif()
|
||||
|
||||
option(PHYSFS_BUILD_SHARED "Build shared library" TRUE)
|
||||
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})
|
||||
set(PHYSFS_LIB_TARGET physfs)
|
||||
set(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";physfs")
|
||||
endif()
|
||||
|
||||
if(NOT PHYSFS_BUILD_SHARED AND NOT PHYSFS_BUILD_STATIC)
|
||||
message(FATAL "Both shared and static libraries are disabled!")
|
||||
endif()
|
||||
|
||||
# CMake FAQ says I need this...
|
||||
if(PHYSFS_BUILD_SHARED AND PHYSFS_BUILD_STATIC)
|
||||
set_target_properties(physfs PROPERTIES CLEAN_DIRECT_OUTPUT 1)
|
||||
set_target_properties(physfs-static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
|
||||
endif()
|
||||
|
||||
option(PHYSFS_BUILD_TEST "Build stdio test program." TRUE)
|
||||
mark_as_advanced(PHYSFS_BUILD_TEST)
|
||||
if(PHYSFS_BUILD_TEST)
|
||||
find_path(READLINE_H readline/readline.h)
|
||||
find_path(HISTORY_H readline/history.h)
|
||||
if(READLINE_H AND HISTORY_H)
|
||||
find_library(CURSES_LIBRARY NAMES curses ncurses)
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${CURSES_LIBRARY})
|
||||
find_library(READLINE_LIBRARY readline)
|
||||
if(READLINE_LIBRARY)
|
||||
set(HAVE_SYSTEM_READLINE TRUE)
|
||||
set(TEST_PHYSFS_LIBS ${TEST_PHYSFS_LIBS} ${READLINE_LIBRARY} ${CURSES_LIBRARY})
|
||||
include_directories(${READLINE_H} ${HISTORY_H})
|
||||
add_definitions(-DPHYSFS_HAVE_READLINE=1)
|
||||
endif()
|
||||
endif()
|
||||
add_executable(test_physfs test/test_physfs.c)
|
||||
target_link_libraries(test_physfs ${PHYSFS_LIB_TARGET} ${TEST_PHYSFS_LIBS} ${OTHER_LDFLAGS})
|
||||
set(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";test_physfs")
|
||||
endif()
|
||||
|
||||
install(TARGETS ${PHYSFS_INSTALL_TARGETS}
|
||||
RUNTIME DESTINATION bin
|
||||
LIBRARY DESTINATION lib${LIB_SUFFIX}
|
||||
ARCHIVE DESTINATION lib${LIB_SUFFIX})
|
||||
install(FILES src/physfs.h DESTINATION include)
|
||||
|
||||
find_package(Doxygen)
|
||||
if(DOXYGEN_FOUND)
|
||||
set(PHYSFS_OUTPUT_DOXYFILE "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile")
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile"
|
||||
"${PHYSFS_OUTPUT_DOXYFILE}"
|
||||
COPYONLY
|
||||
)
|
||||
file(APPEND "${PHYSFS_OUTPUT_DOXYFILE}" "\n\n# Below auto-generated by cmake...\n\n")
|
||||
file(APPEND "${PHYSFS_OUTPUT_DOXYFILE}" "PROJECT_NUMBER = \"${PHYSFS_VERSION}\"\n")
|
||||
file(APPEND "${PHYSFS_OUTPUT_DOXYFILE}" "OUTPUT_DIRECTORY = \"${CMAKE_CURRENT_BINARY_DIR}/docs\"\n")
|
||||
file(APPEND "${PHYSFS_OUTPUT_DOXYFILE}" "\n# End auto-generated section.\n\n")
|
||||
|
||||
add_custom_target(
|
||||
docs
|
||||
${DOXYGEN_EXECUTABLE} "${PHYSFS_OUTPUT_DOXYFILE}"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
COMMENT "Building documentation in 'docs' directory..."
|
||||
)
|
||||
else()
|
||||
message(STATUS "Doxygen not found. You won't be able to build documentation.")
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
set(PHYSFS_TARBALL "${CMAKE_CURRENT_SOURCE_DIR}/../physfs-${PHYSFS_VERSION}.tar.bz2")
|
||||
add_custom_target(
|
||||
dist
|
||||
hg archive -t tbz2 "${PHYSFS_TARBALL}"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
COMMENT "Building source tarball '${PHYSFS_TARBALL}'..."
|
||||
)
|
||||
add_custom_target(
|
||||
uninstall
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/extras/uninstall.sh"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
COMMENT "Uninstall the project..."
|
||||
)
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
configure_file(
|
||||
"extras/physfs.pc.in"
|
||||
"extras/physfs.pc"
|
||||
@ONLY
|
||||
)
|
||||
install(
|
||||
FILES "${CMAKE_CURRENT_BINARY_DIR}/extras/physfs.pc"
|
||||
DESTINATION "lib/pkgconfig"
|
||||
)
|
||||
endif()
|
||||
|
||||
macro(message_bool_option _NAME _VALUE)
|
||||
if(${_VALUE})
|
||||
message(STATUS " ${_NAME}: enabled")
|
||||
else()
|
||||
message(STATUS " ${_NAME}: disabled")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
message(STATUS "PhysicsFS will build with the following options:")
|
||||
message_bool_option("ZIP support" PHYSFS_ARCHIVE_ZIP)
|
||||
message_bool_option("7zip support" PHYSFS_ARCHIVE_7Z)
|
||||
message_bool_option("GRP support" PHYSFS_ARCHIVE_GRP)
|
||||
message_bool_option("WAD support" PHYSFS_ARCHIVE_WAD)
|
||||
message_bool_option("HOG support" PHYSFS_ARCHIVE_HOG)
|
||||
message_bool_option("MVL support" PHYSFS_ARCHIVE_MVL)
|
||||
message_bool_option("QPAK support" PHYSFS_ARCHIVE_QPAK)
|
||||
message_bool_option("SLB support" PHYSFS_ARCHIVE_SLB)
|
||||
message_bool_option("CD-ROM drive support" PHYSFS_HAVE_CDROM_SUPPORT)
|
||||
message_bool_option("Thread safety" PHYSFS_HAVE_THREAD_SUPPORT)
|
||||
message_bool_option("Build static library" PHYSFS_BUILD_STATIC)
|
||||
message_bool_option("Build shared library" PHYSFS_BUILD_SHARED)
|
||||
message_bool_option("Build stdio test program" PHYSFS_BUILD_TEST)
|
||||
if(PHYSFS_BUILD_TEST)
|
||||
message_bool_option(" Use readline in test program" HAVE_SYSTEM_READLINE)
|
||||
endif()
|
||||
|
||||
# end of CMakeLists.txt ...
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
|
||||
Copyright (c) 2001-2011 Ryan C. Gordon and others.
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from
|
||||
the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software in a
|
||||
product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Ryan C. Gordon <icculus@icculus.org>
|
||||
|
||||
|
||||
|
||||
|
||||
Notes, separate from the license. This is not legal advice.
|
||||
|
||||
Versions of PhysicsFS prior to 0.1.9 are licensed under the GNU Lesser General
|
||||
Public License, which restricts you significantly more. For your own safety,
|
||||
please make sure you've got 0.1.9 or later if you plan to use physfs in a
|
||||
commercial or closed-source project.
|
||||
|
||||
Optional pieces of PhysicsFS may fall under other licenses, please consult
|
||||
your lawyer for legal advice, which this is not...
|
||||
|
||||
lzma: if you enable LZMA (7zip) support, PhysicsFS uses the lzma sdk.
|
||||
It uses the LGPL license, with exceptions for closed-source programs.
|
||||
Please see lzma/lzma.txt for details.
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
PhysicsFS; a portable, flexible file i/o abstraction.
|
||||
|
||||
http://icculus.org/physfs/
|
||||
|
||||
Please see the docs directory for documentation, licensing, and information.
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
|
||||
The changelog is no longer maintained by hand. It made sense to have a single
|
||||
timeline when we were using CVS, but modern revision control tools make this
|
||||
redundant, at best.
|
||||
|
||||
If you want a list of changes, updated in real time, just point your web
|
||||
browser here:
|
||||
|
||||
http://hg.icculus.org/icculus/physfs/
|
||||
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
Maintainer and general codemonkey:
|
||||
Ryan C. Gordon
|
||||
|
||||
Tons of win32 help:
|
||||
Adam Gates
|
||||
|
||||
More win32 hacking:
|
||||
Gregory S. Read
|
||||
|
||||
Fixes for missing current working directories,
|
||||
PHYSFS_setSaneConfig() improvements,
|
||||
other bugfixes:
|
||||
David Hedbor
|
||||
|
||||
Darwin support:
|
||||
Patrick Stein
|
||||
|
||||
configure fixes,
|
||||
RPM specfile:
|
||||
Edward Rudd
|
||||
|
||||
GetLastModTime API,
|
||||
other stuff:
|
||||
John R. Hall
|
||||
|
||||
Various support, fixes and suggestions:
|
||||
Alexander Pipelka
|
||||
|
||||
Russian translation,
|
||||
QPAK archiver:
|
||||
Ed Sinjiashvili
|
||||
|
||||
French translation:
|
||||
Stéphane Peter
|
||||
|
||||
Debian package support:
|
||||
Colin Bayer
|
||||
|
||||
"abs-file.h" in "extras" dir:
|
||||
Adam D. Moss
|
||||
|
||||
WinCE port and other Win32 patches:
|
||||
Corona688
|
||||
|
||||
German translation:
|
||||
Michael Renner
|
||||
|
||||
Apple Project Builder support,
|
||||
Mac OS X improvements:
|
||||
Eric Wing
|
||||
|
||||
iPhone support:
|
||||
Christian Gmeiner
|
||||
|
||||
HOG archiver,
|
||||
MVL archiver:
|
||||
Bradley Bell
|
||||
|
||||
MIX archiver:
|
||||
Sebastian Steinhauer
|
||||
|
||||
Bug fixes:
|
||||
Tolga Dalman
|
||||
|
||||
Initial PHYSFS_mount() work:
|
||||
Philip D. Bober
|
||||
|
||||
Brazillian Portuguese translation:
|
||||
Danny Angelo Carminati Grein
|
||||
|
||||
Spanish translation:
|
||||
Pedro J. Pérez
|
||||
|
||||
MacOS Classic fixes,
|
||||
MPW support,
|
||||
bug fixes:
|
||||
Chris Taylor
|
||||
|
||||
Mingw support,
|
||||
General bug fixes:
|
||||
Matze Braun
|
||||
|
||||
Haiku support:
|
||||
scott mc
|
||||
|
||||
Bug fixes:
|
||||
Jörg Walter
|
||||
|
||||
Bug fixes:
|
||||
Olivier Boudeville
|
||||
|
||||
Bug fixes:
|
||||
Henk Boom
|
||||
|
||||
Build system fixes:
|
||||
Marc Kleine-Budde
|
||||
|
||||
Windows .rc file,
|
||||
7zip/lzma archiver:
|
||||
Dennis Schridde
|
||||
|
||||
OS/2 updates:
|
||||
Dave Yeo
|
||||
|
||||
Bug fixes:
|
||||
Patrice Mandin
|
||||
|
||||
PHYSFS_stat() API:
|
||||
Christoph Nelles
|
||||
Indy Sams
|
||||
|
||||
ISO9660 archiver:
|
||||
Christoph Nelles
|
||||
|
||||
Bug fixes:
|
||||
Steven Fuller
|
||||
|
||||
Bug fixes:
|
||||
Tolga Dalman
|
||||
|
||||
Bug fixes:
|
||||
Frank Becker
|
||||
|
||||
Bug fixes:
|
||||
Norfanin
|
||||
|
||||
Bug fixes:
|
||||
Evgeny Podjachev
|
||||
|
||||
Haiku fixes:
|
||||
Chris Roberts
|
||||
|
||||
SLB archiver:
|
||||
Aleksi Nurmi
|
||||
|
||||
Bug fixes:
|
||||
Dmitry Marakasov
|
||||
|
||||
Bug fixes:
|
||||
Andreas Karlsson
|
||||
|
||||
pkg-config support:
|
||||
Jonas Kulla
|
||||
|
||||
Other stuff:
|
||||
Your name here! Patches go to icculus@icculus.org ...
|
||||
|
||||
/* end of CREDITS.txt ... */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,152 @@
|
||||
|
||||
The latest PhysicsFS information and releases can be found at:
|
||||
http://icculus.org/physfs/
|
||||
|
||||
Building is (ahem) very easy.
|
||||
|
||||
|
||||
ALL PLATFORMS:
|
||||
|
||||
Please understand your rights and mine: read the text file LICENSE.txt in the
|
||||
root of the source tree. If you can't abide by it, delete this source tree
|
||||
now. The license is extremely liberal, even to closed-source, commercial
|
||||
applications.
|
||||
|
||||
If you've got Doxygen (http://www.doxygen.org/) installed, you can run it
|
||||
without any command line arguments in the root of the source tree to generate
|
||||
the API reference (or build the "docs" target from your build system). This
|
||||
is optional. You can browse the API docs online here:
|
||||
|
||||
http://icculus.org/physfs/docs/
|
||||
|
||||
|
||||
|
||||
|
||||
UNIX:
|
||||
|
||||
You will need CMake (http://www.cmake.org/) 2.4 or later installed.
|
||||
|
||||
Make a directory, wherever you like. This will be your build directory.
|
||||
|
||||
Chdir to your build directory. Run "cmake /where/i/unpacked/physfs" to
|
||||
generate Makefiles. You can then run "ccmake ." and customize the build,
|
||||
but the defaults are probably okay. You can have CMake generate KDevelop
|
||||
project files if you prefer these.
|
||||
|
||||
Run "make". PhysicsFS will now build.
|
||||
|
||||
As root, run "make install".
|
||||
If you get sick of the library, run "xargs rm < install_manifest.txt" as root
|
||||
and it will remove all traces of the library from the system paths.
|
||||
|
||||
Once you are satisfied, you can delete the build directory.
|
||||
|
||||
Primary Unix development is done with GNU/Linux, but PhysicsFS is known to
|
||||
work out of the box with several flavors of Unix. It it doesn't work, patches
|
||||
to get it running can be sent to icculus@icculus.org.
|
||||
|
||||
|
||||
|
||||
BeOS, Zeta, and Haiku:
|
||||
|
||||
Use the "Unix" instructions, above. The CMake port to BeOS is fairly new at
|
||||
the time of this writing, but it works. You can get a build of CMake from
|
||||
bebits.com or build it yourself from source from cmake.org.
|
||||
|
||||
|
||||
|
||||
Windows:
|
||||
|
||||
If building with Cygwin, mingw32, MSYS, or something else that uses the GNU
|
||||
toolchain, follow the Unix instructions, above.
|
||||
|
||||
If you want to use Visual Studio, nmake, or the Platform SDK, you will need
|
||||
CMake (http://www.cmake.org/) 2.4 or later installed. Point CMake at the
|
||||
CMakeLists.txt file in the root of the source directory and hit the
|
||||
"Configure" button. After telling it what type of compiler you are targeting
|
||||
(Borland, Visual Studio, etc), CMake will process for while and then give you
|
||||
a list of options you can change (what archivers you want to support, etc).
|
||||
If you aren't sure, the defaults are probably fine. Hit the "Configure"
|
||||
button again, then "OK" once configuration has completed with options that
|
||||
match your liking. Now project files for your favorite programming
|
||||
environment will be generated for you in the directory you specified.
|
||||
Go there and use them to build PhysicsFS.
|
||||
|
||||
PhysicsFS will only link directly against system libraries that have existed
|
||||
since Windows 95 and Windows NT 3.51. If there's a newer API we want to use,
|
||||
we try to dynamically load it at runtime and fallback to a reasonable
|
||||
behaviour when we can't find it...this is used for Unicode support and
|
||||
locating user-specific directories, etc.
|
||||
|
||||
PhysicsFS works on 32-bit and 64-bit Windows. There is no 16-bit Windows
|
||||
support at all. Reports of success and problems can go to Ryan at
|
||||
icculus@icculus.org ...
|
||||
|
||||
If someone is willing to maintain prebuilt PhysicsFS DLLs, I'd like to hear
|
||||
from you; send an email to icculus@icculus.org ...
|
||||
|
||||
|
||||
PocketPC/WindowsCE:
|
||||
|
||||
Support for PocketPC was removed in PhysicsFS 2.1.0. This was known to work
|
||||
in the 1.0 releases, but wasn't tested in 2.0 and later. PhysicsFS is not
|
||||
known to work on Windows Phone 7 (the latest Microsoft mobile tech at the
|
||||
time of this writing).
|
||||
|
||||
|
||||
MAC OS 8/9:
|
||||
|
||||
Classic Mac OS support has been dropped in PhysicsFS 2.0. Apple hasn't updated
|
||||
pre-OSX versions in more than a decade at this point, none of the hardware
|
||||
they've shipped will boot it for almost as many years, and finding
|
||||
developer tools for it is becoming almost impossible. As the switch to Intel
|
||||
hardware has removed the "Classic" emulation environment, it was time to
|
||||
remove support from PhysicsFS. That being said, the PhysicsFS 1.0 branch can
|
||||
still target back to Mac OS 8.5, so you can use that if you need support for
|
||||
this legacy OS. We still very much support Mac OS X, though: see below.
|
||||
|
||||
|
||||
|
||||
MAC OS X:
|
||||
|
||||
You will need CMake (http://www.cmake.org/) 2.4 or later installed.
|
||||
|
||||
You can either generate a Unix makefile with CMake, or generate an Xcode
|
||||
project, whichever makes you more comfortable.
|
||||
|
||||
PowerPC and Intel Macs should both be supported.
|
||||
|
||||
If someone is willing to maintain prebuilt PhysicsFS Shared Libraries for
|
||||
Mac OS X, I'd like to hear from you; send an email to icculus@icculus.org.
|
||||
|
||||
|
||||
|
||||
OS/2:
|
||||
|
||||
You need Innotek GCC and libc installed (or kLIBC). I tried this on a stock
|
||||
Warp 4 install, no fixpaks. You need to install link386.exe (Selective
|
||||
Install, "link object modules" option). Once klibc and GCC are installed
|
||||
correctly, unpack the source to PhysicsFS and run the script
|
||||
file "makeos2.cmd". I know this isn't ideal, but I wanted to have this build
|
||||
without users having to hunt down a "make" program.
|
||||
|
||||
Someone please port CMake to OS/2. Ideally I'd like to be able to target
|
||||
Innotek GCC and OpenWatcom with CMake.
|
||||
|
||||
If someone is willing to maintain prebuilt PhysicsFS Shared Libraries for
|
||||
OS/2, I'd like to hear from you; send an email to icculus@icculus.org.
|
||||
|
||||
|
||||
|
||||
OTHER PLATFORMS:
|
||||
|
||||
Many Unix-like platforms might "just work" with CMake. Some of these platforms
|
||||
are known to have worked at one time, but have not been heavily tested, if
|
||||
tested at all. PhysicsFS is, as far as we know, 64-bit and byteorder clean,
|
||||
and is known to compile on several compilers across many platforms. To
|
||||
implement a new platform or archiver, please read the heavily-commented
|
||||
physfs_internal.h and look in the platform/ and archiver/ directories for
|
||||
examples.
|
||||
|
||||
--ryan. (icculus@icculus.org)
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
Stuff that needs to be done and wishlist:
|
||||
|
||||
These are in no particular order.
|
||||
Some might be dupes, some might be done already, some might be bad ideas.
|
||||
|
||||
|
||||
From http://icculus.org/pipermail/physfs/2009-March/000698.html ...
|
||||
|
||||
- Archives formats provided by the implementation.
|
||||
- Write support for various archives. I haven't decided how to do this yet,
|
||||
but I'd like to.
|
||||
- Add an API to expose a file's extended attributes to the application?
|
||||
- Deprecate PHYSFS_setSaneConfig(). It really should have been in the extras
|
||||
directory.
|
||||
- Clean up the sources to match my ever-changing coding style. :)
|
||||
|
||||
|
||||
From http://icculus.org/pipermail/physfs/2010-January/000821.html ...
|
||||
|
||||
- Plugin system for the archive handlers
|
||||
|
||||
|
||||
From http://icculus.org/pipermail/physfs/2010-January/000826.html ...
|
||||
|
||||
- Lua bindings
|
||||
|
||||
|
||||
From http://icculus.org/pipermail/physfs/2010-January/000833.html ...
|
||||
|
||||
- SWIG bindings
|
||||
|
||||
|
||||
|
||||
From old TODO.txt...
|
||||
|
||||
- Other archivers: perhaps tar(.gz|.bz2), RPM, ARJ, etc. These are less
|
||||
important, since streaming archives aren't of much value to games (which
|
||||
is why zipfiles are king: random access), but it could have uses for, say,
|
||||
an installer/updater.
|
||||
- profile string list interpolation.
|
||||
- We have two different ways to find dir entries in zip.c.
|
||||
- Do symlinks in zip archiver work when they point to dirs?
|
||||
- Enable more warnings?
|
||||
- Use __cdecl in physfs.h?
|
||||
- Look for FIXMEs (many marked with "!!!" in comments).
|
||||
- Find some way to relax or remove the security model for external tools.
|
||||
- fscanf and fprintf support in extras dir.
|
||||
- Sanity check byte order at runtime.
|
||||
- Memory locking?
|
||||
- General code audit.
|
||||
- Multiple write dirs with mount points?
|
||||
- Replace code from SDL...
|
||||
- Should file enumeration return an error or set error state?
|
||||
- Write up a simple HOWTO on embedding physicsfs in another project.
|
||||
|
||||
|
||||
Other stuff I thought of...
|
||||
- moar asserts!
|
||||
- constify!
|
||||
- Does iPhone work?
|
||||
- Fix CMake vs Doxygen.
|
||||
- Doxygen replacement? (manpages suck.)
|
||||
- Fix coding standards to match.
|
||||
- See if we can ditch some #include lines...
|
||||
- We lost Vista symlink support when removing isSymLink(). Pull it back from
|
||||
revision control.
|
||||
- PHYSFS_exists() fails if you mountIo with a NULL filename. We need to decide
|
||||
how this API should work.
|
||||
- ZIP64 support?
|
||||
- LZMA support in zip archiver?
|
||||
- bzip2 support in zip archiver?
|
||||
- rewrite 7zip archiver.
|
||||
- ryanify iso9660 code.
|
||||
- Reduce the BAIL and GOTO macro use. A lot of these don't add anything.
|
||||
- Modernize CMakeLists.txt
|
||||
- Change the term "search path" to something less confusing.
|
||||
|
||||
Probably other stuff. Requests and recommendations are welcome.
|
||||
|
||||
// end of TODO.txt ...
|
||||
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
//
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
//
|
||||
[assembly: AssemblyTitle("PhysFS.NET")]
|
||||
[assembly: AssemblyDescription("PhysFS Bindings for .NET")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("PhysFS.NET")]
|
||||
[assembly: AssemblyCopyright("(c)2003 Gregory S. Read")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
//
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Revision and Build Numbers
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
//
|
||||
// In order to sign your assembly you must specify a key to use. Refer to the
|
||||
// Microsoft .NET Framework documentation for more information on assembly signing.
|
||||
//
|
||||
// Use the attributes below to control which key is used for signing.
|
||||
//
|
||||
// Notes:
|
||||
// (*) If no key is specified, the assembly is not signed.
|
||||
// (*) KeyName refers to a key that has been installed in the Crypto Service
|
||||
// Provider (CSP) on your machine. KeyFile refers to a file which contains
|
||||
// a key.
|
||||
// (*) If the KeyFile and the KeyName values are both specified, the
|
||||
// following processing occurs:
|
||||
// (1) If the KeyName can be found in the CSP, that key is used.
|
||||
// (2) If the KeyName does not exist and the KeyFile does exist, the key
|
||||
// in the KeyFile is installed into the CSP and used.
|
||||
// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
|
||||
// When specifying the KeyFile, the location of the KeyFile should be
|
||||
// relative to the project output directory which is
|
||||
// %Project Directory%\obj\<configuration>. For example, if your KeyFile is
|
||||
// located in the project directory, you would specify the AssemblyKeyFile
|
||||
// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
|
||||
// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
|
||||
// documentation for more information on this.
|
||||
//
|
||||
[assembly: AssemblyDelaySign(false)]
|
||||
[assembly: AssemblyKeyFile("")]
|
||||
[assembly: AssemblyKeyName("")]
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
<VisualStudioProject>
|
||||
<CSHARP
|
||||
ProjectType = "Local"
|
||||
ProductVersion = "7.0.9466"
|
||||
SchemaVersion = "1.0"
|
||||
ProjectGuid = "{C6205A43-3D4D-41E6-872C-96CD7BE55230}"
|
||||
>
|
||||
<Build>
|
||||
<Settings
|
||||
ApplicationIcon = ""
|
||||
AssemblyKeyContainerName = ""
|
||||
AssemblyName = "PhysFS.NET"
|
||||
AssemblyOriginatorKeyFile = ""
|
||||
DefaultClientScript = "JScript"
|
||||
DefaultHTMLPageLayout = "Grid"
|
||||
DefaultTargetSchema = "IE50"
|
||||
DelaySign = "false"
|
||||
OutputType = "Library"
|
||||
RootNamespace = "PhysFS.NET"
|
||||
StartupObject = ""
|
||||
>
|
||||
<Config
|
||||
Name = "Debug"
|
||||
AllowUnsafeBlocks = "true"
|
||||
BaseAddress = "285212672"
|
||||
CheckForOverflowUnderflow = "false"
|
||||
ConfigurationOverrideFile = ""
|
||||
DefineConstants = "DEBUG;TRACE"
|
||||
DocumentationFile = ""
|
||||
DebugSymbols = "true"
|
||||
FileAlignment = "4096"
|
||||
IncrementalBuild = "true"
|
||||
Optimize = "false"
|
||||
OutputPath = "bin\Debug\"
|
||||
RegisterForComInterop = "false"
|
||||
RemoveIntegerChecks = "false"
|
||||
TreatWarningsAsErrors = "false"
|
||||
WarningLevel = "4"
|
||||
/>
|
||||
<Config
|
||||
Name = "Release"
|
||||
AllowUnsafeBlocks = "true"
|
||||
BaseAddress = "285212672"
|
||||
CheckForOverflowUnderflow = "false"
|
||||
ConfigurationOverrideFile = ""
|
||||
DefineConstants = "TRACE"
|
||||
DocumentationFile = ""
|
||||
DebugSymbols = "false"
|
||||
FileAlignment = "4096"
|
||||
IncrementalBuild = "false"
|
||||
Optimize = "true"
|
||||
OutputPath = "bin\Release\"
|
||||
RegisterForComInterop = "false"
|
||||
RemoveIntegerChecks = "false"
|
||||
TreatWarningsAsErrors = "false"
|
||||
WarningLevel = "4"
|
||||
/>
|
||||
</Settings>
|
||||
<References>
|
||||
<Reference
|
||||
Name = "System"
|
||||
AssemblyName = "System"
|
||||
HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.dll"
|
||||
/>
|
||||
<Reference
|
||||
Name = "System.Data"
|
||||
AssemblyName = "System.Data"
|
||||
HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Data.dll"
|
||||
/>
|
||||
<Reference
|
||||
Name = "System.XML"
|
||||
AssemblyName = "System.Xml"
|
||||
HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.XML.dll"
|
||||
/>
|
||||
<Reference
|
||||
Name = "System.Drawing"
|
||||
AssemblyName = "System.Drawing"
|
||||
HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Drawing.dll"
|
||||
/>
|
||||
<Reference
|
||||
Name = "System.Windows.Forms"
|
||||
AssemblyName = "System.Windows.Forms"
|
||||
HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Windows.Forms.dll"
|
||||
/>
|
||||
</References>
|
||||
</Build>
|
||||
<Files>
|
||||
<Include>
|
||||
<File
|
||||
RelPath = "AssemblyInfo.cs"
|
||||
SubType = "Code"
|
||||
BuildAction = "Compile"
|
||||
/>
|
||||
<File
|
||||
RelPath = "PhysFS.cs"
|
||||
SubType = "Code"
|
||||
BuildAction = "Compile"
|
||||
/>
|
||||
<File
|
||||
RelPath = "PhysFS_DLL.cs"
|
||||
SubType = "Code"
|
||||
BuildAction = "Compile"
|
||||
/>
|
||||
<File
|
||||
RelPath = "PhysFSFileStream.cs"
|
||||
SubType = "Code"
|
||||
BuildAction = "Compile"
|
||||
/>
|
||||
</Include>
|
||||
</Files>
|
||||
</CSHARP>
|
||||
</VisualStudioProject>
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 7.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhysFS.NET", "PhysFS.NET.csproj", "{C6205A43-3D4D-41E6-872C-96CD7BE55230}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfiguration) = preSolution
|
||||
ConfigName.0 = Debug
|
||||
ConfigName.1 = Release
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectDependencies) = postSolution
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfiguration) = postSolution
|
||||
{C6205A43-3D4D-41E6-872C-96CD7BE55230}.Debug.ActiveCfg = Debug|.NET
|
||||
{C6205A43-3D4D-41E6-872C-96CD7BE55230}.Debug.Build.0 = Debug|.NET
|
||||
{C6205A43-3D4D-41E6-872C-96CD7BE55230}.Release.ActiveCfg = Release|.NET
|
||||
{C6205A43-3D4D-41E6-872C-96CD7BE55230}.Release.Build.0 = Release|.NET
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityAddIns) = postSolution
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
Executable
+189
@@ -0,0 +1,189 @@
|
||||
/* PhysFS.cs - (c)2003 Gregory S. Read
|
||||
* Provides access to PhysFS API calls not specific to file handle access.
|
||||
*/
|
||||
using System;
|
||||
|
||||
namespace PhysFS_NET
|
||||
{
|
||||
public class PhysFS
|
||||
{
|
||||
/* Initialize
|
||||
* Inits the PhysFS API. This normally does not need to be called unless
|
||||
* the API has been manually deinitialized since the PhysFS_DLL class
|
||||
* initializes just before the first call is made into the DLL.
|
||||
* Parameters
|
||||
* none
|
||||
* Returns
|
||||
* none
|
||||
* Exceptions
|
||||
* PhysFSException - An error occured in the PhysFS API
|
||||
*/
|
||||
public static void Initialize()
|
||||
{
|
||||
// Initialize the physfs library, raise an exception if error
|
||||
if(PhysFS_DLL.PHYSFS_init("") == 0)
|
||||
throw new PhysFSException();
|
||||
}
|
||||
|
||||
/* Deinitialize
|
||||
* Deinits the PhysFS API. It is recommended that this method be called
|
||||
* by the application before exiting in order to gracefully deallocate
|
||||
* resources and close all filehandles, etc.
|
||||
* Parameters
|
||||
* none
|
||||
* Returns
|
||||
* none
|
||||
* Exceptions
|
||||
* PhysFSException - An error occured in the PhysFS API
|
||||
*/
|
||||
public static void Deinitialize()
|
||||
{
|
||||
// Deinit, raise an exception if an error occured
|
||||
if(PhysFS_DLL.PHYSFS_deinit() == 0)
|
||||
throw new PhysFSException();
|
||||
}
|
||||
|
||||
/* BaseDir
|
||||
* Gets the base directory configured for PhysFS. See the PhysFS API
|
||||
* documentation for more information.
|
||||
* Parameters
|
||||
* none
|
||||
* Returns
|
||||
* A string value representing the Base Directory
|
||||
* Exceptions
|
||||
* none
|
||||
*/
|
||||
public static string BaseDir
|
||||
{
|
||||
get
|
||||
{
|
||||
// Return the current base directory
|
||||
return PhysFS_DLL.PHYSFS_getBaseDir();
|
||||
}
|
||||
}
|
||||
|
||||
/* WriteDir
|
||||
* Gets or sets the write directory configured for PhysFS. See the PhysFS API
|
||||
* documentation for more information.
|
||||
* Parameters
|
||||
* set - Path to set the WriteDir property to
|
||||
* Returns
|
||||
* A string value representing the Write Directory
|
||||
* Exceptions
|
||||
* PhysFSException - An error occured in the PhysFS API when
|
||||
* settings the write directory.
|
||||
*/
|
||||
public static string WriteDir
|
||||
{
|
||||
get
|
||||
{
|
||||
// Return the current write directory
|
||||
return PhysFS_DLL.PHYSFS_getWriteDir();
|
||||
}
|
||||
set
|
||||
{
|
||||
// Set the write directory and raise an exception if an error occured
|
||||
if(PhysFS_DLL.PHYSFS_setWriteDir(value) == 0)
|
||||
throw new PhysFSException();
|
||||
}
|
||||
}
|
||||
|
||||
/* UserDir
|
||||
* Gets or sets the write directory configured for PhysFS. See the PhysFS API
|
||||
* documentation for more information.
|
||||
* Parameters
|
||||
* set - Path to set the WriteDir property to
|
||||
* Returns
|
||||
* A string value representing the Write Directory
|
||||
* Exceptions
|
||||
* PhysFSException - An error occured in the PhysFS API when
|
||||
* settings the write directory.
|
||||
*/
|
||||
public static string UserDir
|
||||
{
|
||||
get
|
||||
{
|
||||
// Return the current user directory
|
||||
return PhysFS_DLL.PHYSFS_getUserDir();
|
||||
}
|
||||
}
|
||||
public static void AddToSearchPath(string NewDir, bool Append)
|
||||
{
|
||||
if(PhysFS_DLL.PHYSFS_addToSearchPath(NewDir, Append?1:0) == 0)
|
||||
throw new PhysFSException();
|
||||
}
|
||||
public static void RemoveFromSearchPath(string OldDir)
|
||||
{
|
||||
if(PhysFS_DLL.PHYSFS_removeFromSearchPath(OldDir) == 0)
|
||||
throw new PhysFSException();
|
||||
}
|
||||
public unsafe static string[] GetSearchPath()
|
||||
{
|
||||
byte** p; // Searchpath list from PhysFS dll
|
||||
string[] pathlist; // List converted to an array
|
||||
|
||||
// Get the CDROM drive listing
|
||||
p = PhysFS_DLL.PHYSFS_getSearchPath();
|
||||
// Convert the C-style array to a .NET style array
|
||||
pathlist = PhysFS_DLL.BytePPToArray(p);
|
||||
// Free the original list since we're done with it
|
||||
PhysFS_DLL.PHYSFS_freeList(p);
|
||||
|
||||
return pathlist;
|
||||
}
|
||||
public unsafe static string[] GetCDROMDrives()
|
||||
{
|
||||
byte** p; // CDROM list from PhysFS dll
|
||||
string[] cdromlist; // List converted to an array
|
||||
|
||||
// Get the CDROM drive listing
|
||||
p = PhysFS_DLL.PHYSFS_getCdRomDirs();
|
||||
// Convert the C-style array to a .NET style array
|
||||
cdromlist = PhysFS_DLL.BytePPToArray(p);
|
||||
// Free the original list since we're done with it
|
||||
PhysFS_DLL.PHYSFS_freeList(p);
|
||||
|
||||
return cdromlist;
|
||||
}
|
||||
public static void MkDir(string Dirname)
|
||||
{
|
||||
if(PhysFS_DLL.PHYSFS_mkdir(Dirname) == 0)
|
||||
throw new PhysFSException();
|
||||
}
|
||||
public static void Delete(string Filename)
|
||||
{
|
||||
if(PhysFS_DLL.PHYSFS_delete(Filename) == 0)
|
||||
throw new PhysFSException();
|
||||
}
|
||||
public static string GetRealDir(string Filename)
|
||||
{
|
||||
string RetValue;
|
||||
|
||||
RetValue = PhysFS_DLL.PHYSFS_getRealDir(Filename);
|
||||
if(RetValue == null)
|
||||
throw new PhysFSException("File not found in search path.");
|
||||
|
||||
// Return the real file path of the specified filename
|
||||
return RetValue;
|
||||
}
|
||||
public unsafe static string[] EnumerateFiles(string Dirname)
|
||||
{
|
||||
byte** p; // File list from PhysFS dll
|
||||
string[] filelist; // List converted to an array
|
||||
|
||||
// Get the CDROM drive listing
|
||||
p = PhysFS_DLL.PHYSFS_enumerateFiles(Dirname);
|
||||
// Convert the C-style array to a .NET style array
|
||||
filelist = PhysFS_DLL.BytePPToArray(p);
|
||||
// Free the original list since we're done with it
|
||||
PhysFS_DLL.PHYSFS_freeList(p);
|
||||
|
||||
return filelist;
|
||||
}
|
||||
public static bool IsDirectory(string Filename)
|
||||
{
|
||||
// Return true if non-zero, otherwise return false
|
||||
return (PhysFS_DLL.PHYSFS_isDirectory(Filename) == 0)?false:true;
|
||||
}
|
||||
}
|
||||
}
|
||||
+194
@@ -0,0 +1,194 @@
|
||||
/* PhysFSFileStream.cs - (c)2003 Gregory S. Read */
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
|
||||
namespace PhysFS_NET
|
||||
{
|
||||
public enum PhysFSFileMode {Read, Write, Append};
|
||||
|
||||
// Our exception class we'll use for throwing all PhysFS API related exception
|
||||
public class PhysFSException : IOException
|
||||
{
|
||||
public PhysFSException(string Message) : base(Message) {}
|
||||
public PhysFSException() : base(PhysFS_DLL.PHYSFS_getLastError()) {}
|
||||
}
|
||||
|
||||
public unsafe class PhysFSFileStream : Stream
|
||||
{
|
||||
// ***Public properties***
|
||||
public override bool CanRead
|
||||
{
|
||||
get
|
||||
{
|
||||
// Reading is supported
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanSeek
|
||||
{
|
||||
get
|
||||
{
|
||||
// Seek is supported
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanWrite
|
||||
{
|
||||
get
|
||||
{
|
||||
// Writing is supported
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
long TempLength;
|
||||
TempLength = PhysFS_DLL.PHYSFS_fileLength(pHandle);
|
||||
|
||||
// If call returned an error, throw an exception
|
||||
if(TempLength == -1)
|
||||
throw new PhysFSException();
|
||||
|
||||
return TempLength;
|
||||
}
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
long TempPosition;
|
||||
TempPosition = PhysFS_DLL.PHYSFS_tell(pHandle);
|
||||
|
||||
// If call returned an error, throw an exception
|
||||
if(TempPosition == -1)
|
||||
throw new PhysFSException();
|
||||
|
||||
return TempPosition;
|
||||
}
|
||||
set
|
||||
{
|
||||
// Seek from beginning of file using the position value
|
||||
Seek(value, SeekOrigin.Begin);
|
||||
}
|
||||
}
|
||||
|
||||
// ***Public methods***
|
||||
public PhysFSFileStream(string FileName, PhysFSFileMode FileMode, ulong BufferSize)
|
||||
{
|
||||
// Open the specified file with the appropriate file access
|
||||
switch(FileMode)
|
||||
{
|
||||
case PhysFSFileMode.Read:
|
||||
pHandle = PhysFS_DLL.PHYSFS_openRead(FileName);
|
||||
break;
|
||||
case PhysFSFileMode.Write:
|
||||
pHandle = PhysFS_DLL.PHYSFS_openWrite(FileName);
|
||||
break;
|
||||
case PhysFSFileMode.Append:
|
||||
pHandle = PhysFS_DLL.PHYSFS_openAppend(FileName);
|
||||
break;
|
||||
default:
|
||||
throw new PhysFSException("Invalid FileMode specified");
|
||||
}
|
||||
|
||||
// If handle is null, an error occured, so raise an exception
|
||||
//!!! Does object get created if exception is thrown?
|
||||
if(pHandle == null)
|
||||
throw new PhysFSException();
|
||||
|
||||
// Set buffer size, raise an exception if an error occured
|
||||
if(PhysFS_DLL.PHYSFS_setBuffer(pHandle, BufferSize) == 0)
|
||||
throw new PhysFSException();
|
||||
}
|
||||
|
||||
// This constructor sets the buffer size to 0 if not specified
|
||||
public PhysFSFileStream(string FileName, PhysFSFileMode FileMode) : this(FileName, FileMode, 0) {}
|
||||
|
||||
~PhysFSFileStream()
|
||||
{
|
||||
// Don't close the handle if they've specifically closed it already
|
||||
if(!Closed)
|
||||
Close();
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
if(PhysFS_DLL.PHYSFS_flush(pHandle) == 0)
|
||||
throw new PhysFSException();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
long RetValue;
|
||||
|
||||
fixed(byte *pbytes = &buffer[offset])
|
||||
{
|
||||
// Read into our allocated pointer
|
||||
RetValue = PhysFS_DLL.PHYSFS_read(pHandle, pbytes, sizeof(byte), (uint)count);
|
||||
}
|
||||
|
||||
if(RetValue == -1)
|
||||
throw new PhysFSException();
|
||||
|
||||
// Return number of bytes read
|
||||
// Note: This cast should be safe since we are only reading 'count' items, which
|
||||
// is of type 'int'.
|
||||
return (int)RetValue;
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
long RetValue;
|
||||
|
||||
fixed(byte* pbytes = &buffer[offset])
|
||||
{
|
||||
// Write buffer
|
||||
RetValue = PhysFS_DLL.PHYSFS_write(pHandle, pbytes, sizeof(byte), (uint)count);
|
||||
}
|
||||
|
||||
if(RetValue == -1)
|
||||
throw new PhysFSException();
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
// Only seeking from beginning is supported by PhysFS API
|
||||
if(origin != SeekOrigin.Begin)
|
||||
throw new PhysFSException("Only seek origin of \"Begin\" is supported");
|
||||
|
||||
// Seek to specified offset, raise an exception if error occured
|
||||
if(PhysFS_DLL.PHYSFS_seek(pHandle, (ulong)offset) == 0)
|
||||
throw new PhysFSException();
|
||||
|
||||
// Since we always seek from beginning, the offset is always
|
||||
// the absolute position.
|
||||
return offset;
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException("SetLength method not supported in PhysFSFileStream objects.");
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
// Close the handle
|
||||
if(PhysFS_DLL.PHYSFS_close(pHandle) == 0)
|
||||
throw new PhysFSException();
|
||||
|
||||
// File has been closed. Rock.
|
||||
Closed = true;
|
||||
}
|
||||
|
||||
// ***Private variables***
|
||||
private void *pHandle;
|
||||
private bool Closed = false;
|
||||
}
|
||||
}
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
/* PhysFS_DLL - (c)2003 Gregory S. Read
|
||||
* Internal class that provides direct access to the PhysFS DLL. It is
|
||||
* not accessible outside of the PhysFS.NET assembly.
|
||||
*/
|
||||
using System.Collections;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace PhysFS_NET
|
||||
{
|
||||
internal class PhysFS_DLL
|
||||
{
|
||||
/* Static constructor
|
||||
* Initializes the PhysFS API before any method is called in this class. This
|
||||
* relieves the user from having to explicitly initialize the API.
|
||||
* Parameters
|
||||
* none
|
||||
* Returns
|
||||
* none
|
||||
* Exceptions
|
||||
* PhysFSException - An error occured in the PhysFS API
|
||||
*/
|
||||
static PhysFS_DLL()
|
||||
{
|
||||
if(PHYSFS_init("") == 0)
|
||||
throw new PhysFSException();
|
||||
}
|
||||
|
||||
/* BytePPToArray
|
||||
* Converts a C-style string array into a .NET managed string array
|
||||
* Parameters
|
||||
* C-style string array pointer returned from PhysFS
|
||||
* Returns
|
||||
* .NET managed string array
|
||||
* Exceptions
|
||||
* none
|
||||
*/
|
||||
public unsafe static string[] BytePPToArray(byte **bytearray)
|
||||
{
|
||||
byte** ptr;
|
||||
byte* c;
|
||||
string tempstr;
|
||||
ArrayList MyArrayList = new ArrayList();
|
||||
string[] RetArray;
|
||||
|
||||
for(ptr = bytearray; *ptr != null; ptr++)
|
||||
{
|
||||
tempstr = "";
|
||||
for(c = *ptr; *c != 0; c++)
|
||||
{
|
||||
tempstr += (char)*c;
|
||||
}
|
||||
|
||||
// Add string to our list
|
||||
MyArrayList.Add(tempstr);
|
||||
}
|
||||
|
||||
// Return a normal array of the list
|
||||
RetArray = new string[MyArrayList.Count];
|
||||
MyArrayList.CopyTo(RetArray, 0);
|
||||
return RetArray;
|
||||
}
|
||||
|
||||
// Name of DLL to import
|
||||
private const string PHYSFS_DLLNAME = "physfs.dll";
|
||||
|
||||
// DLL import declarations
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern int PHYSFS_init(string argv0);
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern int PHYSFS_deinit();
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern unsafe void PHYSFS_freeList(void *listVar);
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern string PHYSFS_getLastError();
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern string PHYSFS_getDirSeparator();
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern void PHYSFS_permitSymbolicLinks(int allow);
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern unsafe byte** PHYSFS_getCdRomDirs();
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern string PHYSFS_getBaseDir();
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern string PHYSFS_getUserDir();
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern string PHYSFS_getWriteDir();
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern int PHYSFS_setWriteDir(string newDir);
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern int PHYSFS_addToSearchPath(string newDir, int appendToPath);
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern int PHYSFS_removeFromSearchPath(string oldDir);
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern unsafe byte** PHYSFS_getSearchPath();
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern int PHYSFS_setSaneConfig(string organization,
|
||||
string appName,
|
||||
string archiveExt,
|
||||
int includeCdRoms,
|
||||
int archivesFirst);
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern int PHYSFS_mkdir(string dirName);
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern int PHYSFS_delete(string filename);
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern string PHYSFS_getRealDir(string filename);
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern unsafe byte** PHYSFS_enumerateFiles(string dir);
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern int PHYSFS_exists(string fname);
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern int PHYSFS_isDirectory(string fname);
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern int PHYSFS_isSymbolicLink(string fname);
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern unsafe void* PHYSFS_openWrite(string filename);
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern unsafe void* PHYSFS_openAppend(string filename);
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern unsafe void* PHYSFS_openRead(string filename);
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern unsafe int PHYSFS_close(void* handle);
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern unsafe long PHYSFS_getLastModTime(string filename);
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern unsafe long PHYSFS_read(void* handle,
|
||||
void *buffer,
|
||||
uint objSize,
|
||||
uint objCount);
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern unsafe long PHYSFS_write(void* handle,
|
||||
void *buffer,
|
||||
uint objSize,
|
||||
uint objCount);
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern unsafe int PHYSFS_eof(void* handle);
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern unsafe long PHYSFS_tell(void* handle);
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern unsafe int PHYSFS_seek(void* handle, ulong pos);
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern unsafe long PHYSFS_fileLength(void* handle);
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern unsafe int PHYSFS_setBuffer(void* handle, ulong bufsize);
|
||||
[DllImport(PHYSFS_DLLNAME)] public static extern unsafe int PHYSFS_flush(void* handle);
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
PhysFS.NET is a library that encapsulates the PhysFS API into a .NET assembly.
|
||||
|
||||
There are two class objects that are exposed in the assembly:
|
||||
PhysFS.cs
|
||||
This class exposes any non-filehandle specific functionality contained in
|
||||
the PhysFS library.
|
||||
PhysFSFileStream.cs
|
||||
A System.IO.Stream derived class which provides file access via the
|
||||
PhysFS API. Usage of this object is identical to a standard stream
|
||||
object.
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,58 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
//
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
//
|
||||
[assembly: AssemblyTitle("")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("")]
|
||||
[assembly: AssemblyCopyright("")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
//
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Revision and Build Numbers
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
//
|
||||
// In order to sign your assembly you must specify a key to use. Refer to the
|
||||
// Microsoft .NET Framework documentation for more information on assembly signing.
|
||||
//
|
||||
// Use the attributes below to control which key is used for signing.
|
||||
//
|
||||
// Notes:
|
||||
// (*) If no key is specified, the assembly is not signed.
|
||||
// (*) KeyName refers to a key that has been installed in the Crypto Service
|
||||
// Provider (CSP) on your machine. KeyFile refers to a file which contains
|
||||
// a key.
|
||||
// (*) If the KeyFile and the KeyName values are both specified, the
|
||||
// following processing occurs:
|
||||
// (1) If the KeyName can be found in the CSP, that key is used.
|
||||
// (2) If the KeyName does not exist and the KeyFile does exist, the key
|
||||
// in the KeyFile is installed into the CSP and used.
|
||||
// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
|
||||
// When specifying the KeyFile, the location of the KeyFile should be
|
||||
// relative to the project output directory which is
|
||||
// %Project Directory%\obj\<configuration>. For example, if your KeyFile is
|
||||
// located in the project directory, you would specify the AssemblyKeyFile
|
||||
// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
|
||||
// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
|
||||
// documentation for more information on this.
|
||||
//
|
||||
[assembly: AssemblyDelaySign(false)]
|
||||
[assembly: AssemblyKeyFile("")]
|
||||
[assembly: AssemblyKeyName("")]
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
<VisualStudioProject>
|
||||
<CSHARP
|
||||
ProjectType = "Local"
|
||||
ProductVersion = "7.0.9466"
|
||||
SchemaVersion = "1.0"
|
||||
ProjectGuid = "{9C1ECC6B-16C7-42B3-BF7C-8BA8D81BA980}"
|
||||
>
|
||||
<Build>
|
||||
<Settings
|
||||
ApplicationIcon = "App.ico"
|
||||
AssemblyKeyContainerName = ""
|
||||
AssemblyName = "TestApp"
|
||||
AssemblyOriginatorKeyFile = ""
|
||||
DefaultClientScript = "JScript"
|
||||
DefaultHTMLPageLayout = "Grid"
|
||||
DefaultTargetSchema = "IE50"
|
||||
DelaySign = "false"
|
||||
OutputType = "WinExe"
|
||||
RootNamespace = "TestApp"
|
||||
StartupObject = ""
|
||||
>
|
||||
<Config
|
||||
Name = "Debug"
|
||||
AllowUnsafeBlocks = "false"
|
||||
BaseAddress = "285212672"
|
||||
CheckForOverflowUnderflow = "false"
|
||||
ConfigurationOverrideFile = ""
|
||||
DefineConstants = "DEBUG;TRACE"
|
||||
DocumentationFile = ""
|
||||
DebugSymbols = "true"
|
||||
FileAlignment = "4096"
|
||||
IncrementalBuild = "true"
|
||||
Optimize = "false"
|
||||
OutputPath = "bin\Debug\"
|
||||
RegisterForComInterop = "false"
|
||||
RemoveIntegerChecks = "false"
|
||||
TreatWarningsAsErrors = "false"
|
||||
WarningLevel = "4"
|
||||
/>
|
||||
<Config
|
||||
Name = "Release"
|
||||
AllowUnsafeBlocks = "false"
|
||||
BaseAddress = "285212672"
|
||||
CheckForOverflowUnderflow = "false"
|
||||
ConfigurationOverrideFile = ""
|
||||
DefineConstants = "TRACE"
|
||||
DocumentationFile = ""
|
||||
DebugSymbols = "false"
|
||||
FileAlignment = "4096"
|
||||
IncrementalBuild = "false"
|
||||
Optimize = "true"
|
||||
OutputPath = "bin\Release\"
|
||||
RegisterForComInterop = "false"
|
||||
RemoveIntegerChecks = "false"
|
||||
TreatWarningsAsErrors = "false"
|
||||
WarningLevel = "4"
|
||||
/>
|
||||
</Settings>
|
||||
<References>
|
||||
<Reference
|
||||
Name = "System"
|
||||
AssemblyName = "System"
|
||||
HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.dll"
|
||||
/>
|
||||
<Reference
|
||||
Name = "System.Data"
|
||||
AssemblyName = "System.Data"
|
||||
HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Data.dll"
|
||||
/>
|
||||
<Reference
|
||||
Name = "System.Drawing"
|
||||
AssemblyName = "System.Drawing"
|
||||
HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Drawing.dll"
|
||||
/>
|
||||
<Reference
|
||||
Name = "System.Windows.Forms"
|
||||
AssemblyName = "System.Windows.Forms"
|
||||
HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Windows.Forms.dll"
|
||||
/>
|
||||
<Reference
|
||||
Name = "System.XML"
|
||||
AssemblyName = "System.Xml"
|
||||
HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.XML.dll"
|
||||
/>
|
||||
<Reference
|
||||
Name = "PhysFS.NET"
|
||||
Project = "{C6205A43-3D4D-41E6-872C-96CD7BE55230}"
|
||||
Package = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"
|
||||
/>
|
||||
</References>
|
||||
</Build>
|
||||
<Files>
|
||||
<Include>
|
||||
<File
|
||||
RelPath = "App.ico"
|
||||
BuildAction = "Content"
|
||||
/>
|
||||
<File
|
||||
RelPath = "AssemblyInfo.cs"
|
||||
BuildAction = "Compile"
|
||||
/>
|
||||
<File
|
||||
RelPath = "TestAppForm.cs"
|
||||
SubType = "Form"
|
||||
BuildAction = "Compile"
|
||||
/>
|
||||
<File
|
||||
RelPath = "TestAppForm.resx"
|
||||
DependentUpon = "TestAppForm.cs"
|
||||
BuildAction = "EmbeddedResource"
|
||||
/>
|
||||
</Include>
|
||||
</Files>
|
||||
</CSHARP>
|
||||
</VisualStudioProject>
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 7.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApp", "TestApp.csproj", "{9C1ECC6B-16C7-42B3-BF7C-8BA8D81BA980}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhysFS.NET", "..\PhysFS.NET.csproj", "{C6205A43-3D4D-41E6-872C-96CD7BE55230}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfiguration) = preSolution
|
||||
ConfigName.0 = Debug
|
||||
ConfigName.1 = Release
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectDependencies) = postSolution
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfiguration) = postSolution
|
||||
{9C1ECC6B-16C7-42B3-BF7C-8BA8D81BA980}.Debug.ActiveCfg = Debug|.NET
|
||||
{9C1ECC6B-16C7-42B3-BF7C-8BA8D81BA980}.Debug.Build.0 = Debug|.NET
|
||||
{9C1ECC6B-16C7-42B3-BF7C-8BA8D81BA980}.Release.ActiveCfg = Release|.NET
|
||||
{9C1ECC6B-16C7-42B3-BF7C-8BA8D81BA980}.Release.Build.0 = Release|.NET
|
||||
{C6205A43-3D4D-41E6-872C-96CD7BE55230}.Debug.ActiveCfg = Debug|.NET
|
||||
{C6205A43-3D4D-41E6-872C-96CD7BE55230}.Debug.Build.0 = Debug|.NET
|
||||
{C6205A43-3D4D-41E6-872C-96CD7BE55230}.Release.ActiveCfg = Release|.NET
|
||||
{C6205A43-3D4D-41E6-872C-96CD7BE55230}.Release.Build.0 = Release|.NET
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityAddIns) = postSolution
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
+274
@@ -0,0 +1,274 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Collections;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using PhysFS_NET;
|
||||
|
||||
namespace TestApp
|
||||
{
|
||||
/// <summary>
|
||||
/// Summary description for Form1.
|
||||
/// </summary>
|
||||
public class TestAppForm : System.Windows.Forms.Form
|
||||
{
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.Button RefreshCDsButton;
|
||||
private System.Windows.Forms.ListBox CDDrivesList;
|
||||
private System.Windows.Forms.ListBox SearchPathList;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.TextBox EnumFilesPath;
|
||||
private System.Windows.Forms.ListBox EnumList;
|
||||
private System.Windows.Forms.Label label3;
|
||||
private System.Windows.Forms.TextBox NewSearchPathText;
|
||||
private System.Windows.Forms.Button AddSearchPathButton;
|
||||
private System.Windows.Forms.Button RemovePathButton;
|
||||
private System.Windows.Forms.Button RefreshEnumList;
|
||||
private System.Windows.Forms.Button RefreshSearchPathButton;
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.Container components = null;
|
||||
|
||||
public TestAppForm()
|
||||
{
|
||||
//
|
||||
// Required for Windows Form Designer support
|
||||
//
|
||||
InitializeComponent();
|
||||
|
||||
//
|
||||
// TODO: Add any constructor code after InitializeComponent call
|
||||
//
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
protected override void Dispose( bool disposing )
|
||||
{
|
||||
if( disposing )
|
||||
{
|
||||
if (components != null)
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
}
|
||||
base.Dispose( disposing );
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.RefreshCDsButton = new System.Windows.Forms.Button();
|
||||
this.CDDrivesList = new System.Windows.Forms.ListBox();
|
||||
this.SearchPathList = new System.Windows.Forms.ListBox();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.EnumFilesPath = new System.Windows.Forms.TextBox();
|
||||
this.EnumList = new System.Windows.Forms.ListBox();
|
||||
this.label3 = new System.Windows.Forms.Label();
|
||||
this.RefreshEnumList = new System.Windows.Forms.Button();
|
||||
this.NewSearchPathText = new System.Windows.Forms.TextBox();
|
||||
this.AddSearchPathButton = new System.Windows.Forms.Button();
|
||||
this.RemovePathButton = new System.Windows.Forms.Button();
|
||||
this.RefreshSearchPathButton = new System.Windows.Forms.Button();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.Location = new System.Drawing.Point(8, 8);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(136, 16);
|
||||
this.label2.TabIndex = 2;
|
||||
this.label2.Text = "Available CD-ROM Drives";
|
||||
//
|
||||
// RefreshCDsButton
|
||||
//
|
||||
this.RefreshCDsButton.Location = new System.Drawing.Point(8, 152);
|
||||
this.RefreshCDsButton.Name = "RefreshCDsButton";
|
||||
this.RefreshCDsButton.Size = new System.Drawing.Size(72, 24);
|
||||
this.RefreshCDsButton.TabIndex = 4;
|
||||
this.RefreshCDsButton.Text = "Refresh";
|
||||
this.RefreshCDsButton.Click += new System.EventHandler(this.RefreshCDsButton_Click);
|
||||
//
|
||||
// CDDrivesList
|
||||
//
|
||||
this.CDDrivesList.Location = new System.Drawing.Point(8, 24);
|
||||
this.CDDrivesList.Name = "CDDrivesList";
|
||||
this.CDDrivesList.Size = new System.Drawing.Size(136, 121);
|
||||
this.CDDrivesList.TabIndex = 7;
|
||||
//
|
||||
// SearchPathList
|
||||
//
|
||||
this.SearchPathList.Location = new System.Drawing.Point(152, 24);
|
||||
this.SearchPathList.Name = "SearchPathList";
|
||||
this.SearchPathList.Size = new System.Drawing.Size(248, 95);
|
||||
this.SearchPathList.TabIndex = 8;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.Location = new System.Drawing.Point(152, 8);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(136, 16);
|
||||
this.label1.TabIndex = 10;
|
||||
this.label1.Text = "Search Path";
|
||||
//
|
||||
// EnumFilesPath
|
||||
//
|
||||
this.EnumFilesPath.Location = new System.Drawing.Point(408, 128);
|
||||
this.EnumFilesPath.Name = "EnumFilesPath";
|
||||
this.EnumFilesPath.Size = new System.Drawing.Size(208, 20);
|
||||
this.EnumFilesPath.TabIndex = 11;
|
||||
this.EnumFilesPath.Text = "";
|
||||
//
|
||||
// EnumList
|
||||
//
|
||||
this.EnumList.Location = new System.Drawing.Point(408, 24);
|
||||
this.EnumList.Name = "EnumList";
|
||||
this.EnumList.Size = new System.Drawing.Size(208, 95);
|
||||
this.EnumList.TabIndex = 12;
|
||||
//
|
||||
// label3
|
||||
//
|
||||
this.label3.Location = new System.Drawing.Point(408, 8);
|
||||
this.label3.Name = "label3";
|
||||
this.label3.Size = new System.Drawing.Size(136, 16);
|
||||
this.label3.TabIndex = 13;
|
||||
this.label3.Text = "Enumerate Files";
|
||||
//
|
||||
// RefreshEnumList
|
||||
//
|
||||
this.RefreshEnumList.Location = new System.Drawing.Point(544, 152);
|
||||
this.RefreshEnumList.Name = "RefreshEnumList";
|
||||
this.RefreshEnumList.Size = new System.Drawing.Size(72, 24);
|
||||
this.RefreshEnumList.TabIndex = 14;
|
||||
this.RefreshEnumList.Text = "Refresh";
|
||||
this.RefreshEnumList.Click += new System.EventHandler(this.RefreshEnumList_Click);
|
||||
//
|
||||
// NewSearchPathText
|
||||
//
|
||||
this.NewSearchPathText.Location = new System.Drawing.Point(152, 128);
|
||||
this.NewSearchPathText.Name = "NewSearchPathText";
|
||||
this.NewSearchPathText.Size = new System.Drawing.Size(248, 20);
|
||||
this.NewSearchPathText.TabIndex = 15;
|
||||
this.NewSearchPathText.Text = "";
|
||||
//
|
||||
// AddSearchPathButton
|
||||
//
|
||||
this.AddSearchPathButton.Location = new System.Drawing.Point(152, 152);
|
||||
this.AddSearchPathButton.Name = "AddSearchPathButton";
|
||||
this.AddSearchPathButton.Size = new System.Drawing.Size(72, 24);
|
||||
this.AddSearchPathButton.TabIndex = 9;
|
||||
this.AddSearchPathButton.Text = "Add Path";
|
||||
this.AddSearchPathButton.Click += new System.EventHandler(this.AddSearchPathButton_Click);
|
||||
//
|
||||
// RemovePathButton
|
||||
//
|
||||
this.RemovePathButton.Location = new System.Drawing.Point(232, 152);
|
||||
this.RemovePathButton.Name = "RemovePathButton";
|
||||
this.RemovePathButton.Size = new System.Drawing.Size(88, 24);
|
||||
this.RemovePathButton.TabIndex = 16;
|
||||
this.RemovePathButton.Text = "Remove Path";
|
||||
this.RemovePathButton.Click += new System.EventHandler(this.RemovePathButton_Click);
|
||||
//
|
||||
// RefreshSearchPathButton
|
||||
//
|
||||
this.RefreshSearchPathButton.Location = new System.Drawing.Point(328, 152);
|
||||
this.RefreshSearchPathButton.Name = "RefreshSearchPathButton";
|
||||
this.RefreshSearchPathButton.Size = new System.Drawing.Size(72, 24);
|
||||
this.RefreshSearchPathButton.TabIndex = 17;
|
||||
this.RefreshSearchPathButton.Text = "Refresh";
|
||||
this.RefreshSearchPathButton.Click += new System.EventHandler(this.RefreshSearchPathButton_Click);
|
||||
//
|
||||
// TestAppForm
|
||||
//
|
||||
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
|
||||
this.ClientSize = new System.Drawing.Size(624, 309);
|
||||
this.Controls.AddRange(new System.Windows.Forms.Control[] {
|
||||
this.RefreshSearchPathButton,
|
||||
this.RemovePathButton,
|
||||
this.NewSearchPathText,
|
||||
this.RefreshEnumList,
|
||||
this.label3,
|
||||
this.EnumList,
|
||||
this.EnumFilesPath,
|
||||
this.label1,
|
||||
this.SearchPathList,
|
||||
this.CDDrivesList,
|
||||
this.RefreshCDsButton,
|
||||
this.label2,
|
||||
this.AddSearchPathButton});
|
||||
this.Name = "TestAppForm";
|
||||
this.Text = "PhysFS Test Application";
|
||||
this.Load += new System.EventHandler(this.TestAppForm_Load);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
Application.Run(new TestAppForm());
|
||||
}
|
||||
|
||||
private void TestAppForm_Load(object sender, System.EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void RefreshCDsButton_Click(object sender, System.EventArgs e)
|
||||
{
|
||||
// Clear ths listbox if it contains any items
|
||||
CDDrivesList.Items.Clear();
|
||||
// Add the items to the list
|
||||
CDDrivesList.Items.AddRange(PhysFS.GetCDROMDrives());
|
||||
}
|
||||
|
||||
private void RefreshSearchPathButton_Click(object sender, System.EventArgs e)
|
||||
{
|
||||
// Clear ths listbox if it contains any items
|
||||
SearchPathList.Items.Clear();
|
||||
// Add the items to the list
|
||||
SearchPathList.Items.AddRange(PhysFS.GetSearchPath());
|
||||
}
|
||||
|
||||
private void AddSearchPathButton_Click(object sender, System.EventArgs e)
|
||||
{
|
||||
// Add search path
|
||||
PhysFS.AddToSearchPath(NewSearchPathText.Text, false);
|
||||
// Clear ths listbox if it contains any items
|
||||
SearchPathList.Items.Clear();
|
||||
// Add the items to the list
|
||||
SearchPathList.Items.AddRange(PhysFS.GetSearchPath());
|
||||
}
|
||||
|
||||
private void RemovePathButton_Click(object sender, System.EventArgs e)
|
||||
{
|
||||
if(SearchPathList.SelectedItem != null)
|
||||
{
|
||||
PhysFS.RemoveFromSearchPath(SearchPathList.SelectedItem.ToString());
|
||||
// Clear ths listbox if it contains any items
|
||||
SearchPathList.Items.Clear();
|
||||
// Add the items to the list
|
||||
SearchPathList.Items.AddRange(PhysFS.GetSearchPath());
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshEnumList_Click(object sender, System.EventArgs e)
|
||||
{
|
||||
EnumList.Items.Clear();
|
||||
EnumList.Items.AddRange(PhysFS.EnumerateFiles(EnumFilesPath.Text));
|
||||
}
|
||||
}
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 1.3
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">1.3</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1">this is my long string</data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
[base64 mime encoded serialized .NET Framework object]
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
[base64 mime encoded string representing a byte array form of the .NET Framework object]
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>1.3</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="$this.Name">
|
||||
<value>TestAppForm</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* stdio/physfs abstraction layer 2003-04-02
|
||||
*
|
||||
* Adam D. Moss <adam@gimp.org> <aspirin@icculus.org>
|
||||
*
|
||||
* These wrapper macros and functions are designed to allow a program
|
||||
* to perform file I/O with identical semantics and syntax regardless
|
||||
* of whether PhysicsFS is being used or not.
|
||||
*/
|
||||
#ifndef _ABS_FILE_H
|
||||
#define _ABS_FILE_H
|
||||
/*
|
||||
PLEASE NOTE: This license applies to abs-file.h ONLY (to make it clear that
|
||||
you may embed this wrapper code within commercial software); PhysicsFS itself
|
||||
is (at the time of writing) released under a different license with
|
||||
additional restrictions.
|
||||
|
||||
Copyright (C) 2002-2003 Adam D. Moss (the "Author"). All Rights Reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is fur-
|
||||
nished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
|
||||
NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON-
|
||||
NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of the Author of the
|
||||
Software shall not be used in advertising or otherwise to promote the sale,
|
||||
use or other dealings in this Software without prior written authorization
|
||||
from the Author.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
* API:
|
||||
*
|
||||
* Macro/function use like stdio equivalent...
|
||||
* -------------- ----------------------------
|
||||
* MY_FILETYPE FILE
|
||||
* MY_OPEN_FOR_READ fopen(..., "rb")
|
||||
* MY_READ fread(...)
|
||||
* MY_CLOSE fclose(...)
|
||||
* MY_GETC fgetc(...)
|
||||
* MY_GETS fgets(...)
|
||||
* MY_ATEOF feof(...)
|
||||
* MY_TELL ftell(...)
|
||||
* MY_SEEK fseek(..., SEEK_SET)
|
||||
* MY_REWIND rewind(...)
|
||||
* MY_SETBUFFER (not a standard for stdio, does nothing there)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Important DEFINEs:
|
||||
* It is important to define these consistantly across the various
|
||||
* compilation modules of your program if you wish to exchange file
|
||||
* handles between them.
|
||||
*
|
||||
* USE_PHYSFS: Define USE_PHYSFS if PhysicsFS is being used; note that if
|
||||
* you do intend to use PhysicsFS then you will still need to initialize
|
||||
* PhysicsFS yourself and set up its search-paths.
|
||||
*
|
||||
* Optional DEFINEs:
|
||||
*
|
||||
* PHYSFS_DEFAULT_READ_BUFFER <bytes>: If set then abs-file.h sets the
|
||||
* PhysicsFS buffer size to this value whenever you open a file. You
|
||||
* may over-ride this on a per-filehandle basis by using the
|
||||
* MY_SETBUFFER() macro (which simply does nothing when not using
|
||||
* PhysicsFS). If you have not defined this value explicitly then
|
||||
* abs-file.h will default to the same default buffer size as used by
|
||||
* stdio if it can be determined, or 8192 bytes otherwise.
|
||||
*/
|
||||
#ifndef PHYSFS_DEFAULT_READ_BUFFER
|
||||
#ifdef BUFSIZ
|
||||
#define PHYSFS_DEFAULT_READ_BUFFER BUFSIZ
|
||||
#else
|
||||
#define PHYSFS_DEFAULT_READ_BUFFER 8192
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_PHYSFS
|
||||
|
||||
#include <physfs.h>
|
||||
#define MY_FILETYPE PHYSFS_File
|
||||
#define MY_SETBUFFER(fp,size) PHYSFS_setBuffer(fp,size)
|
||||
#define MY_READ(p,s,n,fp) PHYSFS_read(fp,p,s,n)
|
||||
#if PHYSFS_DEFAULT_READ_BUFFER
|
||||
static MY_FILETYPE* MY_OPEN_FOR_READ(const char *const filename)
|
||||
{
|
||||
MY_FILETYPE *const file = PHYSFS_openRead(filename);
|
||||
if (file) {
|
||||
MY_SETBUFFER(file, PHYSFS_DEFAULT_READ_BUFFER);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
#else
|
||||
#define MY_OPEN_FOR_READ(fn) PHYSFS_openRead(fn)
|
||||
#endif
|
||||
static int MY_GETC(MY_FILETYPE *const fp) {
|
||||
unsigned char c;
|
||||
/*if (PHYSFS_eof(fp)) {
|
||||
return EOF;
|
||||
}
|
||||
MY_READ(&c, 1, 1, fp);*/
|
||||
if (MY_READ(&c, 1, 1, fp) != 1) {
|
||||
return EOF;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
static char * MY_GETS(char * const str, const int size,
|
||||
MY_FILETYPE *const fp) {
|
||||
int i = 0;
|
||||
int c;
|
||||
do {
|
||||
if (i == size-1) {
|
||||
break;
|
||||
}
|
||||
c = MY_GETC(fp);
|
||||
if (c == EOF) {
|
||||
break;
|
||||
}
|
||||
str[i++] = c;
|
||||
} while (c != '\0' &&
|
||||
c != -1 &&
|
||||
c != '\n');
|
||||
str[i] = '\0';
|
||||
if (i == 0) {
|
||||
return NULL;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
#define MY_CLOSE(fp) PHYSFS_close(fp)
|
||||
#define MY_ATEOF(fp) PHYSFS_eof(fp)
|
||||
#define MY_TELL(fp) PHYSFS_tell(fp)
|
||||
#define MY_SEEK(fp,o) PHYSFS_seek(fp,o)
|
||||
#define MY_REWIND(fp) MY_SEEK(fp,0)
|
||||
|
||||
#else
|
||||
|
||||
#define MY_FILETYPE FILE
|
||||
#define MY_READ(p,s,n,fp) fread(p,s,n,fp)
|
||||
#define MY_OPEN_FOR_READ(n) fopen(n, "rb")
|
||||
#define MY_GETC(fp) fgetc(fp)
|
||||
#define MY_GETS(str,size,fp) fgets(str,size,fp)
|
||||
#define MY_CLOSE(fp) fclose(fp)
|
||||
#define MY_ATEOF(fp) feof(fp)
|
||||
#define MY_TELL(fp) ftell(fp)
|
||||
#define MY_SEEK(fp,o) fseek(fp,o, SEEK_SET)
|
||||
#define MY_REWIND(fp) rewind(fp)
|
||||
/*static void MY_SETBUFFER(const MY_FILETYPE *const file, const int num) { }*/
|
||||
#define MY_SETBUFFER(fp,size)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,239 @@
|
||||
/** \file globbing.c */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "globbing.h"
|
||||
|
||||
/**
|
||||
* Please see globbing.h for details.
|
||||
*
|
||||
* 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 the file LICENSE.txt in the source's root directory.
|
||||
*
|
||||
* \author Ryan C. Gordon.
|
||||
*/
|
||||
|
||||
|
||||
static int matchesPattern(const char *fname, const char *wildcard,
|
||||
int caseSensitive)
|
||||
{
|
||||
char x, y;
|
||||
const char *fnameptr = fname;
|
||||
const char *wildptr = wildcard;
|
||||
|
||||
while ((*wildptr) && (*fnameptr))
|
||||
{
|
||||
y = *wildptr;
|
||||
if (y == '*')
|
||||
{
|
||||
do
|
||||
{
|
||||
wildptr++; /* skip multiple '*' in a row... */
|
||||
} while (*wildptr == '*');
|
||||
|
||||
y = (caseSensitive) ? *wildptr : (char) tolower(*wildptr);
|
||||
|
||||
while (1)
|
||||
{
|
||||
x = (caseSensitive) ? *fnameptr : (char) tolower(*fnameptr);
|
||||
if ((!x) || (x == y))
|
||||
break;
|
||||
else
|
||||
fnameptr++;
|
||||
} /* while */
|
||||
} /* if */
|
||||
|
||||
else if (y == '?')
|
||||
{
|
||||
wildptr++;
|
||||
fnameptr++;
|
||||
} /* else if */
|
||||
|
||||
else
|
||||
{
|
||||
if (caseSensitive)
|
||||
x = *fnameptr;
|
||||
else
|
||||
{
|
||||
x = tolower(*fnameptr);
|
||||
y = tolower(y);
|
||||
} /* if */
|
||||
|
||||
wildptr++;
|
||||
fnameptr++;
|
||||
|
||||
if (x != y)
|
||||
return 0;
|
||||
} /* else */
|
||||
} /* while */
|
||||
|
||||
while (*wildptr == '*')
|
||||
wildptr++;
|
||||
|
||||
return (*fnameptr == *wildptr);
|
||||
} /* matchesPattern */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const PHYSFS_Allocator *allocator;
|
||||
const char *wildcard;
|
||||
int caseSensitive;
|
||||
PHYSFS_EnumFilesCallback callback;
|
||||
void *origData;
|
||||
} WildcardCallbackData;
|
||||
|
||||
|
||||
/*
|
||||
* This callback sits between the enumerator and the enduser callback,
|
||||
* filtering out files that don't match the wildcard pattern.
|
||||
*/
|
||||
static void wildcardCallback(void *_d, const char *origdir, const char *fname)
|
||||
{
|
||||
const WildcardCallbackData *data = (const WildcardCallbackData *) _d;
|
||||
if (matchesPattern(fname, data->wildcard, data->caseSensitive))
|
||||
data->callback(data->origData, origdir, fname);
|
||||
} /* wildcardCallback */
|
||||
|
||||
|
||||
void PHYSFSEXT_enumerateFilesCallbackWildcard(const char *dir,
|
||||
const char *wildcard,
|
||||
int caseSensitive,
|
||||
PHYSFS_EnumFilesCallback c,
|
||||
void *d)
|
||||
{
|
||||
WildcardCallbackData data;
|
||||
data.allocator = PHYSFS_getAllocator();
|
||||
data.wildcard = wildcard;
|
||||
data.caseSensitive = caseSensitive;
|
||||
data.callback = c;
|
||||
data.origData = d;
|
||||
PHYSFS_enumerateFilesCallback(dir, wildcardCallback, &data);
|
||||
} /* PHYSFSEXT_enumerateFilesCallbackWildcard */
|
||||
|
||||
|
||||
void PHYSFSEXT_freeEnumeration(char **list)
|
||||
{
|
||||
const PHYSFS_Allocator *allocator = PHYSFS_getAllocator();
|
||||
int i;
|
||||
if (list != NULL)
|
||||
{
|
||||
for (i = 0; list[i] != NULL; i++)
|
||||
allocator->Free(list[i]);
|
||||
allocator->Free(list);
|
||||
} /* if */
|
||||
} /* PHYSFSEXT_freeEnumeration */
|
||||
|
||||
|
||||
char **PHYSFSEXT_enumerateFilesWildcard(const char *dir, const char *wildcard,
|
||||
int caseSensitive)
|
||||
{
|
||||
const PHYSFS_Allocator *allocator = PHYSFS_getAllocator();
|
||||
char **list = PHYSFS_enumerateFiles(dir);
|
||||
char **retval = NULL;
|
||||
int totalmatches = 0;
|
||||
int matches = 0;
|
||||
char **i;
|
||||
|
||||
for (i = list; *i != NULL; i++)
|
||||
{
|
||||
#if 0
|
||||
printf("matchesPattern: '%s' vs '%s' (%s) ... %s\n", *i, wildcard,
|
||||
caseSensitive ? "case" : "nocase",
|
||||
matchesPattern(*i, wildcard, caseSensitive) ? "true" : "false");
|
||||
#endif
|
||||
if (matchesPattern(*i, wildcard, caseSensitive))
|
||||
totalmatches++;
|
||||
} /* for */
|
||||
|
||||
retval = (char **) allocator->Malloc(sizeof (char *) * (totalmatches+1));
|
||||
if (retval != NULL)
|
||||
{
|
||||
for (i = list; ((matches < totalmatches) && (*i != NULL)); i++)
|
||||
{
|
||||
if (matchesPattern(*i, wildcard, caseSensitive))
|
||||
{
|
||||
retval[matches] = (char *) allocator->Malloc(strlen(*i) + 1);
|
||||
if (retval[matches] == NULL)
|
||||
{
|
||||
while (matches--)
|
||||
allocator->Free(retval[matches]);
|
||||
allocator->Free(retval);
|
||||
retval = NULL;
|
||||
break;
|
||||
} /* if */
|
||||
strcpy(retval[matches], *i);
|
||||
matches++;
|
||||
} /* if */
|
||||
} /* for */
|
||||
|
||||
if (retval != NULL)
|
||||
{
|
||||
assert(totalmatches == matches);
|
||||
retval[matches] = NULL;
|
||||
} /* if */
|
||||
} /* if */
|
||||
|
||||
PHYSFS_freeList(list);
|
||||
return retval;
|
||||
} /* PHYSFSEXT_enumerateFilesWildcard */
|
||||
|
||||
|
||||
#ifdef TEST_PHYSFSEXT_ENUMERATEFILESWILDCARD
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int rc;
|
||||
char **flist;
|
||||
char **i;
|
||||
|
||||
if (argc != 3)
|
||||
{
|
||||
printf("USAGE: %s <pattern> <caseSen>\n"
|
||||
" where <caseSen> is 1 or 0.\n", argv[0]);
|
||||
return 1;
|
||||
} /* if */
|
||||
|
||||
if (!PHYSFS_init(argv[0]))
|
||||
{
|
||||
fprintf(stderr, "PHYSFS_init(): %s\n", PHYSFS_getLastError());
|
||||
return 1;
|
||||
} /* if */
|
||||
|
||||
if (!PHYSFS_addToSearchPath(".", 1))
|
||||
{
|
||||
fprintf(stderr, "PHYSFS_addToSearchPath(): %s\n", PHYSFS_getLastError());
|
||||
PHYSFS_deinit();
|
||||
return 1;
|
||||
} /* if */
|
||||
|
||||
flist = PHYSFSEXT_enumerateFilesWildcard("/", argv[1], atoi(argv[2]));
|
||||
rc = 0;
|
||||
for (i = flist; *i; i++)
|
||||
{
|
||||
printf("%s\n", *i);
|
||||
rc++;
|
||||
} /* for */
|
||||
printf("\n total %d files.\n\n", rc);
|
||||
|
||||
PHYSFSEXT_freeEnumeration(flist);
|
||||
PHYSFS_deinit();
|
||||
|
||||
return 0;
|
||||
} /* main */
|
||||
#endif
|
||||
|
||||
/* end of globbing.c ... */
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
#ifndef INCL_PHYSFSEXT_GLOBBING_H
|
||||
#define INCL_PHYSFSEXT_GLOBBING_H
|
||||
|
||||
/** \file globbing.h */
|
||||
|
||||
#include "physfs.h"
|
||||
|
||||
/**
|
||||
* \mainpage PhysicsFS globbing
|
||||
*
|
||||
* This is an extension to PhysicsFS to let you search for files with basic
|
||||
* wildcard matching, regardless of what sort of filesystem or archive they
|
||||
* reside in. It does this by enumerating directories as needed and manually
|
||||
* locating matching entries.
|
||||
*
|
||||
* Usage: Set up PhysicsFS as you normally would, then use
|
||||
* PHYSFSEXT_enumerateFilesWildcard() when enumerating files. This is just
|
||||
* like PHYSFS_enumerateFiles(), but it returns a subset that matches your
|
||||
* wildcard pattern. You must call PHYSFSEXT_freeEnumeration() on the results,
|
||||
* just PHYSFS_enumerateFiles() would do with PHYSFS_freeList().
|
||||
*
|
||||
* 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 source's "docs" directory.
|
||||
*
|
||||
* \author Ryan C. Gordon.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \fn char **PHYSFS_enumerateFilesWildcard(const char *dir, const char *wildcard, int caseSensitive)
|
||||
* \brief Get a file listing of a search path's directory, filtered with a wildcard pattern.
|
||||
*
|
||||
* 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.txt", 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_enumerateFilesWildcard("savegames", "*.sav", 0);
|
||||
* 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 [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.
|
||||
*
|
||||
* Wildcard strings can use the '*' and '?' characters, currently.
|
||||
* Matches can be case-insensitive if you pass a zero for argument 3.
|
||||
*
|
||||
* Don't forget to call PHYSFSEXT_freeEnumerator() with the return value from
|
||||
* this function when you are done with it. As we use PhysicsFS's allocator
|
||||
* for this list, you must free it before calling PHYSFS_deinit().
|
||||
* Do not use PHYSFS_freeList() on the returned value!
|
||||
*
|
||||
* \param dir directory in platform-independent notation to enumerate.
|
||||
* \param wildcard Wildcard pattern to use for filtering.
|
||||
* \param caseSensitive Zero for case-insensitive matching,
|
||||
* non-zero for case-sensitive.
|
||||
* \return Null-terminated array of null-terminated strings.
|
||||
*
|
||||
* \sa PHYSFSEXT_freeEnumeration
|
||||
*/
|
||||
PHYSFS_DECL char **PHYSFSEXT_enumerateFilesWildcard(const char *dir,
|
||||
const char *wildcard,
|
||||
int caseSensitive);
|
||||
|
||||
/**
|
||||
* \fn void PHYSFSEXT_freeEnumeration(char **list)
|
||||
* \brief Free data returned by PHYSFSEXT_enumerateFilesWildcard
|
||||
*
|
||||
* Conceptually, this works like PHYSFS_freeList(), but is used with data
|
||||
* returned by PHYSFSEXT_enumerateFilesWildcard() only. Be sure to call this
|
||||
* on any returned data from that function before
|
||||
*
|
||||
* \param list Pointer previously returned by
|
||||
* PHYSFSEXT_enumerateFilesWildcard(). It is safe to pass a
|
||||
* NULL here.
|
||||
*
|
||||
* \sa PHYSFSEXT_enumerateFilesWildcard
|
||||
*/
|
||||
PHYSFS_DECL void PHYSFSEXT_freeEnumeration(char **list);
|
||||
|
||||
|
||||
/**
|
||||
* \fn void PHYSFSEXT_enumerateFilesCallbackWildcard(const char *dir, const char *wildcard, int caseSensitive, PHYSFS_EnumFilesCallback c, void *d);
|
||||
* \brief Get a file listing of a search path's directory, filtered with a wildcard pattern, using an application-defined callback.
|
||||
*
|
||||
* This function is equivalent to PHYSFSEXT_enumerateFilesWildcard(). It
|
||||
* reports file listings, filtered by a wildcard pattern.
|
||||
*
|
||||
* 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_enumerateFilesCallbackWildcard("savegames","*.sav",0,printDir,NULL);
|
||||
* \endcode
|
||||
*
|
||||
* 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_enumerateFilesWildcard() 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. <em>Any sorting you find in
|
||||
* these callbacks is just pure luck. Do not rely on it.</em> As this walks
|
||||
* the entire list of archives, you may receive duplicate filenames.
|
||||
*
|
||||
* Wildcard strings can use the '*' and '?' characters, currently.
|
||||
* Matches can be case-insensitive if you pass a zero for argument 3.
|
||||
*
|
||||
* \param dir Directory, in platform-independent notation, to enumerate.
|
||||
* \param wildcard Wildcard pattern to use for filtering.
|
||||
* \param caseSensitive Zero for case-insensitive matching,
|
||||
* non-zero for case-sensitive.
|
||||
* \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 PHYSFSEXT_enumerateFilesCallbackWildcard(const char *dir,
|
||||
const char *wildcard,
|
||||
int caseSensitive,
|
||||
PHYSFS_EnumFilesCallback c,
|
||||
void *d);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* include-once blocker. */
|
||||
|
||||
/* end of globbing.h ... */
|
||||
|
||||
@@ -0,0 +1,219 @@
|
||||
/** \file ignorecase.c */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "physfs.h"
|
||||
#include "ignorecase.h"
|
||||
|
||||
/**
|
||||
* Please see ignorecase.h for details.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* \author Ryan C. Gordon.
|
||||
*/
|
||||
|
||||
/* I'm not screwing around with stricmp vs. strcasecmp... */
|
||||
/* !!! FIXME: this will NOT work with UTF-8 strings in physfs2.0 */
|
||||
static int caseInsensitiveStringCompare(const char *x, const char *y)
|
||||
{
|
||||
int ux, uy;
|
||||
do
|
||||
{
|
||||
ux = toupper((int) *x);
|
||||
uy = toupper((int) *y);
|
||||
if (ux != uy)
|
||||
return ((ux > uy) ? 1 : -1);
|
||||
x++;
|
||||
y++;
|
||||
} while ((ux) && (uy));
|
||||
|
||||
return 0;
|
||||
} /* caseInsensitiveStringCompare */
|
||||
|
||||
|
||||
static int locateOneElement(char *buf)
|
||||
{
|
||||
char *ptr;
|
||||
char **rc;
|
||||
char **i;
|
||||
|
||||
if (PHYSFS_exists(buf))
|
||||
return 1; /* quick rejection: exists in current case. */
|
||||
|
||||
ptr = strrchr(buf, '/'); /* find entry at end of path. */
|
||||
if (ptr == NULL)
|
||||
{
|
||||
rc = PHYSFS_enumerateFiles("/");
|
||||
ptr = buf;
|
||||
} /* if */
|
||||
else
|
||||
{
|
||||
*ptr = '\0';
|
||||
rc = PHYSFS_enumerateFiles(buf);
|
||||
*ptr = '/';
|
||||
ptr++; /* point past dirsep to entry itself. */
|
||||
} /* else */
|
||||
|
||||
for (i = rc; *i != NULL; i++)
|
||||
{
|
||||
if (caseInsensitiveStringCompare(*i, ptr) == 0)
|
||||
{
|
||||
strcpy(ptr, *i); /* found a match. Overwrite with this case. */
|
||||
PHYSFS_freeList(rc);
|
||||
return 1;
|
||||
} /* if */
|
||||
} /* for */
|
||||
|
||||
/* no match at all... */
|
||||
PHYSFS_freeList(rc);
|
||||
return 0;
|
||||
} /* locateOneElement */
|
||||
|
||||
|
||||
int PHYSFSEXT_locateCorrectCase(char *buf)
|
||||
{
|
||||
int rc;
|
||||
char *ptr;
|
||||
char *prevptr;
|
||||
|
||||
while (*buf == '/') /* skip any '/' at start of string... */
|
||||
buf++;
|
||||
|
||||
ptr = prevptr = buf;
|
||||
if (*ptr == '\0')
|
||||
return 0; /* Uh...I guess that's success. */
|
||||
|
||||
while ( (ptr = strchr(ptr + 1, '/')) != NULL )
|
||||
{
|
||||
*ptr = '\0'; /* block this path section off */
|
||||
rc = locateOneElement(buf);
|
||||
*ptr = '/'; /* restore path separator */
|
||||
if (!rc)
|
||||
return -2; /* missing element in path. */
|
||||
} /* while */
|
||||
|
||||
/* check final element... */
|
||||
return locateOneElement(buf) ? 0 : -1;
|
||||
} /* PHYSFSEXT_locateCorrectCase */
|
||||
|
||||
|
||||
#ifdef TEST_PHYSFSEXT_LOCATECORRECTCASE
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int rc;
|
||||
char buf[128];
|
||||
PHYSFS_File *f;
|
||||
|
||||
if (!PHYSFS_init(argv[0]))
|
||||
{
|
||||
fprintf(stderr, "PHYSFS_init(): %s\n", PHYSFS_getLastError());
|
||||
return 1;
|
||||
} /* if */
|
||||
|
||||
if (!PHYSFS_addToSearchPath(".", 1))
|
||||
{
|
||||
fprintf(stderr, "PHYSFS_addToSearchPath(): %s\n", PHYSFS_getLastError());
|
||||
PHYSFS_deinit();
|
||||
return 1;
|
||||
} /* if */
|
||||
|
||||
if (!PHYSFS_setWriteDir("."))
|
||||
{
|
||||
fprintf(stderr, "PHYSFS_setWriteDir(): %s\n", PHYSFS_getLastError());
|
||||
PHYSFS_deinit();
|
||||
return 1;
|
||||
} /* if */
|
||||
|
||||
if (!PHYSFS_mkdir("/a/b/c"))
|
||||
{
|
||||
fprintf(stderr, "PHYSFS_mkdir(): %s\n", PHYSFS_getLastError());
|
||||
PHYSFS_deinit();
|
||||
return 1;
|
||||
} /* if */
|
||||
|
||||
if (!PHYSFS_mkdir("/a/b/C"))
|
||||
{
|
||||
fprintf(stderr, "PHYSFS_mkdir(): %s\n", PHYSFS_getLastError());
|
||||
PHYSFS_deinit();
|
||||
return 1;
|
||||
} /* if */
|
||||
|
||||
f = PHYSFS_openWrite("/a/b/c/x.txt");
|
||||
PHYSFS_close(f);
|
||||
if (f == NULL)
|
||||
{
|
||||
fprintf(stderr, "PHYSFS_openWrite(): %s\n", PHYSFS_getLastError());
|
||||
PHYSFS_deinit();
|
||||
return 1;
|
||||
} /* if */
|
||||
|
||||
f = PHYSFS_openWrite("/a/b/C/X.txt");
|
||||
PHYSFS_close(f);
|
||||
if (f == NULL)
|
||||
{
|
||||
fprintf(stderr, "PHYSFS_openWrite(): %s\n", PHYSFS_getLastError());
|
||||
PHYSFS_deinit();
|
||||
return 1;
|
||||
} /* if */
|
||||
|
||||
strcpy(buf, "/a/b/c/x.txt");
|
||||
rc = PHYSFSEXT_locateCorrectCase(buf);
|
||||
if ((rc != 0) || (strcmp(buf, "/a/b/c/x.txt") != 0))
|
||||
printf("test 1 failed\n");
|
||||
|
||||
strcpy(buf, "/a/B/c/x.txt");
|
||||
rc = PHYSFSEXT_locateCorrectCase(buf);
|
||||
if ((rc != 0) || (strcmp(buf, "/a/b/c/x.txt") != 0))
|
||||
printf("test 2 failed\n");
|
||||
|
||||
strcpy(buf, "/a/b/C/x.txt");
|
||||
rc = PHYSFSEXT_locateCorrectCase(buf);
|
||||
if ((rc != 0) || (strcmp(buf, "/a/b/C/X.txt") != 0))
|
||||
printf("test 3 failed\n");
|
||||
|
||||
strcpy(buf, "/a/b/c/X.txt");
|
||||
rc = PHYSFSEXT_locateCorrectCase(buf);
|
||||
if ((rc != 0) || (strcmp(buf, "/a/b/c/x.txt") != 0))
|
||||
printf("test 4 failed\n");
|
||||
|
||||
strcpy(buf, "/a/b/c/z.txt");
|
||||
rc = PHYSFSEXT_locateCorrectCase(buf);
|
||||
if ((rc != -1) || (strcmp(buf, "/a/b/c/z.txt") != 0))
|
||||
printf("test 5 failed\n");
|
||||
|
||||
strcpy(buf, "/A/B/Z/z.txt");
|
||||
rc = PHYSFSEXT_locateCorrectCase(buf);
|
||||
if ((rc != -2) || (strcmp(buf, "/a/b/Z/z.txt") != 0))
|
||||
printf("test 6 failed\n");
|
||||
|
||||
printf("Testing completed.\n");
|
||||
printf(" If no errors were reported, you're good to go.\n");
|
||||
|
||||
PHYSFS_delete("/a/b/c/x.txt");
|
||||
PHYSFS_delete("/a/b/C/X.txt");
|
||||
PHYSFS_delete("/a/b/c");
|
||||
PHYSFS_delete("/a/b/C");
|
||||
PHYSFS_delete("/a/b");
|
||||
PHYSFS_delete("/a");
|
||||
PHYSFS_deinit();
|
||||
return 0;
|
||||
} /* main */
|
||||
#endif
|
||||
|
||||
/* end of ignorecase.c ... */
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
#ifndef INCL_PHYSFSEXT_IGNORECASE_H
|
||||
#define INCL_PHYSFSEXT_IGNORECASE_H
|
||||
|
||||
/** \file ignorecase.h */
|
||||
|
||||
/**
|
||||
* \mainpage PhysicsFS ignorecase
|
||||
*
|
||||
* This is an extension to PhysicsFS to let you handle files in a
|
||||
* case-insensitive manner, regardless of what sort of filesystem or
|
||||
* archive they reside in. It does this by enumerating directories as
|
||||
* needed and manually locating matching entries.
|
||||
*
|
||||
* Please note that this brings with it some caveats:
|
||||
* - On filesystems that are case-insensitive to start with, such as those
|
||||
* used on Windows or MacOS, you are adding extra overhead.
|
||||
* - On filesystems that are case-sensitive, you might select the wrong dir
|
||||
* or file (which brings security considerations and potential bugs). This
|
||||
* code favours exact case matches, but you will lose access to otherwise
|
||||
* duplicate filenames, or you might go down a wrong directory tree, etc.
|
||||
* In practive, this is rarely a problem, but you need to be aware of it.
|
||||
* - This doesn't do _anything_ with the write directory; you're on your
|
||||
* own for opening the right files for writing. You can sort of get around
|
||||
* this by adding your write directory to the search path, but then the
|
||||
* interpolated directory tree can screw you up even more.
|
||||
*
|
||||
* This code should be considered an aid for legacy code. New development
|
||||
* shouldn't do dumbass things that require this aid in the first place. :)
|
||||
*
|
||||
* Usage: Set up PhysicsFS as you normally would, then use
|
||||
* PHYSFSEXT_locateCorrectCase() to get a "correct" pathname to pass to
|
||||
* functions like PHYSFS_openRead(), etc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* \author Ryan C. Gordon.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \fn int PHYSFSEXT_locateCorrectCase(char *buf)
|
||||
* \brief Find an existing filename with matching case.
|
||||
*
|
||||
* This function will look for a path/filename that matches the passed in
|
||||
* buffer. Each element of the buffer's path is checked for a
|
||||
* case-insensitive match. The buffer must specify a null-terminated string
|
||||
* in platform-independent notation.
|
||||
*
|
||||
* Please note results may be skewed differently depending on whether symlinks
|
||||
* are enabled or not.
|
||||
*
|
||||
* Each element of the buffer is overwritten with the actual case of an
|
||||
* existing match. If there is no match, the search aborts and reports an
|
||||
* error. Exact matches are favored over case-insensitive matches.
|
||||
*
|
||||
* THIS IS RISKY. Please do not use this function for anything but crappy
|
||||
* legacy code.
|
||||
*
|
||||
* \param buf Buffer with null-terminated string of path/file to locate.
|
||||
* This buffer will be modified by this function.
|
||||
* \return zero if match was found, -1 if the final element (the file itself)
|
||||
* is missing, -2 if one of the parent directories is missing.
|
||||
*/
|
||||
int PHYSFSEXT_locateCorrectCase(char *buf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* include-once blocker. */
|
||||
|
||||
/* end of ignorecase.h ... */
|
||||
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
print <<__EOF__;
|
||||
/*
|
||||
* 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
|
||||
|
||||
__EOF__
|
||||
|
||||
|
||||
my @foldPairs;
|
||||
|
||||
for (my $i = 0; $i < 256; $i++) {
|
||||
$foldPairs[$i] = '';
|
||||
}
|
||||
|
||||
open(FH,'<','casefolding.txt') or die("failed to open casefolding.txt: $!\n");
|
||||
while (<FH>) {
|
||||
chomp;
|
||||
# strip comments from textfile...
|
||||
s/\#.*\Z//;
|
||||
|
||||
# strip whitespace...
|
||||
s/\A\s+//;
|
||||
s/\s+\Z//;
|
||||
|
||||
next if not /\A([a-fA-F0-9]+)\;\s*(.)\;\s*(.+)\;/;
|
||||
my ($code, $status, $mapping) = ($1, $2, $3);
|
||||
my $hexxed = hex($code);
|
||||
my $hashed = (($hexxed ^ ($hexxed >> 8)) & 0xFF);
|
||||
#print("// code '$code' status '$status' mapping '$mapping'\n");
|
||||
#print("// hexxed '$hexxed' hashed '$hashed'\n");
|
||||
|
||||
if (($status eq 'C') or ($status eq 'F')) {
|
||||
my ($map1, $map2, $map3) = ('0000', '0000', '0000');
|
||||
$map1 = $1 if $mapping =~ s/\A([a-fA-F0-9]+)(\s*|\Z)//;
|
||||
$map2 = $1 if $mapping =~ s/\A([a-fA-F0-9]+)(\s*|\Z)//;
|
||||
$map3 = $1 if $mapping =~ s/\A([a-fA-F0-9]+)(\s*|\Z)//;
|
||||
die("mapping space too small for '$code'\n") if ($mapping ne '');
|
||||
$foldPairs[$hashed] .= " { 0x$code, 0x$map1, 0x$map2, 0x$map3 },\n";
|
||||
}
|
||||
}
|
||||
close(FH);
|
||||
|
||||
for (my $i = 0; $i < 256; $i++) {
|
||||
$foldPairs[$i] =~ s/,\n\Z//;
|
||||
my $str = $foldPairs[$i];
|
||||
next if $str eq '';
|
||||
my $num = '000' . $i;
|
||||
$num =~ s/\A.*?(\d\d\d)\Z/$1/;
|
||||
my $sym = "case_fold_${num}";
|
||||
print("static const CaseFoldMapping ${sym}[] = {\n$str\n};\n\n");
|
||||
}
|
||||
|
||||
print("\nstatic const CaseFoldHashBucket case_fold_hash[256] = {\n");
|
||||
|
||||
for (my $i = 0; $i < 256; $i++) {
|
||||
my $str = $foldPairs[$i];
|
||||
if ($str eq '') {
|
||||
print(" { 0, NULL },\n");
|
||||
} else {
|
||||
my $num = '000' . $i;
|
||||
$num =~ s/\A.*?(\d\d\d)\Z/$1/;
|
||||
my $sym = "case_fold_${num}";
|
||||
print(" { __PHYSFS_ARRAYLEN($sym), $sym },\n");
|
||||
}
|
||||
}
|
||||
print("};\n\n");
|
||||
|
||||
exit 0;
|
||||
|
||||
# end of makecashfoldhashtable.pl ...
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/* Metadata to generate the scripting language bindings. Please ignore. */
|
||||
%module physfs
|
||||
|
||||
%{
|
||||
#include "physfs.h"
|
||||
%}
|
||||
|
||||
/* I _think_ this is safe for now. */
|
||||
%warnfilter(451) PHYSFS_ArchiveInfo;
|
||||
|
||||
%ignore _INCLUDE_PHYSFS_H_; /* ignore the include-once blocker. */
|
||||
%ignore PHYSFS_DECL; /* ignore the export define. */
|
||||
%ignore PHYSFS_CALL; /* ignore the calling conventions define. */
|
||||
%ignore PHYSFS_DEPRECATED; /* ignore the deprecation define. */
|
||||
%ignore PHYSFS_file; /* legacy type define. */
|
||||
|
||||
/* Some bindings put everything in a namespace, so we don't need PHYSFS_ */
|
||||
#if defined(SWIGPERL) || defined(SWIGRUBY)
|
||||
%rename(File) PHYSFS_File;
|
||||
%rename(Version) PHYSFS_Version;
|
||||
%rename(ArchiveInfo) PHYSFS_ArchiveInfo;
|
||||
%rename(getLinkedVersion) PHYSFS_getLinkedVersion;
|
||||
%rename(init) PHYSFS_init;
|
||||
%rename(deinit) PHYSFS_deinit;
|
||||
%rename(supportedArchiveTypes) PHYSFS_supportedArchiveTypes;
|
||||
%rename(freeList) PHYSFS_freeList;
|
||||
%rename(getLastError) PHYSFS_getLastError;
|
||||
%rename(getDirSeparator) PHYSFS_getDirSeparator;
|
||||
%rename(permitSymbolicLinks) PHYSFS_permitSymbolicLinks;
|
||||
%rename(getCdRomDirs) PHYSFS_getCdRomDirs;
|
||||
%rename(getBaseDir) PHYSFS_getBaseDir;
|
||||
%rename(getUserDir) PHYSFS_getUserDir;
|
||||
%rename(getWriteDir) PHYSFS_getWriteDir;
|
||||
%rename(setWriteDir) PHYSFS_setWriteDir;
|
||||
%rename(addToSearchPath) PHYSFS_addToSearchPath;
|
||||
%rename(removeFromSearchPath) PHYSFS_removeFromSearchPath;
|
||||
%rename(getSearchPath) PHYSFS_getSearchPath;
|
||||
%rename(setSaneConfig) PHYSFS_setSaneConfig;
|
||||
%rename(mkdir) PHYSFS_mkdir;
|
||||
%rename(delete) PHYSFS_delete;
|
||||
%rename(getRealDir) PHYSFS_getRealDir;
|
||||
%rename(enumerateFiles) PHYSFS_enumerateFiles;
|
||||
%rename(exists) PHYSFS_exists;
|
||||
%rename(isDirectory) PHYSFS_isDirectory;
|
||||
%rename(isSymbolicLink) PHYSFS_isSymbolicLink;
|
||||
%rename(getLastModTime) PHYSFS_getLastModTime;
|
||||
%rename(openWrite) PHYSFS_openWrite;
|
||||
%rename(openAppend) PHYSFS_openAppend;
|
||||
%rename(openRead) PHYSFS_openRead;
|
||||
%rename(close) PHYSFS_close;
|
||||
%rename(read) PHYSFS_read;
|
||||
%rename(write) PHYSFS_write;
|
||||
%rename(eof) PHYSFS_eof;
|
||||
%rename(tell) PHYSFS_tell;
|
||||
%rename(seek) PHYSFS_seek;
|
||||
%rename(fileLength) PHYSFS_fileLength;
|
||||
%rename(setBuffer) PHYSFS_setBuffer;
|
||||
%rename(flush) PHYSFS_flush;
|
||||
%rename(readSLE16) PHYSFS_readSLE16;
|
||||
%rename(readULE16) PHYSFS_readULE16;
|
||||
%rename(readSBE16) PHYSFS_readSBE16;
|
||||
%rename(readUBE16) PHYSFS_readUBE16;
|
||||
%rename(readSLE32) PHYSFS_readSLE32;
|
||||
%rename(readULE32) PHYSFS_readULE32;
|
||||
%rename(readSBE32) PHYSFS_readSBE32;
|
||||
%rename(readUBE32) PHYSFS_readUBE32;
|
||||
%rename(readSLE64) PHYSFS_readSLE64;
|
||||
%rename(readULE64) PHYSFS_readULE64;
|
||||
%rename(readSBE64) PHYSFS_readSBE64;
|
||||
%rename(readUBE64) PHYSFS_readUBE64;
|
||||
%rename(writeSLE16) PHYSFS_writeSLE16;
|
||||
%rename(writeULE16) PHYSFS_writeULE16;
|
||||
%rename(writeSBE16) PHYSFS_writeSBE16;
|
||||
%rename(writeUBE16) PHYSFS_writeUBE16;
|
||||
%rename(writeSLE32) PHYSFS_writeSLE32;
|
||||
%rename(writeULE32) PHYSFS_writeULE32;
|
||||
%rename(writeSBE32) PHYSFS_writeSBE32;
|
||||
%rename(writeUBE32) PHYSFS_writeUBE32;
|
||||
%rename(writeSLE64) PHYSFS_writeSLE64;
|
||||
%rename(writeULE64) PHYSFS_writeULE64;
|
||||
%rename(writeSBE64) PHYSFS_writeSBE64;
|
||||
%rename(writeUBE64) PHYSFS_writeUBE64;
|
||||
%rename(isInit) PHYSFS_isInit;
|
||||
%rename(symbolicLinksPermitted) PHYSFS_symbolicLinksPermitted;
|
||||
%rename(mount) PHYSFS_mount;
|
||||
%rename(getMountPoint) PHYSFS_getMountPoint;
|
||||
%rename(Stat) PHYSFS_Stat; /* !!! FIXME: case insensitive script languages? */
|
||||
%rename(stat) PHYSFS_stat;
|
||||
%rename(readBytes) PHYSFS_readBytes;
|
||||
%rename(writeBytes) PHYSFS_writeBytes;
|
||||
%rename(unmount) PHYSFS_unmount;
|
||||
%rename(mountMemory) PHYSFS_mountMemory;
|
||||
%rename(mountHandle) PHYSFS_mountHandle;
|
||||
%rename(getPrefDir) PHYSFS_getPrefDir;
|
||||
#endif
|
||||
|
||||
%include "../src/physfs.h"
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=${prefix}
|
||||
libdir=${exec_prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: PhysicsFS
|
||||
Description: PhysicsFS is a library to provide abstract access to various archives.
|
||||
URL: https://icculus.org/physfs/
|
||||
Version: @PHYSFS_VERSION@
|
||||
Libs: -L${libdir} -lphysfs
|
||||
Cflags: -I${includedir}
|
||||
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
* This is a quick and dirty HTTP server that uses PhysicsFS to retrieve
|
||||
* files. It is not robust at all, probably buggy, and definitely poorly
|
||||
* designed. It's just meant to show that it can be done.
|
||||
*
|
||||
* Basically, you compile this code, and run it:
|
||||
* ./physfshttpd archive1.zip archive2.zip /path/to/a/real/dir etc...
|
||||
*
|
||||
* The files are appended in order to the PhysicsFS search path, and when
|
||||
* a client request comes it, it looks for the file in said search path.
|
||||
*
|
||||
* My goal was to make this work in less than 300 lines of C, so again, it's
|
||||
* not to be used for any serious purpose. Patches to make this application
|
||||
* suck less will be readily and gratefully accepted.
|
||||
*
|
||||
* Command line I used to build this on Linux:
|
||||
* gcc -Wall -Werror -g -o bin/physfshttpd extras/physfshttpd.c -lphysfs
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This file was written by Ryan C. Gordon. (icculus@icculus.org).
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#ifndef LACKING_SIGNALS
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#ifndef LACKING_PROTOENT
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
#include "physfs.h"
|
||||
|
||||
|
||||
#define DEFAULT_PORTNUM 6667
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int sock;
|
||||
struct sockaddr *addr;
|
||||
socklen_t addrlen;
|
||||
} http_args;
|
||||
|
||||
|
||||
static char *txt404 =
|
||||
"HTTP/1.0 404 Not Found\n"
|
||||
"Connection: close\n"
|
||||
"Content-Type: text/html; charset=utf-8\n"
|
||||
"\n"
|
||||
"<html><head><title>404 Not Found</title></head>\n"
|
||||
"<body>Can't find that.</body></html>\n\n";
|
||||
|
||||
|
||||
static void feed_file_http(const char *ipstr, int sock, const char *fname)
|
||||
{
|
||||
PHYSFS_File *in = PHYSFS_openRead(fname);
|
||||
char buffer[1024];
|
||||
printf("%s: requested [%s].\n", ipstr, fname);
|
||||
if (in == NULL)
|
||||
{
|
||||
printf("%s: Can't open [%s]: %s.\n",
|
||||
ipstr, fname, PHYSFS_getLastError());
|
||||
write(sock, txt404, strlen(txt404)); /* !!! FIXME: Check retval */
|
||||
} /* if */
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
PHYSFS_sint64 br = PHYSFS_read(in, buffer, 1, sizeof (buffer));
|
||||
if (br == -1)
|
||||
{
|
||||
printf("%s: Read error: %s.\n", ipstr, PHYSFS_getLastError());
|
||||
break;
|
||||
} /* if */
|
||||
|
||||
write(sock, buffer, (int) br); /* !!! FIXME: CHECK THIS RETVAL! */
|
||||
} while (!PHYSFS_eof(in));
|
||||
|
||||
PHYSFS_close(in);
|
||||
} /* else */
|
||||
} /* feed_file_http */
|
||||
|
||||
|
||||
static void *do_http(void *_args)
|
||||
{
|
||||
http_args *args = (http_args *) _args;
|
||||
char ipstr[128];
|
||||
char buffer[512];
|
||||
char *ptr;
|
||||
strncpy(ipstr, inet_ntoa(((struct sockaddr_in *) args->addr)->sin_addr),
|
||||
sizeof (ipstr));
|
||||
ipstr[sizeof (ipstr) - 1] = '\0';
|
||||
|
||||
printf("%s: connected.\n", ipstr);
|
||||
read(args->sock, buffer, sizeof (buffer));
|
||||
buffer[sizeof (buffer) - 1] = '\0';
|
||||
ptr = strchr(buffer, '\n');
|
||||
if (!ptr)
|
||||
printf("%s: potentially bogus request.\n", ipstr);
|
||||
else
|
||||
{
|
||||
*ptr = '\0';
|
||||
ptr = strchr(buffer, '\r');
|
||||
if (ptr != NULL)
|
||||
*ptr = '\0';
|
||||
|
||||
if ((toupper(buffer[0]) == 'G') &&
|
||||
(toupper(buffer[1]) == 'E') &&
|
||||
(toupper(buffer[2]) == 'T') &&
|
||||
(toupper(buffer[3]) == ' ') &&
|
||||
(toupper(buffer[4]) == '/'))
|
||||
{
|
||||
ptr = strchr(buffer + 5, ' ');
|
||||
if (ptr != NULL)
|
||||
*ptr = '\0';
|
||||
feed_file_http(ipstr, args->sock, buffer + 4);
|
||||
} /* if */
|
||||
} /* else */
|
||||
|
||||
/* !!! FIXME: Time the transfer. */
|
||||
printf("%s: closing connection.\n", ipstr);
|
||||
close(args->sock);
|
||||
free(args->addr);
|
||||
free(args);
|
||||
return NULL;
|
||||
} /* do_http */
|
||||
|
||||
|
||||
static void serve_http_request(int sock, struct sockaddr *addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
http_args *args = (http_args *) malloc(sizeof (http_args));
|
||||
if (args == NULL)
|
||||
{
|
||||
printf("out of memory.\n");
|
||||
return;
|
||||
} /* if */
|
||||
args->addr = (struct sockaddr *) malloc(addrlen);
|
||||
if (args->addr == NULL)
|
||||
{
|
||||
free(args);
|
||||
printf("out of memory.\n");
|
||||
return;
|
||||
} /* if */
|
||||
|
||||
args->sock = sock;
|
||||
args->addrlen = addrlen;
|
||||
memcpy(args->addr, addr, addrlen);
|
||||
|
||||
/* !!! FIXME: optionally spin a thread... */
|
||||
do_http((void *) args);
|
||||
} /* server_http_request */
|
||||
|
||||
|
||||
static int create_listen_socket(short portnum)
|
||||
{
|
||||
int retval = -1;
|
||||
int protocol = 0; /* pray this is right. */
|
||||
|
||||
#ifndef LACKING_PROTOENT
|
||||
struct protoent *prot;
|
||||
setprotoent(0);
|
||||
prot = getprotobyname("tcp");
|
||||
if (prot != NULL)
|
||||
protocol = prot->p_proto;
|
||||
#endif
|
||||
|
||||
retval = socket(PF_INET, SOCK_STREAM, protocol);
|
||||
if (retval >= 0)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(portnum);
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
if ((bind(retval, &addr, (socklen_t) sizeof (addr)) == -1) ||
|
||||
(listen(retval, 5) == -1))
|
||||
{
|
||||
close(retval);
|
||||
retval = -1;
|
||||
} /* if */
|
||||
} /* if */
|
||||
|
||||
return retval;
|
||||
} /* create_listen_socket */
|
||||
|
||||
|
||||
static int listensocket = -1;
|
||||
|
||||
void at_exit_cleanup(void)
|
||||
{
|
||||
/*
|
||||
* !!! FIXME: If thread support, signal threads to terminate and
|
||||
* !!! FIXME: wait for them to clean up.
|
||||
*/
|
||||
|
||||
if (listensocket >= 0)
|
||||
close(listensocket);
|
||||
|
||||
if (!PHYSFS_deinit())
|
||||
printf("PHYSFS_deinit() failed: %s\n", PHYSFS_getLastError());
|
||||
} /* at_exit_cleanup */
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
int portnum = DEFAULT_PORTNUM;
|
||||
|
||||
setbuf(stdout, NULL);
|
||||
setbuf(stderr, NULL);
|
||||
|
||||
#ifndef LACKING_SIGNALS
|
||||
/* I'm not sure if this qualifies as a cheap trick... */
|
||||
signal(SIGTERM, exit);
|
||||
signal(SIGINT, exit);
|
||||
signal(SIGFPE, exit);
|
||||
signal(SIGSEGV, exit);
|
||||
signal(SIGPIPE, exit);
|
||||
signal(SIGILL, exit);
|
||||
#endif
|
||||
|
||||
if (argc == 1)
|
||||
{
|
||||
printf("USAGE: %s <archive1> [archive2 [... archiveN]]\n", argv[0]);
|
||||
return 42;
|
||||
} /* if */
|
||||
|
||||
if (!PHYSFS_init(argv[0]))
|
||||
{
|
||||
printf("PHYSFS_init() failed: %s\n", PHYSFS_getLastError());
|
||||
return 42;
|
||||
} /* if */
|
||||
|
||||
/* normally, this is bad practice, but oh well. */
|
||||
atexit(at_exit_cleanup);
|
||||
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
if (!PHYSFS_addToSearchPath(argv[i], 1))
|
||||
printf(" WARNING: failed to add [%s] to search path.\n", argv[i]);
|
||||
} /* else */
|
||||
|
||||
listensocket = create_listen_socket(portnum);
|
||||
if (listensocket < 0)
|
||||
{
|
||||
printf("listen socket failed to create.\n");
|
||||
return 42;
|
||||
} /* if */
|
||||
|
||||
while (1) /* infinite loop for now. */
|
||||
{
|
||||
struct sockaddr addr;
|
||||
socklen_t len;
|
||||
int s = accept(listensocket, &addr, &len);
|
||||
if (s < 0)
|
||||
{
|
||||
printf("accept() failed: %s\n", strerror(errno));
|
||||
close(listensocket);
|
||||
return 42;
|
||||
} /* if */
|
||||
|
||||
serve_http_request(s, &addr, len);
|
||||
} /* while */
|
||||
|
||||
return 0;
|
||||
} /* main */
|
||||
|
||||
/* end of physfshttpd.c ... */
|
||||
|
||||
@@ -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 <stdio.h> /* 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 ... */
|
||||
|
||||
@@ -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 ... */
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "physfs.h"
|
||||
|
||||
|
||||
static int failure = 0;
|
||||
|
||||
static void modTimeToStr(PHYSFS_sint64 modtime, char *modstr, size_t strsize)
|
||||
{
|
||||
const char *str = "unknown modtime";
|
||||
if (modtime != -1)
|
||||
{
|
||||
time_t t = (time_t) modtime;
|
||||
str = ctime(&t);
|
||||
} /* if */
|
||||
|
||||
strncpy(modstr, str, strsize);
|
||||
modstr[strsize-1] = '\0';
|
||||
strsize = strlen(modstr);
|
||||
while ((modstr[strsize-1] == '\n') || (modstr[strsize-1] == '\r'))
|
||||
modstr[--strsize] = '\0';
|
||||
} /* modTimeToStr */
|
||||
|
||||
|
||||
static void fail(const char *what, const char *why)
|
||||
{
|
||||
if (why == NULL)
|
||||
why = PHYSFS_getLastError();
|
||||
fprintf(stderr, "%s failed: %s\n", what, why);
|
||||
failure = 1;
|
||||
} /* fail */
|
||||
|
||||
|
||||
static void dumpFile(const char *fname)
|
||||
{
|
||||
const int origfailure = failure;
|
||||
PHYSFS_File *out = NULL;
|
||||
PHYSFS_File *in = NULL;
|
||||
|
||||
failure = 0;
|
||||
|
||||
if ((in = PHYSFS_openRead(fname)) == NULL)
|
||||
fail("\nPHYSFS_openRead", NULL);
|
||||
else if ((out = PHYSFS_openWrite(fname)) == NULL)
|
||||
fail("\nPHYSFS_openWrite", NULL);
|
||||
else
|
||||
{
|
||||
char modstr[64];
|
||||
PHYSFS_sint64 size = PHYSFS_fileLength(in);
|
||||
|
||||
printf("(");
|
||||
if (size == -1)
|
||||
printf("?");
|
||||
else
|
||||
printf("%lld", (long long) size);
|
||||
printf(" bytes");
|
||||
|
||||
modTimeToStr(PHYSFS_getLastModTime(fname), modstr, sizeof (modstr));
|
||||
printf(", %s)\n", modstr);
|
||||
|
||||
while ( (!failure) && (!PHYSFS_eof(in)) )
|
||||
{
|
||||
static char buf[64 * 1024];
|
||||
PHYSFS_sint64 br = PHYSFS_read(in, buf, 1, sizeof (buf));
|
||||
if (br == -1)
|
||||
fail("PHYSFS_read", NULL);
|
||||
else
|
||||
{
|
||||
PHYSFS_sint64 bw = PHYSFS_write(out, buf, 1, br);
|
||||
if (bw != br)
|
||||
fail("PHYSFS_write", NULL);
|
||||
else
|
||||
size -= bw;
|
||||
} /* else */
|
||||
} /* while */
|
||||
|
||||
if ((!failure) && (size != 0))
|
||||
fail("PHYSFS_eof", "BUG! eof != PHYSFS_fileLength bytes!");
|
||||
} /* else */
|
||||
|
||||
if (in != NULL)
|
||||
PHYSFS_close(in);
|
||||
|
||||
if (out != NULL)
|
||||
{
|
||||
if (!PHYSFS_close(out))
|
||||
fail("PHYSFS_close", NULL);
|
||||
} /* if */
|
||||
|
||||
if (failure)
|
||||
PHYSFS_delete(fname);
|
||||
else
|
||||
failure = origfailure;
|
||||
} /* dumpFile */
|
||||
|
||||
|
||||
static void unpackCallback(void *_depth, const char *origdir, const char *str)
|
||||
{
|
||||
int depth = *((int *) _depth);
|
||||
const int len = strlen(origdir) + strlen(str) + 2;
|
||||
char *fname = (char *) malloc(len);
|
||||
if (fname == NULL)
|
||||
fail("malloc", "Out of memory!");
|
||||
else
|
||||
{
|
||||
if (strcmp(origdir, "/") == 0)
|
||||
origdir = "";
|
||||
|
||||
snprintf(fname, len, "%s/%s", origdir, str);
|
||||
|
||||
printf("%s ", fname);
|
||||
if (PHYSFS_isDirectory(fname))
|
||||
{
|
||||
depth++;
|
||||
printf("(directory)\n");
|
||||
if (!PHYSFS_mkdir(fname))
|
||||
fail("PHYSFS_mkdir", NULL);
|
||||
else
|
||||
PHYSFS_enumerateFilesCallback(fname, unpackCallback, &depth);
|
||||
} /* if */
|
||||
|
||||
else if (PHYSFS_isSymbolicLink(fname))
|
||||
{
|
||||
printf("(symlink)\n");
|
||||
/* !!! FIXME: ? if (!symlink(fname, */
|
||||
} /* else if */
|
||||
|
||||
else /* ...file. */
|
||||
{
|
||||
dumpFile(fname);
|
||||
} /* else */
|
||||
|
||||
free(fname);
|
||||
} /* else */
|
||||
} /* unpackCallback */
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int zero = 0;
|
||||
|
||||
if (argc != 3)
|
||||
{
|
||||
fprintf(stderr, "USAGE: %s <archive> <unpackDirectory>\n", argv[0]);
|
||||
return 1;
|
||||
} /* if */
|
||||
|
||||
if (!PHYSFS_init(argv[0]))
|
||||
{
|
||||
fprintf(stderr, "PHYSFS_init() failed: %s\n", PHYSFS_getLastError());
|
||||
return 2;
|
||||
} /* if */
|
||||
|
||||
if (!PHYSFS_setWriteDir(argv[2]))
|
||||
{
|
||||
fprintf(stderr, "PHYSFS_setWriteDir('%s') failed: %s\n",
|
||||
argv[2], PHYSFS_getLastError());
|
||||
return 3;
|
||||
} /* if */
|
||||
|
||||
if (!PHYSFS_mount(argv[1], NULL, 1))
|
||||
{
|
||||
fprintf(stderr, "PHYSFS_mount('%s') failed: %s\n",
|
||||
argv[1], PHYSFS_getLastError());
|
||||
return 4;
|
||||
} /* if */
|
||||
|
||||
PHYSFS_permitSymbolicLinks(1);
|
||||
PHYSFS_enumerateFilesCallback("/", unpackCallback, &zero);
|
||||
PHYSFS_deinit();
|
||||
if (failure)
|
||||
return 5;
|
||||
|
||||
return 0;
|
||||
} /* main */
|
||||
|
||||
/* end of physfsunpack.c ... */
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* This code shows how to read a zipfile included in an app's binary.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This file was written by Ryan C. Gordon. (icculus@icculus.org).
|
||||
*/
|
||||
|
||||
/*
|
||||
* Compile this program and then attach a .zip file to the end of the
|
||||
* compiled binary.
|
||||
*
|
||||
* On Linux, something like this will build the final binary:
|
||||
* gcc -o selfextract.tmp selfextract.c -lphysfs && \
|
||||
* cat selfextract.tmp myzipfile.zip >> selfextract && \
|
||||
* chmod a+x selfextract && \
|
||||
* rm -f selfextract.tmp
|
||||
*
|
||||
* This may not work on all platforms, and it probably only works with
|
||||
* .zip files, since they are designed to be appended to another file.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "physfs.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (!PHYSFS_init(argv[0]))
|
||||
{
|
||||
printf("PHYSFS_init() failed: %s\n", PHYSFS_getLastError());
|
||||
return 42;
|
||||
} /* if */
|
||||
|
||||
rc = PHYSFS_addToSearchPath(argv[0], 0);
|
||||
if (!rc)
|
||||
{
|
||||
printf("Couldn't find self-extract data: %s\n", PHYSFS_getLastError());
|
||||
printf("This might mean you didn't append a zipfile to the binary.\n");
|
||||
return 42;
|
||||
} /* if */
|
||||
|
||||
char **files = PHYSFS_enumerateFiles("/");
|
||||
char **i;
|
||||
for (i = files; *i != NULL; i++)
|
||||
{
|
||||
const char *dirorfile = PHYSFS_isDirectory(*i) ? "Directory" : "File";
|
||||
printf(" * %s '%s' is in root of attached data.\n", dirorfile, *i);
|
||||
} /* for */
|
||||
PHYSFS_freeList(files);
|
||||
|
||||
return 0;
|
||||
} /* main */
|
||||
|
||||
Executable
+10
@@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ ! -f "./install_manifest.txt" ]; then
|
||||
echo "ERROR: This needs to be run from your CMake build directory after installing." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
xargs rm -vf < install_manifest.txt
|
||||
exit 0
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
assert(io == NULL); /* shouldn't create an Io for these. */
|
||||
BAIL_IF_MACRO(!__PHYSFS_platformStat(name, &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(void *opaque, const char *dname,
|
||||
PHYSFS_EnumFilesCallback cb,
|
||||
const char *origdir, void *callbackdata)
|
||||
{
|
||||
char *d;
|
||||
|
||||
CVT_TO_DEPENDENT(d, opaque, dname);
|
||||
if (d != NULL)
|
||||
{
|
||||
__PHYSFS_platformEnumerateFiles(d, cb, origdir, callbackdata);
|
||||
__PHYSFS_smallFree(d);
|
||||
} /* if */
|
||||
} /* DIR_enumerateFiles */
|
||||
|
||||
|
||||
static PHYSFS_Io *doOpen(void *opaque, const char *name, const int mode)
|
||||
{
|
||||
PHYSFS_Io *io = NULL;
|
||||
char *f = NULL;
|
||||
|
||||
CVT_TO_DEPENDENT(f, opaque, name);
|
||||
BAIL_IF_MACRO(!f, ERRPASS, NULL);
|
||||
|
||||
io = __PHYSFS_createNativeIo(f, mode);
|
||||
if (io == NULL)
|
||||
{
|
||||
const PHYSFS_ErrorCode err = PHYSFS_getLastErrorCode();
|
||||
PHYSFS_Stat statbuf;
|
||||
__PHYSFS_platformStat(f, &statbuf);
|
||||
PHYSFS_setErrorCode(err);
|
||||
} /* if */
|
||||
|
||||
__PHYSFS_smallFree(f);
|
||||
|
||||
return io;
|
||||
} /* doOpen */
|
||||
|
||||
|
||||
static PHYSFS_Io *DIR_openRead(void *opaque, const char *filename)
|
||||
{
|
||||
return doOpen(opaque, filename, 'r');
|
||||
} /* DIR_openRead */
|
||||
|
||||
|
||||
static PHYSFS_Io *DIR_openWrite(void *opaque, const char *filename)
|
||||
{
|
||||
return doOpen(opaque, filename, 'w');
|
||||
} /* DIR_openWrite */
|
||||
|
||||
|
||||
static PHYSFS_Io *DIR_openAppend(void *opaque, const char *filename)
|
||||
{
|
||||
return doOpen(opaque, filename, 'a');
|
||||
} /* DIR_openAppend */
|
||||
|
||||
|
||||
static int DIR_remove(void *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(void *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(void *opaque)
|
||||
{
|
||||
allocator.Free(opaque);
|
||||
} /* DIR_closeArchive */
|
||||
|
||||
|
||||
static int DIR_stat(void *opaque, const char *name, PHYSFS_Stat *stat)
|
||||
{
|
||||
int retval = 0;
|
||||
char *d;
|
||||
|
||||
CVT_TO_DEPENDENT(d, opaque, name);
|
||||
BAIL_IF_MACRO(!d, ERRPASS, 0);
|
||||
retval = __PHYSFS_platformStat(d, stat);
|
||||
__PHYSFS_smallFree(d);
|
||||
return retval;
|
||||
} /* DIR_stat */
|
||||
|
||||
|
||||
const PHYSFS_Archiver __PHYSFS_Archiver_DIR =
|
||||
{
|
||||
CURRENT_PHYSFS_ARCHIVER_API_VERSION,
|
||||
{
|
||||
"",
|
||||
"Non-archive, direct filesystem I/O",
|
||||
"Ryan C. Gordon <icculus@icculus.org>",
|
||||
"http://icculus.org/physfs/",
|
||||
1, /* supportsSymlinks */
|
||||
},
|
||||
DIR_openArchive,
|
||||
DIR_enumerateFiles,
|
||||
DIR_openRead,
|
||||
DIR_openWrite,
|
||||
DIR_openAppend,
|
||||
DIR_remove,
|
||||
DIR_mkdir,
|
||||
DIR_stat,
|
||||
DIR_closeArchive
|
||||
};
|
||||
|
||||
/* end of archiver_dir.c ... */
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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 =
|
||||
{
|
||||
CURRENT_PHYSFS_ARCHIVER_API_VERSION,
|
||||
{
|
||||
"GRP",
|
||||
"Build engine Groupfile format",
|
||||
"Ryan C. Gordon <icculus@icculus.org>",
|
||||
"http://icculus.org/physfs/",
|
||||
0, /* supportsSymlinks */
|
||||
},
|
||||
GRP_openArchive,
|
||||
UNPK_enumerateFiles,
|
||||
UNPK_openRead,
|
||||
UNPK_openWrite,
|
||||
UNPK_openAppend,
|
||||
UNPK_remove,
|
||||
UNPK_mkdir,
|
||||
UNPK_stat,
|
||||
UNPK_closeArchive
|
||||
};
|
||||
|
||||
#endif /* defined PHYSFS_SUPPORTS_GRP */
|
||||
|
||||
/* end of archiver_grp.c ... */
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* 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 =
|
||||
{
|
||||
CURRENT_PHYSFS_ARCHIVER_API_VERSION,
|
||||
{
|
||||
"HOG",
|
||||
"Descent I/II HOG file format",
|
||||
"Bradley Bell <btb@icculus.org>",
|
||||
"http://icculus.org/physfs/",
|
||||
0, /* supportsSymlinks */
|
||||
},
|
||||
HOG_openArchive,
|
||||
UNPK_enumerateFiles,
|
||||
UNPK_openRead,
|
||||
UNPK_openWrite,
|
||||
UNPK_openAppend,
|
||||
UNPK_remove,
|
||||
UNPK_mkdir,
|
||||
UNPK_stat,
|
||||
UNPK_closeArchive
|
||||
};
|
||||
|
||||
#endif /* defined PHYSFS_SUPPORTS_HOG */
|
||||
|
||||
/* end of archiver_hog.c ... */
|
||||
|
||||
@@ -0,0 +1,961 @@
|
||||
/*
|
||||
* 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 <time.h>
|
||||
|
||||
/* 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_NOT_FOUND /* !!! FIXME: PHYSFS_ERR_BAD_FILENAME */, -1);
|
||||
BAIL_IF_MACRO(lastfound == (descriptor->filenamelen -1), PHYSFS_ERR_NOT_FOUND /* !!! 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)
|
||||
{
|
||||
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;
|
||||
|
||||
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) )
|
||||
return 0; /* no subpaths left and we found the entry */
|
||||
|
||||
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
|
||||
{
|
||||
/* !!! FIXME: set PHYSFS_ERR_NOT_FOUND? */
|
||||
/* we're at a file but have a remaining subpath -> no match */
|
||||
return 0;
|
||||
} /* else */
|
||||
} /* if */
|
||||
} /* while */
|
||||
|
||||
/* !!! FIXME: set PHYSFS_ERR_NOT_FOUND? */
|
||||
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(void *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(void *opaque, const char *filename)
|
||||
{
|
||||
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);
|
||||
GOTO_IF_MACRO(rc, ERRPASS, 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(void *opaque, const char *dname,
|
||||
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);
|
||||
BAIL_IF_MACRO(iso_find_dir_entry(handle,dname, &descriptor), 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(void *opaque, const char *name, PHYSFS_Stat *stat)
|
||||
{
|
||||
ISO9660Handle *handle = (ISO9660Handle*) opaque;
|
||||
ISO9660FileDescriptor descriptor;
|
||||
ISO9660ExtAttributeRec extattr;
|
||||
BAIL_IF_MACRO(iso_find_dir_entry(handle, name, &descriptor), ERRPASS, -1);
|
||||
|
||||
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(void *opaque, const char *name)
|
||||
{
|
||||
BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
|
||||
} /* ISO9660_openWrite */
|
||||
|
||||
|
||||
static PHYSFS_Io *ISO9660_openAppend(void *opaque, const char *name)
|
||||
{
|
||||
BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
|
||||
} /* ISO9660_openAppend */
|
||||
|
||||
|
||||
static int ISO9660_remove(void *opaque, const char *name)
|
||||
{
|
||||
BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
|
||||
} /* ISO9660_remove */
|
||||
|
||||
|
||||
static int ISO9660_mkdir(void *opaque, const char *name)
|
||||
{
|
||||
BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
|
||||
} /* ISO9660_mkdir */
|
||||
|
||||
|
||||
const PHYSFS_Archiver __PHYSFS_Archiver_ISO9660 =
|
||||
{
|
||||
CURRENT_PHYSFS_ARCHIVER_API_VERSION,
|
||||
{
|
||||
"ISO",
|
||||
"ISO9660 image file",
|
||||
"Christoph Nelles <evilazrael@evilazrael.de>",
|
||||
"http://www.evilazrael.de/",
|
||||
0, /* supportsSymlinks */
|
||||
},
|
||||
ISO9660_openArchive,
|
||||
ISO9660_enumerateFiles,
|
||||
ISO9660_openRead,
|
||||
ISO9660_openWrite,
|
||||
ISO9660_openAppend,
|
||||
ISO9660_remove,
|
||||
ISO9660_mkdir,
|
||||
ISO9660_stat,
|
||||
ISO9660_closeArchive
|
||||
};
|
||||
|
||||
#endif /* defined PHYSFS_SUPPORTS_ISO9660 */
|
||||
|
||||
/* end of archiver_iso9660.c ... */
|
||||
|
||||
@@ -0,0 +1,699 @@
|
||||
/*
|
||||
* 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_NOT_FOUND, 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_setErrorCode(PHYSFS_ERR_CORRUPT); /*!!!FIXME: was "PHYSFS_ERR_DATA_ERROR" */
|
||||
break;
|
||||
case SZE_OUTOFMEMORY:
|
||||
PHYSFS_setErrorCode(PHYSFS_ERR_OUT_OF_MEMORY);
|
||||
break;
|
||||
case SZE_CRC_ERROR:
|
||||
PHYSFS_setErrorCode(PHYSFS_ERR_CORRUPT);
|
||||
break;
|
||||
case SZE_NOTIMPL:
|
||||
PHYSFS_setErrorCode(PHYSFS_ERR_UNSUPPORTED);
|
||||
break;
|
||||
case SZE_FAIL:
|
||||
PHYSFS_setErrorCode(PHYSFS_ERR_OTHER_ERROR); /* !!! FIXME: right? */
|
||||
break;
|
||||
case SZE_ARCHIVE_ERROR:
|
||||
PHYSFS_setErrorCode(PHYSFS_ERR_CORRUPT); /* !!! FIXME: right? */
|
||||
break;
|
||||
default:
|
||||
PHYSFS_setErrorCode(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(void *opaque, const char *dname,
|
||||
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_NOT_FOUND, );
|
||||
|
||||
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(void *opaque, const char *name)
|
||||
{
|
||||
LZMAarchive *archive = (LZMAarchive *) opaque;
|
||||
LZMAfile *file = lzma_find_file(archive, name);
|
||||
PHYSFS_Io *io = NULL;
|
||||
|
||||
BAIL_IF_MACRO(file == NULL, PHYSFS_ERR_NOT_FOUND, 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(void *opaque, const char *filename)
|
||||
{
|
||||
BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
|
||||
} /* LZMA_openWrite */
|
||||
|
||||
|
||||
static PHYSFS_Io *LZMA_openAppend(void *opaque, const char *filename)
|
||||
{
|
||||
BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
|
||||
} /* LZMA_openAppend */
|
||||
|
||||
|
||||
static void LZMA_closeArchive(void *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(void *opaque, const char *name)
|
||||
{
|
||||
BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
|
||||
} /* LZMA_remove */
|
||||
|
||||
|
||||
static int LZMA_mkdir(void *opaque, const char *name)
|
||||
{
|
||||
BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
|
||||
} /* LZMA_mkdir */
|
||||
|
||||
static int LZMA_stat(void *opaque, const char *filename, PHYSFS_Stat *stat)
|
||||
{
|
||||
const LZMAarchive *archive = (const LZMAarchive *) opaque;
|
||||
const LZMAfile *file = lzma_find_file(archive, filename);
|
||||
|
||||
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 =
|
||||
{
|
||||
CURRENT_PHYSFS_ARCHIVER_API_VERSION,
|
||||
{
|
||||
"7Z",
|
||||
"LZMA (7zip) format",
|
||||
"Dennis Schridde <devurandom@gmx.net>",
|
||||
"http://icculus.org/physfs/",
|
||||
0, /* supportsSymlinks */
|
||||
},
|
||||
LZMA_openArchive,
|
||||
LZMA_enumerateFiles,
|
||||
LZMA_openRead,
|
||||
LZMA_openWrite,
|
||||
LZMA_openAppend,
|
||||
LZMA_remove,
|
||||
LZMA_mkdir,
|
||||
LZMA_stat,
|
||||
LZMA_closeArchive
|
||||
};
|
||||
|
||||
#endif /* defined PHYSFS_SUPPORTS_7Z */
|
||||
|
||||
/* end of archiver_lzma.c ... */
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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 =
|
||||
{
|
||||
CURRENT_PHYSFS_ARCHIVER_API_VERSION,
|
||||
{
|
||||
"MVL",
|
||||
"Descent II Movielib format",
|
||||
"Bradley Bell <btb@icculus.org>",
|
||||
"http://icculus.org/physfs/",
|
||||
0, /* supportsSymlinks */
|
||||
},
|
||||
MVL_openArchive,
|
||||
UNPK_enumerateFiles,
|
||||
UNPK_openRead,
|
||||
UNPK_openWrite,
|
||||
UNPK_openAppend,
|
||||
UNPK_remove,
|
||||
UNPK_mkdir,
|
||||
UNPK_stat,
|
||||
UNPK_closeArchive
|
||||
};
|
||||
|
||||
#endif /* defined PHYSFS_SUPPORTS_MVL */
|
||||
|
||||
/* end of archiver_mvl.c ... */
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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 =
|
||||
{
|
||||
CURRENT_PHYSFS_ARCHIVER_API_VERSION,
|
||||
{
|
||||
"PAK",
|
||||
"Quake I/II format",
|
||||
"Ryan C. Gordon <icculus@icculus.org>",
|
||||
"http://icculus.org/physfs/",
|
||||
0, /* supportsSymlinks */
|
||||
},
|
||||
QPAK_openArchive,
|
||||
UNPK_enumerateFiles,
|
||||
UNPK_openRead,
|
||||
UNPK_openWrite,
|
||||
UNPK_openAppend,
|
||||
UNPK_remove,
|
||||
UNPK_mkdir,
|
||||
UNPK_stat,
|
||||
UNPK_closeArchive
|
||||
};
|
||||
|
||||
#endif /* defined PHYSFS_SUPPORTS_QPAK */
|
||||
|
||||
/* end of archiver_qpak.c ... */
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* SLB support routines for PhysicsFS.
|
||||
*
|
||||
* This driver handles SLB archives ("slab files"). This uncompressed format
|
||||
* is used in I-War / Independence War and Independence War: Defiance.
|
||||
*
|
||||
* The format begins with four zero bytes (version?), the file count and the
|
||||
* location of the table of contents. Each ToC entry contains a 64-byte buffer
|
||||
* containing a zero-terminated filename, the offset of the data, and its size.
|
||||
* All the filenames begin with the separator character '\'.
|
||||
*
|
||||
* Please see the file LICENSE.txt in the source's root directory.
|
||||
*
|
||||
* This file written by Aleksi Nurmi, based on the GRP archiver by
|
||||
* Ryan C. Gordon.
|
||||
*/
|
||||
|
||||
#define __PHYSICSFS_INTERNAL__
|
||||
#include "physfs_internal.h"
|
||||
|
||||
#if PHYSFS_SUPPORTS_SLB
|
||||
|
||||
static UNPKentry *slbLoadEntries(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++)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
/* don't include the '\' in the beginning */
|
||||
char backslash;
|
||||
GOTO_IF_MACRO(!__PHYSFS_readAll(io, &backslash, 1), ERRPASS, failed);
|
||||
GOTO_IF_MACRO(backslash != '\\', ERRPASS, failed);
|
||||
|
||||
/* read the rest of the buffer, 63 bytes */
|
||||
GOTO_IF_MACRO(!__PHYSFS_readAll(io, &entry->name, 63), ERRPASS, failed);
|
||||
entry->name[63] = '\0'; /* in case the name lacks the null terminator */
|
||||
|
||||
/* convert backslashes */
|
||||
for (ptr = entry->name; *ptr; ptr++)
|
||||
{
|
||||
if (*ptr == '\\')
|
||||
*ptr = '/';
|
||||
} /* for */
|
||||
|
||||
GOTO_IF_MACRO(!__PHYSFS_readAll(io, &entry->startPos, 4),
|
||||
ERRPASS, failed);
|
||||
entry->startPos = PHYSFS_swapULE32(entry->startPos);
|
||||
|
||||
GOTO_IF_MACRO(!__PHYSFS_readAll(io, &entry->size, 4), ERRPASS, failed);
|
||||
entry->size = PHYSFS_swapULE32(entry->size);
|
||||
} /* for */
|
||||
|
||||
return entries;
|
||||
|
||||
failed:
|
||||
allocator.Free(entries);
|
||||
return NULL;
|
||||
|
||||
} /* slbLoadEntries */
|
||||
|
||||
|
||||
static void *SLB_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
|
||||
{
|
||||
PHYSFS_uint32 version;
|
||||
PHYSFS_uint32 count = 0;
|
||||
PHYSFS_uint32 tocPos = 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, &version, sizeof(version)),
|
||||
ERRPASS, NULL);
|
||||
version = PHYSFS_swapULE32(version);
|
||||
BAIL_IF_MACRO(version != 0, ERRPASS, NULL);
|
||||
|
||||
BAIL_IF_MACRO(!__PHYSFS_readAll(io, &count, sizeof(count)), ERRPASS, NULL);
|
||||
count = PHYSFS_swapULE32(count);
|
||||
|
||||
/* offset of the table of contents */
|
||||
BAIL_IF_MACRO(!__PHYSFS_readAll(io, &tocPos, sizeof(tocPos)),
|
||||
ERRPASS, NULL);
|
||||
tocPos = PHYSFS_swapULE32(tocPos);
|
||||
|
||||
/* seek to the table of contents */
|
||||
BAIL_IF_MACRO(!io->seek(io, tocPos), ERRPASS, NULL);
|
||||
|
||||
entries = slbLoadEntries(io, count);
|
||||
BAIL_IF_MACRO(!entries, ERRPASS, NULL);
|
||||
|
||||
return UNPK_openArchive(io, entries, count);
|
||||
} /* SLB_openArchive */
|
||||
|
||||
|
||||
const PHYSFS_Archiver __PHYSFS_Archiver_SLB =
|
||||
{
|
||||
CURRENT_PHYSFS_ARCHIVER_API_VERSION,
|
||||
{
|
||||
"SLB",
|
||||
"I-War / Independence War Slab file",
|
||||
"Aleksi Nurmi <aleksi.nurmi@gmail.com>",
|
||||
"http://bitbucket.org/ahnurmi/",
|
||||
0, /* supportsSymlinks */
|
||||
},
|
||||
SLB_openArchive,
|
||||
UNPK_enumerateFiles,
|
||||
UNPK_openRead,
|
||||
UNPK_openWrite,
|
||||
UNPK_openAppend,
|
||||
UNPK_remove,
|
||||
UNPK_mkdir,
|
||||
UNPK_stat,
|
||||
UNPK_closeArchive
|
||||
};
|
||||
|
||||
#endif /* defined PHYSFS_SUPPORTS_SLB */
|
||||
|
||||
/* end of archiver_slb.c ... */
|
||||
|
||||
@@ -0,0 +1,464 @@
|
||||
/*
|
||||
* 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 <= 64 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(void *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(void *opaque, const char *dname,
|
||||
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_NOT_FOUND, NULL);
|
||||
} /* findEntry */
|
||||
|
||||
|
||||
PHYSFS_Io *UNPK_openRead(void *opaque, const char *name)
|
||||
{
|
||||
PHYSFS_Io *retval = NULL;
|
||||
UNPKinfo *info = (UNPKinfo *) opaque;
|
||||
UNPKfileinfo *finfo = NULL;
|
||||
int isdir = 0;
|
||||
UNPKentry *entry = findEntry(info, name, &isdir);
|
||||
|
||||
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(void *opaque, const char *name)
|
||||
{
|
||||
BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
|
||||
} /* UNPK_openWrite */
|
||||
|
||||
|
||||
PHYSFS_Io *UNPK_openAppend(void *opaque, const char *name)
|
||||
{
|
||||
BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
|
||||
} /* UNPK_openAppend */
|
||||
|
||||
|
||||
int UNPK_remove(void *opaque, const char *name)
|
||||
{
|
||||
BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
|
||||
} /* UNPK_remove */
|
||||
|
||||
|
||||
int UNPK_mkdir(void *opaque, const char *name)
|
||||
{
|
||||
BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
|
||||
} /* UNPK_mkdir */
|
||||
|
||||
|
||||
int UNPK_stat(void *opaque, const char *filename, PHYSFS_Stat *stat)
|
||||
{
|
||||
int isDir = 0;
|
||||
const UNPKinfo *info = (const UNPKinfo *) opaque;
|
||||
const UNPKentry *entry = findEntry(info, filename, &isDir);
|
||||
|
||||
if (isDir)
|
||||
{
|
||||
stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
|
||||
stat->filesize = 0;
|
||||
} /* if */
|
||||
else if (entry != NULL)
|
||||
{
|
||||
stat->filetype = PHYSFS_FILETYPE_REGULAR;
|
||||
stat->filesize = entry->size;
|
||||
} /* else if */
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
} /* else */
|
||||
|
||||
stat->modtime = -1;
|
||||
stat->createtime = -1;
|
||||
stat->accesstime = -1;
|
||||
stat->readonly = 1;
|
||||
|
||||
return 1;
|
||||
} /* UNPK_stat */
|
||||
|
||||
|
||||
void *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 ... */
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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 =
|
||||
{
|
||||
CURRENT_PHYSFS_ARCHIVER_API_VERSION,
|
||||
{
|
||||
"WAD",
|
||||
"DOOM engine format",
|
||||
"Travis Wells <traviswells@mchsi.com>",
|
||||
"http://www.3dmm2.com/doom/",
|
||||
0, /* supportsSymlinks */
|
||||
},
|
||||
WAD_openArchive,
|
||||
UNPK_enumerateFiles,
|
||||
UNPK_openRead,
|
||||
UNPK_openWrite,
|
||||
UNPK_openAppend,
|
||||
UNPK_remove,
|
||||
UNPK_mkdir,
|
||||
UNPK_stat,
|
||||
UNPK_closeArchive
|
||||
};
|
||||
|
||||
#endif /* defined PHYSFS_SUPPORTS_WAD */
|
||||
|
||||
/* end of archiver_wad.c ... */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,237 @@
|
||||
7z ANSI-C Decoder 4.48
|
||||
----------------------
|
||||
|
||||
7z ANSI-C Decoder 4.48 Copyright (C) 1999-2006 Igor Pavlov
|
||||
|
||||
7z ANSI-C provides 7z/LZMA decoding.
|
||||
7z ANSI-C version is simplified version ported from C++ code.
|
||||
|
||||
LZMA is default and general compression method of 7z format
|
||||
in 7-Zip compression program (www.7-zip.org). LZMA provides high
|
||||
compression ratio and very fast decompression.
|
||||
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
|
||||
Read lzma.txt for information about license.
|
||||
|
||||
|
||||
Files
|
||||
---------------------
|
||||
|
||||
7zAlloc.* - Allocate and Free
|
||||
7zBuffer.* - Buffer structure
|
||||
7zCrc.* - CRC32 code
|
||||
7zDecode.* - Low level memory->memory decoding
|
||||
7zExtract.* - High level stream->memory decoding
|
||||
7zHeader.* - .7z format constants
|
||||
7zIn.* - .7z archive opening
|
||||
7zItem.* - .7z structures
|
||||
7zMain.c - Test application
|
||||
7zMethodID.* - MethodID structure
|
||||
7zTypes.h - Base types and constants
|
||||
|
||||
|
||||
How To Use
|
||||
----------
|
||||
|
||||
You must download 7-Zip program from www.7-zip.org.
|
||||
|
||||
You can create .7z archive with 7z.exe or 7za.exe:
|
||||
|
||||
7za.exe a archive.7z *.htm -r -mx -m0fb=255
|
||||
|
||||
If you have big number of files in archive, and you need fast extracting,
|
||||
you can use partly-solid archives:
|
||||
|
||||
7za.exe a archive.7z *.htm -ms=512K -r -mx -m0fb=255 -m0d=512K
|
||||
|
||||
In that example 7-Zip will use 512KB solid blocks. So it needs to decompress only
|
||||
512KB for extracting one file from such archive.
|
||||
|
||||
|
||||
Limitations of current version of 7z ANSI-C Decoder
|
||||
---------------------------------------------------
|
||||
|
||||
- It reads only "FileName", "Size", "LastWriteTime" and "CRC" information for each file in archive.
|
||||
- It supports only LZMA and Copy (no compression) methods with BCJ or BCJ2 filters.
|
||||
- It converts original UTF-16 Unicode file names to UTF-8 Unicode file names.
|
||||
|
||||
These limitations will be fixed in future versions.
|
||||
|
||||
|
||||
Using 7z ANSI-C Decoder Test application:
|
||||
-----------------------------------------
|
||||
|
||||
Usage: 7zDec <command> <archive_name>
|
||||
|
||||
<Command>:
|
||||
e: Extract files from archive
|
||||
l: List contents of archive
|
||||
t: Test integrity of archive
|
||||
|
||||
Example:
|
||||
|
||||
7zDec l archive.7z
|
||||
|
||||
lists contents of archive.7z
|
||||
|
||||
7zDec e archive.7z
|
||||
|
||||
extracts files from archive.7z to current folder.
|
||||
|
||||
|
||||
How to use .7z Decoder
|
||||
----------------------
|
||||
|
||||
.7z Decoder can be compiled in one of two modes:
|
||||
|
||||
1) Default mode. In that mode 7z Decoder will read full compressed
|
||||
block to RAM before decompressing.
|
||||
|
||||
2) Mode with defined _LZMA_IN_CB. In that mode 7z Decoder can read
|
||||
compressed block by parts. And you can specify desired buffer size.
|
||||
So memory requirements can be reduced. But decompressing speed will
|
||||
be 5-10% lower and code size is slightly larger.
|
||||
|
||||
|
||||
Memory allocation
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
7z Decoder uses two memory pools:
|
||||
1) Temporary pool
|
||||
2) Main pool
|
||||
Such scheme can allow you to avoid fragmentation of allocated blocks.
|
||||
|
||||
Steps for using 7z decoder
|
||||
--------------------------
|
||||
|
||||
Use code at 7zMain.c as example.
|
||||
|
||||
1) Declare variables:
|
||||
inStream /* implements ISzInStream interface */
|
||||
CArchiveDatabaseEx db; /* 7z archive database structure */
|
||||
ISzAlloc allocImp; /* memory functions for main pool */
|
||||
ISzAlloc allocTempImp; /* memory functions for temporary pool */
|
||||
|
||||
2) call InitCrcTable(); function to initialize CRC structures.
|
||||
|
||||
3) call SzArDbExInit(&db); function to initialize db structures.
|
||||
|
||||
4) call SzArchiveOpen(inStream, &db, &allocMain, &allocTemp) to open archive
|
||||
|
||||
This function opens archive "inStream" and reads headers to "db".
|
||||
All items in "db" will be allocated with "allocMain" functions.
|
||||
SzArchiveOpen function allocates and frees temporary structures by "allocTemp" functions.
|
||||
|
||||
5) List items or Extract items
|
||||
|
||||
Listing code:
|
||||
~~~~~~~~~~~~~
|
||||
{
|
||||
UInt32 i;
|
||||
for (i = 0; i < db.Database.NumFiles; i++)
|
||||
{
|
||||
CFileItem *f = db.Database.Files + i;
|
||||
printf("%10d %s\n", (int)f->Size, f->Name);
|
||||
}
|
||||
}
|
||||
|
||||
Extracting code:
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
SZ_RESULT SzExtract(
|
||||
ISzInStream *inStream,
|
||||
CArchiveDatabaseEx *db,
|
||||
UInt32 fileIndex, /* index of file */
|
||||
UInt32 *blockIndex, /* index of solid block */
|
||||
Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */
|
||||
size_t *outBufferSize, /* buffer size for output buffer */
|
||||
size_t *offset, /* offset of stream for required file in *outBuffer */
|
||||
size_t *outSizeProcessed, /* size of file in *outBuffer */
|
||||
ISzAlloc *allocMain,
|
||||
ISzAlloc *allocTemp);
|
||||
|
||||
If you need to decompress more than one file, you can send these values from previous call:
|
||||
blockIndex,
|
||||
outBuffer,
|
||||
outBufferSize,
|
||||
You can consider "outBuffer" as cache of solid block. If your archive is solid,
|
||||
it will increase decompression speed.
|
||||
|
||||
After decompressing you must free "outBuffer":
|
||||
allocImp.Free(outBuffer);
|
||||
|
||||
6) call SzArDbExFree(&db, allocImp.Free) to free allocated items in "db".
|
||||
|
||||
|
||||
|
||||
|
||||
Memory requirements for .7z decoding
|
||||
------------------------------------
|
||||
|
||||
Memory usage for Archive opening:
|
||||
- Temporary pool:
|
||||
- Memory for compressed .7z headers (if _LZMA_IN_CB is not defined)
|
||||
- Memory for uncompressed .7z headers
|
||||
- some other temporary blocks
|
||||
- Main pool:
|
||||
- Memory for database:
|
||||
Estimated size of one file structures in solid archive:
|
||||
- Size (4 or 8 Bytes)
|
||||
- CRC32 (4 bytes)
|
||||
- LastWriteTime (8 bytes)
|
||||
- Some file information (4 bytes)
|
||||
- File Name (variable length) + pointer + allocation structures
|
||||
|
||||
Memory usage for archive Decompressing:
|
||||
- Temporary pool:
|
||||
- Memory for compressed solid block (if _LZMA_IN_CB is not defined)
|
||||
- Memory for LZMA decompressing structures
|
||||
- Main pool:
|
||||
- Memory for decompressed solid block
|
||||
- Memory for temprorary buffers, if BCJ2 fileter is used. Usually these
|
||||
temprorary buffers can be about 15% of solid block size.
|
||||
|
||||
|
||||
If _LZMA_IN_CB is defined, 7z Decoder will not allocate memory for
|
||||
compressed blocks. Instead of this, you must allocate buffer with desired
|
||||
size before calling 7z Decoder. Use 7zMain.c as example.
|
||||
|
||||
|
||||
|
||||
EXIT codes
|
||||
-----------
|
||||
|
||||
7z Decoder functions can return one of the following codes:
|
||||
|
||||
#define SZ_OK (0)
|
||||
#define SZE_DATA_ERROR (1)
|
||||
#define SZE_OUTOFMEMORY (2)
|
||||
#define SZE_CRC_ERROR (3)
|
||||
|
||||
#define SZE_NOTIMPL (4)
|
||||
#define SZE_FAIL (5)
|
||||
|
||||
#define SZE_ARCHIVE_ERROR (6)
|
||||
|
||||
|
||||
|
||||
LZMA Defines
|
||||
------------
|
||||
|
||||
_LZMA_IN_CB - Use special callback mode for input stream to reduce memory requirements
|
||||
|
||||
_SZ_FILE_SIZE_32 - define it if you need only support for files smaller than 4 GB
|
||||
_SZ_NO_INT_64 - define it if your compiler doesn't support long long int or __int64.
|
||||
|
||||
_LZMA_PROB32 - it can increase LZMA decompressing speed on some 32-bit CPUs.
|
||||
|
||||
_SZ_ALLOC_DEBUG - define it if you want to debug alloc/free operations to stderr.
|
||||
|
||||
|
||||
---
|
||||
|
||||
http://www.7-zip.org
|
||||
http://www.7-zip.org/support.html
|
||||
@@ -0,0 +1,471 @@
|
||||
7z Format description (2.30 Beta 25)
|
||||
-----------------------------------
|
||||
|
||||
This file contains description of 7z archive format.
|
||||
7z archive can contain files compressed with any method.
|
||||
See "Methods.txt" for description for defined compressing methods.
|
||||
|
||||
|
||||
Format structure Overview
|
||||
-------------------------
|
||||
|
||||
Some fields can be optional.
|
||||
|
||||
Archive structure
|
||||
~~~~~~~~~~~~~~~~~
|
||||
SignatureHeader
|
||||
[PackedStreams]
|
||||
[PackedStreamsForHeaders]
|
||||
[
|
||||
Header
|
||||
or
|
||||
{
|
||||
Packed Header
|
||||
HeaderInfo
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
|
||||
Header structure
|
||||
~~~~~~~~~~~~~~~~
|
||||
{
|
||||
ArchiveProperties
|
||||
AdditionalStreams
|
||||
{
|
||||
PackInfo
|
||||
{
|
||||
PackPos
|
||||
NumPackStreams
|
||||
Sizes[NumPackStreams]
|
||||
CRCs[NumPackStreams]
|
||||
}
|
||||
CodersInfo
|
||||
{
|
||||
NumFolders
|
||||
Folders[NumFolders]
|
||||
{
|
||||
NumCoders
|
||||
CodersInfo[NumCoders]
|
||||
{
|
||||
ID
|
||||
NumInStreams;
|
||||
NumOutStreams;
|
||||
PropertiesSize
|
||||
Properties[PropertiesSize]
|
||||
}
|
||||
NumBindPairs
|
||||
BindPairsInfo[NumBindPairs]
|
||||
{
|
||||
InIndex;
|
||||
OutIndex;
|
||||
}
|
||||
PackedIndices
|
||||
}
|
||||
UnPackSize[Folders][Folders.NumOutstreams]
|
||||
CRCs[NumFolders]
|
||||
}
|
||||
SubStreamsInfo
|
||||
{
|
||||
NumUnPackStreamsInFolders[NumFolders];
|
||||
UnPackSizes[]
|
||||
CRCs[]
|
||||
}
|
||||
}
|
||||
MainStreamsInfo
|
||||
{
|
||||
(Same as in AdditionalStreams)
|
||||
}
|
||||
FilesInfo
|
||||
{
|
||||
NumFiles
|
||||
Properties[]
|
||||
{
|
||||
ID
|
||||
Size
|
||||
Data
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HeaderInfo structure
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
{
|
||||
(Same as in AdditionalStreams)
|
||||
}
|
||||
|
||||
|
||||
|
||||
Notes about Notation and encoding
|
||||
---------------------------------
|
||||
|
||||
7z uses little endian encoding.
|
||||
|
||||
7z archive format has optional headers that are marked as
|
||||
[]
|
||||
Header
|
||||
[]
|
||||
|
||||
REAL_UINT64 means real UINT64.
|
||||
|
||||
UINT64 means real UINT64 encoded with the following scheme:
|
||||
|
||||
Size of encoding sequence depends from first byte:
|
||||
First_Byte Extra_Bytes Value
|
||||
(binary)
|
||||
0xxxxxxx : ( xxxxxxx )
|
||||
10xxxxxx BYTE y[1] : ( xxxxxx << (8 * 1)) + y
|
||||
110xxxxx BYTE y[2] : ( xxxxx << (8 * 2)) + y
|
||||
...
|
||||
1111110x BYTE y[6] : ( x << (8 * 6)) + y
|
||||
11111110 BYTE y[7] : y
|
||||
11111111 BYTE y[8] : y
|
||||
|
||||
|
||||
|
||||
Property IDs
|
||||
------------
|
||||
|
||||
0x00 = kEnd,
|
||||
|
||||
0x01 = kHeader,
|
||||
|
||||
0x02 = kArchiveProperties,
|
||||
|
||||
0x03 = kAdditionalStreamsInfo,
|
||||
0x04 = kMainStreamsInfo,
|
||||
0x05 = kFilesInfo,
|
||||
|
||||
0x06 = kPackInfo,
|
||||
0x07 = kUnPackInfo,
|
||||
0x08 = kSubStreamsInfo,
|
||||
|
||||
0x09 = kSize,
|
||||
0x0A = kCRC,
|
||||
|
||||
0x0B = kFolder,
|
||||
|
||||
0x0C = kCodersUnPackSize,
|
||||
0x0D = kNumUnPackStream,
|
||||
|
||||
0x0E = kEmptyStream,
|
||||
0x0F = kEmptyFile,
|
||||
0x10 = kAnti,
|
||||
|
||||
0x11 = kName,
|
||||
0x12 = kCreationTime,
|
||||
0x13 = kLastAccessTime,
|
||||
0x14 = kLastWriteTime,
|
||||
0x15 = kWinAttributes,
|
||||
0x16 = kComment,
|
||||
|
||||
0x17 = kEncodedHeader,
|
||||
|
||||
|
||||
7z format headers
|
||||
-----------------
|
||||
|
||||
SignatureHeader
|
||||
~~~~~~~~~~~~~~~
|
||||
BYTE kSignature[6] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
|
||||
|
||||
ArchiveVersion
|
||||
{
|
||||
BYTE Major; // now = 0
|
||||
BYTE Minor; // now = 2
|
||||
};
|
||||
|
||||
UINT32 StartHeaderCRC;
|
||||
|
||||
StartHeader
|
||||
{
|
||||
REAL_UINT64 NextHeaderOffset
|
||||
REAL_UINT64 NextHeaderSize
|
||||
UINT32 NextHeaderCRC
|
||||
}
|
||||
|
||||
|
||||
...........................
|
||||
|
||||
|
||||
ArchiveProperties
|
||||
~~~~~~~~~~~~~~~~~
|
||||
BYTE NID::kArchiveProperties (0x02)
|
||||
for (;;)
|
||||
{
|
||||
BYTE PropertyType;
|
||||
if (aType == 0)
|
||||
break;
|
||||
UINT64 PropertySize;
|
||||
BYTE PropertyData[PropertySize];
|
||||
}
|
||||
|
||||
|
||||
Digests (NumStreams)
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
BYTE AllAreDefined
|
||||
if (AllAreDefined == 0)
|
||||
{
|
||||
for(NumStreams)
|
||||
BIT Defined
|
||||
}
|
||||
UINT32 CRCs[NumDefined]
|
||||
|
||||
|
||||
PackInfo
|
||||
~~~~~~~~~~~~
|
||||
BYTE NID::kPackInfo (0x06)
|
||||
UINT64 PackPos
|
||||
UINT64 NumPackStreams
|
||||
|
||||
[]
|
||||
BYTE NID::kSize (0x09)
|
||||
UINT64 PackSizes[NumPackStreams]
|
||||
[]
|
||||
|
||||
[]
|
||||
BYTE NID::kCRC (0x0A)
|
||||
PackStreamDigests[NumPackStreams]
|
||||
[]
|
||||
|
||||
BYTE NID::kEnd
|
||||
|
||||
|
||||
Folder
|
||||
~~~~~~
|
||||
UINT64 NumCoders;
|
||||
for (NumCoders)
|
||||
{
|
||||
BYTE
|
||||
{
|
||||
0:3 DecompressionMethod.IDSize
|
||||
4:
|
||||
0 - IsSimple
|
||||
1 - Is not simple
|
||||
5:
|
||||
0 - No Attributes
|
||||
1 - There Are Attributes
|
||||
7:
|
||||
0 - Last Method in Alternative_Method_List
|
||||
1 - There are more alternative methods
|
||||
}
|
||||
BYTE DecompressionMethod.ID[DecompressionMethod.IDSize]
|
||||
if (!IsSimple)
|
||||
{
|
||||
UINT64 NumInStreams;
|
||||
UINT64 NumOutStreams;
|
||||
}
|
||||
if (DecompressionMethod[0] != 0)
|
||||
{
|
||||
UINT64 PropertiesSize
|
||||
BYTE Properties[PropertiesSize]
|
||||
}
|
||||
}
|
||||
|
||||
NumBindPairs = NumOutStreamsTotal - 1;
|
||||
|
||||
for (NumBindPairs)
|
||||
{
|
||||
UINT64 InIndex;
|
||||
UINT64 OutIndex;
|
||||
}
|
||||
|
||||
NumPackedStreams = NumInStreamsTotal - NumBindPairs;
|
||||
if (NumPackedStreams > 1)
|
||||
for(NumPackedStreams)
|
||||
{
|
||||
UINT64 Index;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
Coders Info
|
||||
~~~~~~~~~~~
|
||||
|
||||
BYTE NID::kUnPackInfo (0x07)
|
||||
|
||||
|
||||
BYTE NID::kFolder (0x0B)
|
||||
UINT64 NumFolders
|
||||
BYTE External
|
||||
switch(External)
|
||||
{
|
||||
case 0:
|
||||
Folders[NumFolders]
|
||||
case 1:
|
||||
UINT64 DataStreamIndex
|
||||
}
|
||||
|
||||
|
||||
BYTE ID::kCodersUnPackSize (0x0C)
|
||||
for(Folders)
|
||||
for(Folder.NumOutStreams)
|
||||
UINT64 UnPackSize;
|
||||
|
||||
|
||||
[]
|
||||
BYTE NID::kCRC (0x0A)
|
||||
UnPackDigests[NumFolders]
|
||||
[]
|
||||
|
||||
|
||||
|
||||
BYTE NID::kEnd
|
||||
|
||||
|
||||
|
||||
SubStreams Info
|
||||
~~~~~~~~~~~~~~
|
||||
BYTE NID::kSubStreamsInfo; (0x08)
|
||||
|
||||
[]
|
||||
BYTE NID::kNumUnPackStream; (0x0D)
|
||||
UINT64 NumUnPackStreamsInFolders[NumFolders];
|
||||
[]
|
||||
|
||||
|
||||
[]
|
||||
BYTE NID::kSize (0x09)
|
||||
UINT64 UnPackSizes[]
|
||||
[]
|
||||
|
||||
|
||||
[]
|
||||
BYTE NID::kCRC (0x0A)
|
||||
Digests[Number of streams with unknown CRC]
|
||||
[]
|
||||
|
||||
|
||||
BYTE NID::kEnd
|
||||
|
||||
|
||||
Streams Info
|
||||
~~~~~~~~~~~~
|
||||
|
||||
[]
|
||||
PackInfo
|
||||
[]
|
||||
|
||||
|
||||
[]
|
||||
CodersInfo
|
||||
[]
|
||||
|
||||
|
||||
[]
|
||||
SubStreamsInfo
|
||||
[]
|
||||
|
||||
BYTE NID::kEnd
|
||||
|
||||
|
||||
FilesInfo
|
||||
~~~~~~~~~
|
||||
BYTE NID::kFilesInfo; (0x05)
|
||||
UINT64 NumFiles
|
||||
|
||||
for (;;)
|
||||
{
|
||||
BYTE PropertyType;
|
||||
if (aType == 0)
|
||||
break;
|
||||
|
||||
UINT64 Size;
|
||||
|
||||
switch(PropertyType)
|
||||
{
|
||||
kEmptyStream: (0x0E)
|
||||
for(NumFiles)
|
||||
BIT IsEmptyStream
|
||||
|
||||
kEmptyFile: (0x0F)
|
||||
for(EmptyStreams)
|
||||
BIT IsEmptyFile
|
||||
|
||||
kAnti: (0x10)
|
||||
for(EmptyStreams)
|
||||
BIT IsAntiFile
|
||||
|
||||
case kCreationTime: (0x12)
|
||||
case kLastAccessTime: (0x13)
|
||||
case kLastWriteTime: (0x14)
|
||||
BYTE AllAreDefined
|
||||
if (AllAreDefined == 0)
|
||||
{
|
||||
for(NumFiles)
|
||||
BIT TimeDefined
|
||||
}
|
||||
BYTE External;
|
||||
if(External != 0)
|
||||
UINT64 DataIndex
|
||||
[]
|
||||
for(Definded Items)
|
||||
UINT32 Time
|
||||
[]
|
||||
|
||||
kNames: (0x11)
|
||||
BYTE External;
|
||||
if(External != 0)
|
||||
UINT64 DataIndex
|
||||
[]
|
||||
for(Files)
|
||||
{
|
||||
wchar_t Names[NameSize];
|
||||
wchar_t 0;
|
||||
}
|
||||
[]
|
||||
|
||||
kAttributes: (0x15)
|
||||
BYTE AllAreDefined
|
||||
if (AllAreDefined == 0)
|
||||
{
|
||||
for(NumFiles)
|
||||
BIT AttributesAreDefined
|
||||
}
|
||||
BYTE External;
|
||||
if(External != 0)
|
||||
UINT64 DataIndex
|
||||
[]
|
||||
for(Definded Attributes)
|
||||
UINT32 Attributes
|
||||
[]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Header
|
||||
~~~~~~
|
||||
BYTE NID::kHeader (0x01)
|
||||
|
||||
[]
|
||||
ArchiveProperties
|
||||
[]
|
||||
|
||||
[]
|
||||
BYTE NID::kAdditionalStreamsInfo; (0x03)
|
||||
StreamsInfo
|
||||
[]
|
||||
|
||||
[]
|
||||
BYTE NID::kMainStreamsInfo; (0x04)
|
||||
StreamsInfo
|
||||
[]
|
||||
|
||||
[]
|
||||
FilesInfo
|
||||
[]
|
||||
|
||||
BYTE NID::kEnd
|
||||
|
||||
|
||||
HeaderInfo
|
||||
~~~~~~~~~~
|
||||
[]
|
||||
BYTE NID::kEncodedHeader; (0x17)
|
||||
StreamsInfo for Encoded Header
|
||||
[]
|
||||
|
||||
|
||||
---
|
||||
End of document
|
||||
@@ -0,0 +1,32 @@
|
||||
/* 7zCrc.c */
|
||||
|
||||
#include "7zCrc.h"
|
||||
|
||||
#define kCrcPoly 0xEDB88320
|
||||
UInt32 g_CrcTable[256];
|
||||
|
||||
void MY_FAST_CALL CrcGenerateTable(void)
|
||||
{
|
||||
UInt32 i;
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
UInt32 r = i;
|
||||
int j;
|
||||
for (j = 0; j < 8; j++)
|
||||
r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
|
||||
g_CrcTable[i] = r;
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size)
|
||||
{
|
||||
const Byte *p = (const Byte *)data;
|
||||
for (; size > 0 ; size--, p++)
|
||||
v = CRC_UPDATE_BYTE(v, *p);
|
||||
return v;
|
||||
}
|
||||
|
||||
UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size)
|
||||
{
|
||||
return CrcUpdate(CRC_INIT_VAL, data, size) ^ 0xFFFFFFFF;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/* 7zCrc.h */
|
||||
|
||||
#ifndef __7Z_CRC_H
|
||||
#define __7Z_CRC_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
extern UInt32 g_CrcTable[];
|
||||
|
||||
void MY_FAST_CALL CrcGenerateTable(void);
|
||||
|
||||
#define CRC_INIT_VAL 0xFFFFFFFF
|
||||
#define CRC_GET_DIGEST(crc) ((crc) ^ 0xFFFFFFFF)
|
||||
#define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
|
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdate(UInt32 crc, const void *data, size_t size);
|
||||
UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,40 @@
|
||||
/* 7zCrcT8.c */
|
||||
|
||||
#include "7zCrc.h"
|
||||
|
||||
#define kCrcPoly 0xEDB88320
|
||||
#define CRC_NUM_TABLES 8
|
||||
|
||||
UInt32 g_CrcTable[256 * CRC_NUM_TABLES];
|
||||
|
||||
void MY_FAST_CALL CrcGenerateTable()
|
||||
{
|
||||
UInt32 i;
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
UInt32 r = i;
|
||||
int j;
|
||||
for (j = 0; j < 8; j++)
|
||||
r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
|
||||
g_CrcTable[i] = r;
|
||||
}
|
||||
#if CRC_NUM_TABLES > 1
|
||||
for (; i < 256 * CRC_NUM_TABLES; i++)
|
||||
{
|
||||
UInt32 r = g_CrcTable[i - 256];
|
||||
g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
|
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size)
|
||||
{
|
||||
return CrcUpdateT8(v, data, size, g_CrcTable);
|
||||
}
|
||||
|
||||
UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size)
|
||||
{
|
||||
return CrcUpdateT8(CRC_INIT_VAL, data, size, g_CrcTable) ^ 0xFFFFFFFF;
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/* Alloc.c */
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Alloc.h"
|
||||
|
||||
/* #define _SZ_ALLOC_DEBUG */
|
||||
|
||||
/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
#include <stdio.h>
|
||||
int g_allocCount = 0;
|
||||
int g_allocCountMid = 0;
|
||||
int g_allocCountBig = 0;
|
||||
#endif
|
||||
|
||||
void *MyAlloc(size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return 0;
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
fprintf(stderr, "\nAlloc %10d bytes; count = %10d", size, g_allocCount++);
|
||||
#endif
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void MyFree(void *address)
|
||||
{
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
if (address != 0)
|
||||
fprintf(stderr, "\nFree; count = %10d", --g_allocCount);
|
||||
#endif
|
||||
free(address);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
void *MidAlloc(size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return 0;
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
fprintf(stderr, "\nAlloc_Mid %10d bytes; count = %10d", size, g_allocCountMid++);
|
||||
#endif
|
||||
return VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
}
|
||||
|
||||
void MidFree(void *address)
|
||||
{
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
if (address != 0)
|
||||
fprintf(stderr, "\nFree_Mid; count = %10d", --g_allocCountMid);
|
||||
#endif
|
||||
if (address == 0)
|
||||
return;
|
||||
VirtualFree(address, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
#ifndef MEM_LARGE_PAGES
|
||||
#undef _7ZIP_LARGE_PAGES
|
||||
#endif
|
||||
|
||||
#ifdef _7ZIP_LARGE_PAGES
|
||||
SIZE_T g_LargePageSize = 0;
|
||||
typedef SIZE_T (WINAPI *GetLargePageMinimumP)();
|
||||
#endif
|
||||
|
||||
void SetLargePageSize()
|
||||
{
|
||||
#ifdef _7ZIP_LARGE_PAGES
|
||||
SIZE_T size = 0;
|
||||
GetLargePageMinimumP largePageMinimum = (GetLargePageMinimumP)
|
||||
GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetLargePageMinimum");
|
||||
if (largePageMinimum == 0)
|
||||
return;
|
||||
size = largePageMinimum();
|
||||
if (size == 0 || (size & (size - 1)) != 0)
|
||||
return;
|
||||
g_LargePageSize = size;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void *BigAlloc(size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return 0;
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
fprintf(stderr, "\nAlloc_Big %10d bytes; count = %10d", size, g_allocCountBig++);
|
||||
#endif
|
||||
|
||||
#ifdef _7ZIP_LARGE_PAGES
|
||||
if (g_LargePageSize != 0 && g_LargePageSize <= (1 << 30) && size >= (1 << 18))
|
||||
{
|
||||
void *res = VirtualAlloc(0, (size + g_LargePageSize - 1) & (~(g_LargePageSize - 1)),
|
||||
MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);
|
||||
if (res != 0)
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
return VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
}
|
||||
|
||||
void BigFree(void *address)
|
||||
{
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
if (address != 0)
|
||||
fprintf(stderr, "\nFree_Big; count = %10d", --g_allocCountBig);
|
||||
#endif
|
||||
|
||||
if (address == 0)
|
||||
return;
|
||||
VirtualFree(address, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,29 @@
|
||||
/* Alloc.h */
|
||||
|
||||
#ifndef __COMMON_ALLOC_H
|
||||
#define __COMMON_ALLOC_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
void *MyAlloc(size_t size);
|
||||
void MyFree(void *address);
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
void SetLargePageSize();
|
||||
|
||||
void *MidAlloc(size_t size);
|
||||
void MidFree(void *address);
|
||||
void *BigAlloc(size_t size);
|
||||
void BigFree(void *address);
|
||||
|
||||
#else
|
||||
|
||||
#define MidAlloc(size) MyAlloc(size)
|
||||
#define MidFree(address) MyFree(address)
|
||||
#define BigAlloc(size) MyAlloc(size)
|
||||
#define BigFree(address) MyFree(address)
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,70 @@
|
||||
/* 7zAlloc.c */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "7zAlloc.h"
|
||||
|
||||
/* #define _SZ_ALLOC_DEBUG */
|
||||
/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */
|
||||
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
int g_allocCount = 0;
|
||||
int g_allocCountTemp = 0;
|
||||
#endif
|
||||
|
||||
void *SzAlloc(size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return 0;
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
fprintf(stderr, "\nAlloc %10d bytes; count = %10d", size, g_allocCount);
|
||||
g_allocCount++;
|
||||
#endif
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void SzFree(void *address)
|
||||
{
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
if (address != 0)
|
||||
{
|
||||
g_allocCount--;
|
||||
fprintf(stderr, "\nFree; count = %10d", g_allocCount);
|
||||
}
|
||||
#endif
|
||||
free(address);
|
||||
}
|
||||
|
||||
void *SzAllocTemp(size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return 0;
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
fprintf(stderr, "\nAlloc_temp %10d bytes; count = %10d", size, g_allocCountTemp);
|
||||
g_allocCountTemp++;
|
||||
#ifdef _WIN32
|
||||
return HeapAlloc(GetProcessHeap(), 0, size);
|
||||
#endif
|
||||
#endif
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void SzFreeTemp(void *address)
|
||||
{
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
if (address != 0)
|
||||
{
|
||||
g_allocCountTemp--;
|
||||
fprintf(stderr, "\nFree_temp; count = %10d", g_allocCountTemp);
|
||||
}
|
||||
#ifdef _WIN32
|
||||
HeapFree(GetProcessHeap(), 0, address);
|
||||
return;
|
||||
#endif
|
||||
#endif
|
||||
free(address);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/* 7zAlloc.h */
|
||||
|
||||
#ifndef __7Z_ALLOC_H
|
||||
#define __7Z_ALLOC_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct _ISzAlloc
|
||||
{
|
||||
void *(*Alloc)(size_t size);
|
||||
void (*Free)(void *address); /* address can be 0 */
|
||||
} ISzAlloc;
|
||||
|
||||
void *SzAlloc(size_t size);
|
||||
void SzFree(void *address);
|
||||
|
||||
void *SzAllocTemp(size_t size);
|
||||
void SzFreeTemp(void *address);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,29 @@
|
||||
/* 7zBuffer.c */
|
||||
|
||||
#include "7zBuffer.h"
|
||||
#include "7zAlloc.h"
|
||||
|
||||
void SzByteBufferInit(CSzByteBuffer *buffer)
|
||||
{
|
||||
buffer->Capacity = 0;
|
||||
buffer->Items = 0;
|
||||
}
|
||||
|
||||
int SzByteBufferCreate(CSzByteBuffer *buffer, size_t newCapacity, void * (*allocFunc)(size_t size))
|
||||
{
|
||||
buffer->Capacity = newCapacity;
|
||||
if (newCapacity == 0)
|
||||
{
|
||||
buffer->Items = 0;
|
||||
return 1;
|
||||
}
|
||||
buffer->Items = (Byte *)allocFunc(newCapacity);
|
||||
return (buffer->Items != 0);
|
||||
}
|
||||
|
||||
void SzByteBufferFree(CSzByteBuffer *buffer, void (*freeFunc)(void *))
|
||||
{
|
||||
freeFunc(buffer->Items);
|
||||
buffer->Items = 0;
|
||||
buffer->Capacity = 0;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/* 7zBuffer.h */
|
||||
|
||||
#ifndef __7Z_BUFFER_H
|
||||
#define __7Z_BUFFER_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include "../../Types.h"
|
||||
|
||||
typedef struct _CSzByteBuffer
|
||||
{
|
||||
size_t Capacity;
|
||||
Byte *Items;
|
||||
}CSzByteBuffer;
|
||||
|
||||
void SzByteBufferInit(CSzByteBuffer *buffer);
|
||||
int SzByteBufferCreate(CSzByteBuffer *buffer, size_t newCapacity, void * (*allocFunc)(size_t size));
|
||||
void SzByteBufferFree(CSzByteBuffer *buffer, void (*freeFunc)(void *));
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,345 @@
|
||||
/* 7zDecode.c */
|
||||
|
||||
#include <memory.h>
|
||||
|
||||
/* BEGIN PHYSFS CHANGE */
|
||||
#include <string.h>
|
||||
/* END PHYSFS CHANGE */
|
||||
|
||||
#include "7zDecode.h"
|
||||
#ifdef _SZ_ONE_DIRECTORY
|
||||
#include "LzmaDecode.h"
|
||||
#else
|
||||
#include "../../Compress/Lzma/LzmaDecode.h"
|
||||
#include "../../Compress/Branch/BranchX86.h"
|
||||
#include "../../Compress/Branch/BranchX86_2.h"
|
||||
#endif
|
||||
|
||||
#define k_Copy 0
|
||||
#define k_LZMA 0x30101
|
||||
#define k_BCJ 0x03030103
|
||||
#define k_BCJ2 0x0303011B
|
||||
|
||||
#ifdef _LZMA_IN_CB
|
||||
|
||||
typedef struct _CLzmaInCallbackImp
|
||||
{
|
||||
ILzmaInCallback InCallback;
|
||||
ISzInStream *InStream;
|
||||
CFileSize Size;
|
||||
} CLzmaInCallbackImp;
|
||||
|
||||
int LzmaReadImp(void *object, const unsigned char **buffer, SizeT *size)
|
||||
{
|
||||
CLzmaInCallbackImp *cb = (CLzmaInCallbackImp *)object;
|
||||
size_t processedSize;
|
||||
SZ_RESULT res;
|
||||
size_t curSize = (1 << 20);
|
||||
if (curSize > cb->Size)
|
||||
curSize = (size_t)cb->Size;
|
||||
*size = 0;
|
||||
res = cb->InStream->Read((void *)cb->InStream, (void **)buffer, curSize, &processedSize);
|
||||
*size = (SizeT)processedSize;
|
||||
if (processedSize > curSize)
|
||||
return (int)SZE_FAIL;
|
||||
cb->Size -= processedSize;
|
||||
if (res == SZ_OK)
|
||||
return 0;
|
||||
return (int)res;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
SZ_RESULT SzDecodeLzma(CCoderInfo *coder, CFileSize inSize,
|
||||
#ifdef _LZMA_IN_CB
|
||||
ISzInStream *inStream,
|
||||
#else
|
||||
const Byte *inBuffer,
|
||||
#endif
|
||||
Byte *outBuffer, size_t outSize, ISzAlloc *allocMain)
|
||||
{
|
||||
#ifdef _LZMA_IN_CB
|
||||
CLzmaInCallbackImp lzmaCallback;
|
||||
#else
|
||||
SizeT inProcessed;
|
||||
#endif
|
||||
|
||||
CLzmaDecoderState state; /* it's about 24-80 bytes structure, if int is 32-bit */
|
||||
int result;
|
||||
SizeT outSizeProcessedLoc;
|
||||
|
||||
#ifdef _LZMA_IN_CB
|
||||
lzmaCallback.Size = inSize;
|
||||
lzmaCallback.InStream = inStream;
|
||||
lzmaCallback.InCallback.Read = LzmaReadImp;
|
||||
#endif
|
||||
|
||||
if (LzmaDecodeProperties(&state.Properties, coder->Properties.Items,
|
||||
(unsigned)coder->Properties.Capacity) != LZMA_RESULT_OK)
|
||||
return SZE_FAIL;
|
||||
|
||||
state.Probs = (CProb *)allocMain->Alloc(LzmaGetNumProbs(&state.Properties) * sizeof(CProb));
|
||||
if (state.Probs == 0)
|
||||
return SZE_OUTOFMEMORY;
|
||||
|
||||
#ifdef _LZMA_OUT_READ
|
||||
if (state.Properties.DictionarySize == 0)
|
||||
state.Dictionary = 0;
|
||||
else
|
||||
{
|
||||
state.Dictionary = (unsigned char *)allocMain->Alloc(state.Properties.DictionarySize);
|
||||
if (state.Dictionary == 0)
|
||||
{
|
||||
allocMain->Free(state.Probs);
|
||||
return SZE_OUTOFMEMORY;
|
||||
}
|
||||
}
|
||||
LzmaDecoderInit(&state);
|
||||
#endif
|
||||
|
||||
result = LzmaDecode(&state,
|
||||
#ifdef _LZMA_IN_CB
|
||||
&lzmaCallback.InCallback,
|
||||
#else
|
||||
inBuffer, (SizeT)inSize, &inProcessed,
|
||||
#endif
|
||||
outBuffer, (SizeT)outSize, &outSizeProcessedLoc);
|
||||
allocMain->Free(state.Probs);
|
||||
#ifdef _LZMA_OUT_READ
|
||||
allocMain->Free(state.Dictionary);
|
||||
#endif
|
||||
if (result == LZMA_RESULT_DATA_ERROR)
|
||||
return SZE_DATA_ERROR;
|
||||
if (result != LZMA_RESULT_OK)
|
||||
return SZE_FAIL;
|
||||
return (outSizeProcessedLoc == outSize) ? SZ_OK : SZE_DATA_ERROR;
|
||||
}
|
||||
|
||||
#ifdef _LZMA_IN_CB
|
||||
SZ_RESULT SzDecodeCopy(CFileSize inSize, ISzInStream *inStream, Byte *outBuffer)
|
||||
{
|
||||
while (inSize > 0)
|
||||
{
|
||||
void *inBuffer;
|
||||
size_t processedSize, curSize = (1 << 18);
|
||||
if (curSize > inSize)
|
||||
curSize = (size_t)(inSize);
|
||||
RINOK(inStream->Read((void *)inStream, (void **)&inBuffer, curSize, &processedSize));
|
||||
if (processedSize == 0)
|
||||
return SZE_DATA_ERROR;
|
||||
if (processedSize > curSize)
|
||||
return SZE_FAIL;
|
||||
memcpy(outBuffer, inBuffer, processedSize);
|
||||
outBuffer += processedSize;
|
||||
inSize -= processedSize;
|
||||
}
|
||||
return SZ_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define IS_UNSUPPORTED_METHOD(m) ((m) != k_Copy && (m) != k_LZMA)
|
||||
#define IS_UNSUPPORTED_CODER(c) (IS_UNSUPPORTED_METHOD(c.MethodID) || c.NumInStreams != 1 || c.NumOutStreams != 1)
|
||||
#define IS_NO_BCJ(c) (c.MethodID != k_BCJ || c.NumInStreams != 1 || c.NumOutStreams != 1)
|
||||
#define IS_NO_BCJ2(c) (c.MethodID != k_BCJ2 || c.NumInStreams != 4 || c.NumOutStreams != 1)
|
||||
|
||||
SZ_RESULT CheckSupportedFolder(const CFolder *f)
|
||||
{
|
||||
if (f->NumCoders < 1 || f->NumCoders > 4)
|
||||
return SZE_NOTIMPL;
|
||||
if (IS_UNSUPPORTED_CODER(f->Coders[0]))
|
||||
return SZE_NOTIMPL;
|
||||
if (f->NumCoders == 1)
|
||||
{
|
||||
if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0)
|
||||
return SZE_NOTIMPL;
|
||||
return SZ_OK;
|
||||
}
|
||||
if (f->NumCoders == 2)
|
||||
{
|
||||
if (IS_NO_BCJ(f->Coders[1]) ||
|
||||
f->NumPackStreams != 1 || f->PackStreams[0] != 0 ||
|
||||
f->NumBindPairs != 1 ||
|
||||
f->BindPairs[0].InIndex != 1 || f->BindPairs[0].OutIndex != 0)
|
||||
return SZE_NOTIMPL;
|
||||
return SZ_OK;
|
||||
}
|
||||
if (f->NumCoders == 4)
|
||||
{
|
||||
if (IS_UNSUPPORTED_CODER(f->Coders[1]) ||
|
||||
IS_UNSUPPORTED_CODER(f->Coders[2]) ||
|
||||
IS_NO_BCJ2(f->Coders[3]))
|
||||
return SZE_NOTIMPL;
|
||||
if (f->NumPackStreams != 4 ||
|
||||
f->PackStreams[0] != 2 ||
|
||||
f->PackStreams[1] != 6 ||
|
||||
f->PackStreams[2] != 1 ||
|
||||
f->PackStreams[3] != 0 ||
|
||||
f->NumBindPairs != 3 ||
|
||||
f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 ||
|
||||
f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 ||
|
||||
f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2)
|
||||
return SZE_NOTIMPL;
|
||||
return SZ_OK;
|
||||
}
|
||||
return SZE_NOTIMPL;
|
||||
}
|
||||
|
||||
CFileSize GetSum(const CFileSize *values, UInt32 index)
|
||||
{
|
||||
CFileSize sum = 0;
|
||||
UInt32 i;
|
||||
for (i = 0; i < index; i++)
|
||||
sum += values[i];
|
||||
return sum;
|
||||
}
|
||||
|
||||
SZ_RESULT SzDecode2(const CFileSize *packSizes, const CFolder *folder,
|
||||
#ifdef _LZMA_IN_CB
|
||||
ISzInStream *inStream, CFileSize startPos,
|
||||
#else
|
||||
const Byte *inBuffer,
|
||||
#endif
|
||||
Byte *outBuffer, size_t outSize, ISzAlloc *allocMain,
|
||||
Byte *tempBuf[])
|
||||
{
|
||||
UInt32 ci;
|
||||
size_t tempSizes[3] = { 0, 0, 0};
|
||||
size_t tempSize3 = 0;
|
||||
Byte *tempBuf3 = 0;
|
||||
|
||||
RINOK(CheckSupportedFolder(folder));
|
||||
|
||||
for (ci = 0; ci < folder->NumCoders; ci++)
|
||||
{
|
||||
CCoderInfo *coder = &folder->Coders[ci];
|
||||
|
||||
if (coder->MethodID == k_Copy || coder->MethodID == k_LZMA)
|
||||
{
|
||||
UInt32 si = 0;
|
||||
CFileSize offset;
|
||||
CFileSize inSize;
|
||||
Byte *outBufCur = outBuffer;
|
||||
size_t outSizeCur = outSize;
|
||||
if (folder->NumCoders == 4)
|
||||
{
|
||||
UInt32 indices[] = { 3, 2, 0 };
|
||||
CFileSize unpackSize = folder->UnPackSizes[ci];
|
||||
si = indices[ci];
|
||||
if (ci < 2)
|
||||
{
|
||||
Byte *temp;
|
||||
outSizeCur = (size_t)unpackSize;
|
||||
if (outSizeCur != unpackSize)
|
||||
return SZE_OUTOFMEMORY;
|
||||
temp = (Byte *)allocMain->Alloc(outSizeCur);
|
||||
if (temp == 0 && outSizeCur != 0)
|
||||
return SZE_OUTOFMEMORY;
|
||||
outBufCur = tempBuf[1 - ci] = temp;
|
||||
tempSizes[1 - ci] = outSizeCur;
|
||||
}
|
||||
else if (ci == 2)
|
||||
{
|
||||
if (unpackSize > outSize)
|
||||
return SZE_OUTOFMEMORY;
|
||||
tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
|
||||
tempSize3 = outSizeCur = (size_t)unpackSize;
|
||||
}
|
||||
else
|
||||
return SZE_NOTIMPL;
|
||||
}
|
||||
offset = GetSum(packSizes, si);
|
||||
inSize = packSizes[si];
|
||||
#ifdef _LZMA_IN_CB
|
||||
RINOK(inStream->Seek(inStream, startPos + offset));
|
||||
#endif
|
||||
|
||||
if (coder->MethodID == k_Copy)
|
||||
{
|
||||
if (inSize != outSizeCur)
|
||||
return SZE_DATA_ERROR;
|
||||
|
||||
#ifdef _LZMA_IN_CB
|
||||
RINOK(SzDecodeCopy(inSize, inStream, outBufCur));
|
||||
#else
|
||||
memcpy(outBufCur, inBuffer + (size_t)offset, (size_t)inSize);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
SZ_RESULT res = SzDecodeLzma(coder, inSize,
|
||||
#ifdef _LZMA_IN_CB
|
||||
inStream,
|
||||
#else
|
||||
inBuffer + (size_t)offset,
|
||||
#endif
|
||||
outBufCur, outSizeCur, allocMain);
|
||||
RINOK(res)
|
||||
}
|
||||
}
|
||||
else if (coder->MethodID == k_BCJ)
|
||||
{
|
||||
UInt32 state;
|
||||
if (ci != 1)
|
||||
return SZE_NOTIMPL;
|
||||
x86_Convert_Init(state);
|
||||
x86_Convert(outBuffer, outSize, 0, &state, 0);
|
||||
}
|
||||
else if (coder->MethodID == k_BCJ2)
|
||||
{
|
||||
CFileSize offset = GetSum(packSizes, 1);
|
||||
CFileSize s3Size = packSizes[1];
|
||||
SZ_RESULT res;
|
||||
if (ci != 3)
|
||||
return SZE_NOTIMPL;
|
||||
|
||||
#ifdef _LZMA_IN_CB
|
||||
RINOK(inStream->Seek(inStream, startPos + offset));
|
||||
tempSizes[2] = (size_t)s3Size;
|
||||
if (tempSizes[2] != s3Size)
|
||||
return SZE_OUTOFMEMORY;
|
||||
tempBuf[2] = (Byte *)allocMain->Alloc(tempSizes[2]);
|
||||
if (tempBuf[2] == 0 && tempSizes[2] != 0)
|
||||
return SZE_OUTOFMEMORY;
|
||||
res = SzDecodeCopy(s3Size, inStream, tempBuf[2]);
|
||||
RINOK(res)
|
||||
#endif
|
||||
|
||||
res = x86_2_Decode(
|
||||
tempBuf3, tempSize3,
|
||||
tempBuf[0], tempSizes[0],
|
||||
tempBuf[1], tempSizes[1],
|
||||
#ifdef _LZMA_IN_CB
|
||||
tempBuf[2], tempSizes[2],
|
||||
#else
|
||||
inBuffer + (size_t)offset, (size_t)s3Size,
|
||||
#endif
|
||||
outBuffer, outSize);
|
||||
RINOK(res)
|
||||
}
|
||||
else
|
||||
return SZE_NOTIMPL;
|
||||
}
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
SZ_RESULT SzDecode(const CFileSize *packSizes, const CFolder *folder,
|
||||
#ifdef _LZMA_IN_CB
|
||||
ISzInStream *inStream, CFileSize startPos,
|
||||
#else
|
||||
const Byte *inBuffer,
|
||||
#endif
|
||||
Byte *outBuffer, size_t outSize, ISzAlloc *allocMain)
|
||||
{
|
||||
Byte *tempBuf[3] = { 0, 0, 0};
|
||||
int i;
|
||||
SZ_RESULT res = SzDecode2(packSizes, folder,
|
||||
#ifdef _LZMA_IN_CB
|
||||
inStream, startPos,
|
||||
#else
|
||||
inBuffer,
|
||||
#endif
|
||||
outBuffer, outSize, allocMain, tempBuf);
|
||||
for (i = 0; i < 3; i++)
|
||||
allocMain->Free(tempBuf[i]);
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/* 7zDecode.h */
|
||||
|
||||
#ifndef __7Z_DECODE_H
|
||||
#define __7Z_DECODE_H
|
||||
|
||||
#include "7zItem.h"
|
||||
#include "7zAlloc.h"
|
||||
#ifdef _LZMA_IN_CB
|
||||
#include "7zIn.h"
|
||||
#endif
|
||||
|
||||
SZ_RESULT SzDecode(const CFileSize *packSizes, const CFolder *folder,
|
||||
#ifdef _LZMA_IN_CB
|
||||
ISzInStream *stream, CFileSize startPos,
|
||||
#else
|
||||
const Byte *inBuffer,
|
||||
#endif
|
||||
Byte *outBuffer, size_t outSize, ISzAlloc *allocMain);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,119 @@
|
||||
/* 7zExtract.c */
|
||||
|
||||
#include "7zExtract.h"
|
||||
#include "7zDecode.h"
|
||||
#include "../../7zCrc.h"
|
||||
|
||||
SZ_RESULT SzExtract(
|
||||
ISzInStream *inStream,
|
||||
CArchiveDatabaseEx *db,
|
||||
UInt32 fileIndex,
|
||||
UInt32 *blockIndex,
|
||||
Byte **outBuffer,
|
||||
size_t *outBufferSize,
|
||||
size_t *offset,
|
||||
size_t *outSizeProcessed,
|
||||
ISzAlloc *allocMain,
|
||||
ISzAlloc *allocTemp)
|
||||
{
|
||||
UInt32 folderIndex = db->FileIndexToFolderIndexMap[fileIndex];
|
||||
SZ_RESULT res = SZ_OK;
|
||||
*offset = 0;
|
||||
*outSizeProcessed = 0;
|
||||
if (folderIndex == (UInt32)-1)
|
||||
{
|
||||
allocMain->Free(*outBuffer);
|
||||
*blockIndex = folderIndex;
|
||||
*outBuffer = 0;
|
||||
*outBufferSize = 0;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
if (*outBuffer == 0 || *blockIndex != folderIndex)
|
||||
{
|
||||
CFolder *folder = db->Database.Folders + folderIndex;
|
||||
CFileSize unPackSizeSpec = SzFolderGetUnPackSize(folder);
|
||||
size_t unPackSize = (size_t)unPackSizeSpec;
|
||||
CFileSize startOffset = SzArDbGetFolderStreamPos(db, folderIndex, 0);
|
||||
#ifndef _LZMA_IN_CB
|
||||
Byte *inBuffer = 0;
|
||||
size_t processedSize;
|
||||
CFileSize packSizeSpec;
|
||||
size_t packSize;
|
||||
RINOK(SzArDbGetFolderFullPackSize(db, folderIndex, &packSizeSpec));
|
||||
packSize = (size_t)packSizeSpec;
|
||||
if (packSize != packSizeSpec)
|
||||
return SZE_OUTOFMEMORY;
|
||||
#endif
|
||||
if (unPackSize != unPackSizeSpec)
|
||||
return SZE_OUTOFMEMORY;
|
||||
*blockIndex = folderIndex;
|
||||
allocMain->Free(*outBuffer);
|
||||
*outBuffer = 0;
|
||||
|
||||
RINOK(inStream->Seek(inStream, startOffset));
|
||||
|
||||
#ifndef _LZMA_IN_CB
|
||||
if (packSize != 0)
|
||||
{
|
||||
inBuffer = (Byte *)allocTemp->Alloc(packSize);
|
||||
if (inBuffer == 0)
|
||||
return SZE_OUTOFMEMORY;
|
||||
}
|
||||
res = inStream->Read(inStream, inBuffer, packSize, &processedSize);
|
||||
if (res == SZ_OK && processedSize != packSize)
|
||||
res = SZE_FAIL;
|
||||
#endif
|
||||
if (res == SZ_OK)
|
||||
{
|
||||
*outBufferSize = unPackSize;
|
||||
if (unPackSize != 0)
|
||||
{
|
||||
*outBuffer = (Byte *)allocMain->Alloc(unPackSize);
|
||||
if (*outBuffer == 0)
|
||||
res = SZE_OUTOFMEMORY;
|
||||
}
|
||||
if (res == SZ_OK)
|
||||
{
|
||||
res = SzDecode(db->Database.PackSizes +
|
||||
db->FolderStartPackStreamIndex[folderIndex], folder,
|
||||
#ifdef _LZMA_IN_CB
|
||||
inStream, startOffset,
|
||||
#else
|
||||
inBuffer,
|
||||
#endif
|
||||
*outBuffer, unPackSize, allocTemp);
|
||||
if (res == SZ_OK)
|
||||
{
|
||||
if (folder->UnPackCRCDefined)
|
||||
{
|
||||
if (CrcCalc(*outBuffer, unPackSize) != folder->UnPackCRC)
|
||||
res = SZE_CRC_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef _LZMA_IN_CB
|
||||
allocTemp->Free(inBuffer);
|
||||
#endif
|
||||
}
|
||||
if (res == SZ_OK)
|
||||
{
|
||||
UInt32 i;
|
||||
CFileItem *fileItem = db->Database.Files + fileIndex;
|
||||
*offset = 0;
|
||||
for(i = db->FolderStartFileIndex[folderIndex]; i < fileIndex; i++)
|
||||
*offset += (UInt32)db->Database.Files[i].Size;
|
||||
*outSizeProcessed = (size_t)fileItem->Size;
|
||||
if (*offset + *outSizeProcessed > *outBufferSize)
|
||||
return SZE_FAIL;
|
||||
{
|
||||
if (fileItem->IsFileCRCDefined)
|
||||
{
|
||||
if (CrcCalc(*outBuffer + *offset, *outSizeProcessed) != fileItem->FileCRC)
|
||||
res = SZE_CRC_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/* 7zExtract.h */
|
||||
|
||||
#ifndef __7Z_EXTRACT_H
|
||||
#define __7Z_EXTRACT_H
|
||||
|
||||
#include "7zIn.h"
|
||||
|
||||
/*
|
||||
SzExtract extracts file from archive
|
||||
|
||||
*outBuffer must be 0 before first call for each new archive.
|
||||
|
||||
Extracting cache:
|
||||
If you need to decompress more than one file, you can send
|
||||
these values from previous call:
|
||||
*blockIndex,
|
||||
*outBuffer,
|
||||
*outBufferSize
|
||||
You can consider "*outBuffer" as cache of solid block. If your archive is solid,
|
||||
it will increase decompression speed.
|
||||
|
||||
If you use external function, you can declare these 3 cache variables
|
||||
(blockIndex, outBuffer, outBufferSize) as static in that external function.
|
||||
|
||||
Free *outBuffer and set *outBuffer to 0, if you want to flush cache.
|
||||
*/
|
||||
|
||||
SZ_RESULT SzExtract(
|
||||
ISzInStream *inStream,
|
||||
CArchiveDatabaseEx *db,
|
||||
UInt32 fileIndex, /* index of file */
|
||||
UInt32 *blockIndex, /* index of solid block */
|
||||
Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */
|
||||
size_t *outBufferSize, /* buffer size for output buffer */
|
||||
size_t *offset, /* offset of stream for required file in *outBuffer */
|
||||
size_t *outSizeProcessed, /* size of file in *outBuffer */
|
||||
ISzAlloc *allocMain,
|
||||
ISzAlloc *allocTemp);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,5 @@
|
||||
/* 7zHeader.c */
|
||||
|
||||
#include "7zHeader.h"
|
||||
|
||||
Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
|
||||
@@ -0,0 +1,55 @@
|
||||
/* 7zHeader.h */
|
||||
|
||||
#ifndef __7Z_HEADER_H
|
||||
#define __7Z_HEADER_H
|
||||
|
||||
#include "../../Types.h"
|
||||
|
||||
#define k7zSignatureSize 6
|
||||
extern Byte k7zSignature[k7zSignatureSize];
|
||||
|
||||
#define k7zMajorVersion 0
|
||||
|
||||
#define k7zStartHeaderSize 0x20
|
||||
|
||||
enum EIdEnum
|
||||
{
|
||||
k7zIdEnd,
|
||||
|
||||
k7zIdHeader,
|
||||
|
||||
k7zIdArchiveProperties,
|
||||
|
||||
k7zIdAdditionalStreamsInfo,
|
||||
k7zIdMainStreamsInfo,
|
||||
k7zIdFilesInfo,
|
||||
|
||||
k7zIdPackInfo,
|
||||
k7zIdUnPackInfo,
|
||||
k7zIdSubStreamsInfo,
|
||||
|
||||
k7zIdSize,
|
||||
k7zIdCRC,
|
||||
|
||||
k7zIdFolder,
|
||||
|
||||
k7zIdCodersUnPackSize,
|
||||
k7zIdNumUnPackStream,
|
||||
|
||||
k7zIdEmptyStream,
|
||||
k7zIdEmptyFile,
|
||||
k7zIdAnti,
|
||||
|
||||
k7zIdName,
|
||||
k7zIdCreationTime,
|
||||
k7zIdLastAccessTime,
|
||||
k7zIdLastWriteTime,
|
||||
k7zIdWinAttributes,
|
||||
k7zIdComment,
|
||||
|
||||
k7zIdEncodedHeader,
|
||||
|
||||
k7zIdStartPos
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,55 @@
|
||||
/* 7zIn.h */
|
||||
|
||||
#ifndef __7Z_IN_H
|
||||
#define __7Z_IN_H
|
||||
|
||||
#include "7zHeader.h"
|
||||
#include "7zItem.h"
|
||||
#include "7zAlloc.h"
|
||||
|
||||
typedef struct _CInArchiveInfo
|
||||
{
|
||||
CFileSize StartPositionAfterHeader;
|
||||
CFileSize DataStartPosition;
|
||||
}CInArchiveInfo;
|
||||
|
||||
typedef struct _CArchiveDatabaseEx
|
||||
{
|
||||
CArchiveDatabase Database;
|
||||
CInArchiveInfo ArchiveInfo;
|
||||
UInt32 *FolderStartPackStreamIndex;
|
||||
CFileSize *PackStreamStartPositions;
|
||||
UInt32 *FolderStartFileIndex;
|
||||
UInt32 *FileIndexToFolderIndexMap;
|
||||
}CArchiveDatabaseEx;
|
||||
|
||||
void SzArDbExInit(CArchiveDatabaseEx *db);
|
||||
void SzArDbExFree(CArchiveDatabaseEx *db, void (*freeFunc)(void *));
|
||||
CFileSize SzArDbGetFolderStreamPos(CArchiveDatabaseEx *db, UInt32 folderIndex, UInt32 indexInFolder);
|
||||
int SzArDbGetFolderFullPackSize(CArchiveDatabaseEx *db, UInt32 folderIndex, CFileSize *resSize);
|
||||
|
||||
typedef struct _ISzInStream
|
||||
{
|
||||
#ifdef _LZMA_IN_CB
|
||||
SZ_RESULT (*Read)(
|
||||
void *object, /* pointer to ISzInStream itself */
|
||||
void **buffer, /* out: pointer to buffer with data */
|
||||
size_t maxRequiredSize, /* max required size to read */
|
||||
size_t *processedSize); /* real processed size.
|
||||
processedSize can be less than maxRequiredSize.
|
||||
If processedSize == 0, then there are no more
|
||||
bytes in stream. */
|
||||
#else
|
||||
SZ_RESULT (*Read)(void *object, void *buffer, size_t size, size_t *processedSize);
|
||||
#endif
|
||||
SZ_RESULT (*Seek)(void *object, CFileSize pos);
|
||||
} ISzInStream;
|
||||
|
||||
|
||||
int SzArchiveOpen(
|
||||
ISzInStream *inStream,
|
||||
CArchiveDatabaseEx *db,
|
||||
ISzAlloc *allocMain,
|
||||
ISzAlloc *allocTemp);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,134 @@
|
||||
/* 7zItem.c */
|
||||
|
||||
#include "7zItem.h"
|
||||
#include "7zAlloc.h"
|
||||
|
||||
void SzCoderInfoInit(CCoderInfo *coder)
|
||||
{
|
||||
SzByteBufferInit(&coder->Properties);
|
||||
}
|
||||
|
||||
void SzCoderInfoFree(CCoderInfo *coder, void (*freeFunc)(void *p))
|
||||
{
|
||||
SzByteBufferFree(&coder->Properties, freeFunc);
|
||||
SzCoderInfoInit(coder);
|
||||
}
|
||||
|
||||
void SzFolderInit(CFolder *folder)
|
||||
{
|
||||
folder->NumCoders = 0;
|
||||
folder->Coders = 0;
|
||||
folder->NumBindPairs = 0;
|
||||
folder->BindPairs = 0;
|
||||
folder->NumPackStreams = 0;
|
||||
folder->PackStreams = 0;
|
||||
folder->UnPackSizes = 0;
|
||||
folder->UnPackCRCDefined = 0;
|
||||
folder->UnPackCRC = 0;
|
||||
folder->NumUnPackStreams = 0;
|
||||
}
|
||||
|
||||
void SzFolderFree(CFolder *folder, void (*freeFunc)(void *p))
|
||||
{
|
||||
UInt32 i;
|
||||
for (i = 0; i < folder->NumCoders; i++)
|
||||
SzCoderInfoFree(&folder->Coders[i], freeFunc);
|
||||
freeFunc(folder->Coders);
|
||||
freeFunc(folder->BindPairs);
|
||||
freeFunc(folder->PackStreams);
|
||||
freeFunc(folder->UnPackSizes);
|
||||
SzFolderInit(folder);
|
||||
}
|
||||
|
||||
UInt32 SzFolderGetNumOutStreams(CFolder *folder)
|
||||
{
|
||||
UInt32 result = 0;
|
||||
UInt32 i;
|
||||
for (i = 0; i < folder->NumCoders; i++)
|
||||
result += folder->Coders[i].NumOutStreams;
|
||||
return result;
|
||||
}
|
||||
|
||||
int SzFolderFindBindPairForInStream(CFolder *folder, UInt32 inStreamIndex)
|
||||
{
|
||||
UInt32 i;
|
||||
for(i = 0; i < folder->NumBindPairs; i++)
|
||||
if (folder->BindPairs[i].InIndex == inStreamIndex)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int SzFolderFindBindPairForOutStream(CFolder *folder, UInt32 outStreamIndex)
|
||||
{
|
||||
UInt32 i;
|
||||
for(i = 0; i < folder->NumBindPairs; i++)
|
||||
if (folder->BindPairs[i].OutIndex == outStreamIndex)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
CFileSize SzFolderGetUnPackSize(CFolder *folder)
|
||||
{
|
||||
int i = (int)SzFolderGetNumOutStreams(folder);
|
||||
if (i == 0)
|
||||
return 0;
|
||||
for (i--; i >= 0; i--)
|
||||
if (SzFolderFindBindPairForOutStream(folder, i) < 0)
|
||||
return folder->UnPackSizes[i];
|
||||
/* throw 1; */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
int FindPackStreamArrayIndex(int inStreamIndex) const
|
||||
{
|
||||
for(int i = 0; i < PackStreams.Size(); i++)
|
||||
if (PackStreams[i] == inStreamIndex)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
*/
|
||||
|
||||
void SzFileInit(CFileItem *fileItem)
|
||||
{
|
||||
fileItem->IsFileCRCDefined = 0;
|
||||
fileItem->HasStream = 1;
|
||||
fileItem->IsDirectory = 0;
|
||||
fileItem->IsAnti = 0;
|
||||
fileItem->IsLastWriteTimeDefined = 0;
|
||||
fileItem->Name = 0;
|
||||
}
|
||||
|
||||
void SzFileFree(CFileItem *fileItem, void (*freeFunc)(void *p))
|
||||
{
|
||||
freeFunc(fileItem->Name);
|
||||
SzFileInit(fileItem);
|
||||
}
|
||||
|
||||
void SzArchiveDatabaseInit(CArchiveDatabase *db)
|
||||
{
|
||||
db->NumPackStreams = 0;
|
||||
db->PackSizes = 0;
|
||||
db->PackCRCsDefined = 0;
|
||||
db->PackCRCs = 0;
|
||||
db->NumFolders = 0;
|
||||
db->Folders = 0;
|
||||
db->NumFiles = 0;
|
||||
db->Files = 0;
|
||||
}
|
||||
|
||||
void SzArchiveDatabaseFree(CArchiveDatabase *db, void (*freeFunc)(void *))
|
||||
{
|
||||
UInt32 i;
|
||||
for (i = 0; i < db->NumFolders; i++)
|
||||
SzFolderFree(&db->Folders[i], freeFunc);
|
||||
for (i = 0; i < db->NumFiles; i++)
|
||||
SzFileFree(&db->Files[i], freeFunc);
|
||||
freeFunc(db->PackSizes);
|
||||
freeFunc(db->PackCRCsDefined);
|
||||
freeFunc(db->PackCRCs);
|
||||
freeFunc(db->Folders);
|
||||
freeFunc(db->Files);
|
||||
SzArchiveDatabaseInit(db);
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/* 7zItem.h */
|
||||
|
||||
#ifndef __7Z_ITEM_H
|
||||
#define __7Z_ITEM_H
|
||||
|
||||
#include "7zMethodID.h"
|
||||
#include "7zHeader.h"
|
||||
#include "7zBuffer.h"
|
||||
|
||||
typedef struct _CCoderInfo
|
||||
{
|
||||
UInt32 NumInStreams;
|
||||
UInt32 NumOutStreams;
|
||||
CMethodID MethodID;
|
||||
CSzByteBuffer Properties;
|
||||
}CCoderInfo;
|
||||
|
||||
void SzCoderInfoInit(CCoderInfo *coder);
|
||||
void SzCoderInfoFree(CCoderInfo *coder, void (*freeFunc)(void *p));
|
||||
|
||||
typedef struct _CBindPair
|
||||
{
|
||||
UInt32 InIndex;
|
||||
UInt32 OutIndex;
|
||||
}CBindPair;
|
||||
|
||||
typedef struct _CFolder
|
||||
{
|
||||
UInt32 NumCoders;
|
||||
CCoderInfo *Coders;
|
||||
UInt32 NumBindPairs;
|
||||
CBindPair *BindPairs;
|
||||
UInt32 NumPackStreams;
|
||||
UInt32 *PackStreams;
|
||||
CFileSize *UnPackSizes;
|
||||
int UnPackCRCDefined;
|
||||
UInt32 UnPackCRC;
|
||||
|
||||
UInt32 NumUnPackStreams;
|
||||
}CFolder;
|
||||
|
||||
void SzFolderInit(CFolder *folder);
|
||||
CFileSize SzFolderGetUnPackSize(CFolder *folder);
|
||||
int SzFolderFindBindPairForInStream(CFolder *folder, UInt32 inStreamIndex);
|
||||
UInt32 SzFolderGetNumOutStreams(CFolder *folder);
|
||||
CFileSize SzFolderGetUnPackSize(CFolder *folder);
|
||||
|
||||
typedef struct _CArchiveFileTime
|
||||
{
|
||||
UInt32 Low;
|
||||
UInt32 High;
|
||||
} CArchiveFileTime;
|
||||
|
||||
typedef struct _CFileItem
|
||||
{
|
||||
CArchiveFileTime LastWriteTime;
|
||||
/*
|
||||
CFileSize StartPos;
|
||||
UInt32 Attributes;
|
||||
*/
|
||||
CFileSize Size;
|
||||
UInt32 FileCRC;
|
||||
char *Name;
|
||||
|
||||
Byte IsFileCRCDefined;
|
||||
Byte HasStream;
|
||||
Byte IsDirectory;
|
||||
Byte IsAnti;
|
||||
Byte IsLastWriteTimeDefined;
|
||||
/*
|
||||
int AreAttributesDefined;
|
||||
int IsLastWriteTimeDefined;
|
||||
int IsStartPosDefined;
|
||||
*/
|
||||
}CFileItem;
|
||||
|
||||
void SzFileInit(CFileItem *fileItem);
|
||||
|
||||
typedef struct _CArchiveDatabase
|
||||
{
|
||||
UInt32 NumPackStreams;
|
||||
CFileSize *PackSizes;
|
||||
Byte *PackCRCsDefined;
|
||||
UInt32 *PackCRCs;
|
||||
UInt32 NumFolders;
|
||||
CFolder *Folders;
|
||||
UInt32 NumFiles;
|
||||
CFileItem *Files;
|
||||
}CArchiveDatabase;
|
||||
|
||||
void SzArchiveDatabaseInit(CArchiveDatabase *db);
|
||||
void SzArchiveDatabaseFree(CArchiveDatabase *db, void (*freeFunc)(void *));
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,428 @@
|
||||
/*
|
||||
7zMain.c
|
||||
Test application for 7z Decoder
|
||||
LZMA SDK 4.43 Copyright (c) 1999-2006 Igor Pavlov (2006-06-04)
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define USE_WINDOWS_FUNCTIONS
|
||||
#endif
|
||||
|
||||
#ifdef USE_WINDOWS_FUNCTIONS
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "7zIn.h"
|
||||
#include "7zExtract.h"
|
||||
|
||||
#include "../../7zCrc.h"
|
||||
|
||||
|
||||
#ifdef USE_WINDOWS_FUNCTIONS
|
||||
typedef HANDLE MY_FILE_HANDLE;
|
||||
#else
|
||||
typedef FILE *MY_FILE_HANDLE;
|
||||
#endif
|
||||
|
||||
void ConvertNumberToString(CFileSize value, char *s)
|
||||
{
|
||||
char temp[32];
|
||||
int pos = 0;
|
||||
do
|
||||
{
|
||||
temp[pos++] = (char)('0' + (int)(value % 10));
|
||||
value /= 10;
|
||||
}
|
||||
while (value != 0);
|
||||
do
|
||||
*s++ = temp[--pos];
|
||||
while(pos > 0);
|
||||
*s = '\0';
|
||||
}
|
||||
|
||||
#define PERIOD_4 (4 * 365 + 1)
|
||||
#define PERIOD_100 (PERIOD_4 * 25 - 1)
|
||||
#define PERIOD_400 (PERIOD_100 * 4 + 1)
|
||||
|
||||
void ConvertFileTimeToString(CArchiveFileTime *ft, char *s)
|
||||
{
|
||||
unsigned year, mon, day, hour, min, sec;
|
||||
UInt64 v64 = ft->Low | ((UInt64)ft->High << 32);
|
||||
Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
unsigned temp;
|
||||
UInt32 v;
|
||||
v64 /= 10000000;
|
||||
sec = (unsigned)(v64 % 60);
|
||||
v64 /= 60;
|
||||
min = (unsigned)(v64 % 60);
|
||||
v64 /= 60;
|
||||
hour = (unsigned)(v64 % 24);
|
||||
v64 /= 24;
|
||||
|
||||
v = (UInt32)v64;
|
||||
|
||||
year = (unsigned)(1601 + v / PERIOD_400 * 400);
|
||||
v %= PERIOD_400;
|
||||
|
||||
temp = (unsigned)(v / PERIOD_100);
|
||||
if (temp == 4)
|
||||
temp = 3;
|
||||
year += temp * 100;
|
||||
v -= temp * PERIOD_100;
|
||||
|
||||
temp = v / PERIOD_4;
|
||||
if (temp == 25)
|
||||
temp = 24;
|
||||
year += temp * 4;
|
||||
v -= temp * PERIOD_4;
|
||||
|
||||
temp = v / 365;
|
||||
if (temp == 4)
|
||||
temp = 3;
|
||||
year += temp;
|
||||
v -= temp * 365;
|
||||
|
||||
if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
|
||||
ms[1] = 29;
|
||||
for (mon = 1; mon <= 12; mon++)
|
||||
{
|
||||
unsigned s = ms[mon - 1];
|
||||
if (v < s)
|
||||
break;
|
||||
v -= s;
|
||||
}
|
||||
day = (unsigned)v + 1;
|
||||
sprintf(s, "%04d-%02d-%02d %02d:%02d:%02d", year, mon, day, hour, min, sec);
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_WINDOWS_FUNCTIONS
|
||||
/*
|
||||
ReadFile and WriteFile functions in Windows have BUG:
|
||||
If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1)
|
||||
from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES
|
||||
(Insufficient system resources exist to complete the requested service).
|
||||
*/
|
||||
#define kChunkSizeMax (1 << 24)
|
||||
#endif
|
||||
|
||||
size_t MyReadFile(MY_FILE_HANDLE file, void *data, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return 0;
|
||||
#ifdef USE_WINDOWS_FUNCTIONS
|
||||
{
|
||||
size_t processedSize = 0;
|
||||
do
|
||||
{
|
||||
DWORD curSize = (size > kChunkSizeMax) ? kChunkSizeMax : (DWORD)size;
|
||||
DWORD processedLoc = 0;
|
||||
BOOL res = ReadFile(file, data, curSize, &processedLoc, NULL);
|
||||
data = (void *)((unsigned char *)data + processedLoc);
|
||||
size -= processedLoc;
|
||||
processedSize += processedLoc;
|
||||
if (!res || processedLoc == 0)
|
||||
break;
|
||||
}
|
||||
while (size > 0);
|
||||
return processedSize;
|
||||
}
|
||||
#else
|
||||
return fread(data, 1, size, file);
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t MyWriteFile(MY_FILE_HANDLE file, void *data, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return 0;
|
||||
#ifdef USE_WINDOWS_FUNCTIONS
|
||||
{
|
||||
size_t processedSize = 0;
|
||||
do
|
||||
{
|
||||
DWORD curSize = (size > kChunkSizeMax) ? kChunkSizeMax : (DWORD)size;
|
||||
DWORD processedLoc = 0;
|
||||
BOOL res = WriteFile(file, data, curSize, &processedLoc, NULL);
|
||||
data = (void *)((unsigned char *)data + processedLoc);
|
||||
size -= processedLoc;
|
||||
processedSize += processedLoc;
|
||||
if (!res)
|
||||
break;
|
||||
}
|
||||
while (size > 0);
|
||||
return processedSize;
|
||||
}
|
||||
#else
|
||||
return fwrite(data, 1, size, file);
|
||||
#endif
|
||||
}
|
||||
|
||||
int MyCloseFile(MY_FILE_HANDLE file)
|
||||
{
|
||||
#ifdef USE_WINDOWS_FUNCTIONS
|
||||
return (CloseHandle(file) != FALSE) ? 0 : 1;
|
||||
#else
|
||||
return fclose(file);
|
||||
#endif
|
||||
}
|
||||
|
||||
typedef struct _CFileInStream
|
||||
{
|
||||
ISzInStream InStream;
|
||||
MY_FILE_HANDLE File;
|
||||
} CFileInStream;
|
||||
|
||||
#ifdef _LZMA_IN_CB
|
||||
|
||||
#define kBufferSize (1 << 12)
|
||||
Byte g_Buffer[kBufferSize];
|
||||
|
||||
SZ_RESULT SzFileReadImp(void *object, void **buffer, size_t maxRequiredSize, size_t *processedSize)
|
||||
{
|
||||
CFileInStream *s = (CFileInStream *)object;
|
||||
size_t processedSizeLoc;
|
||||
if (maxRequiredSize > kBufferSize)
|
||||
maxRequiredSize = kBufferSize;
|
||||
processedSizeLoc = MyReadFile(s->File, g_Buffer, maxRequiredSize);
|
||||
*buffer = g_Buffer;
|
||||
if (processedSize != 0)
|
||||
*processedSize = processedSizeLoc;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
SZ_RESULT SzFileReadImp(void *object, void *buffer, size_t size, size_t *processedSize)
|
||||
{
|
||||
CFileInStream *s = (CFileInStream *)object;
|
||||
size_t processedSizeLoc = MyReadFile(s->File, buffer, size);
|
||||
if (processedSize != 0)
|
||||
*processedSize = processedSizeLoc;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
SZ_RESULT SzFileSeekImp(void *object, CFileSize pos)
|
||||
{
|
||||
CFileInStream *s = (CFileInStream *)object;
|
||||
|
||||
#ifdef USE_WINDOWS_FUNCTIONS
|
||||
{
|
||||
LARGE_INTEGER value;
|
||||
value.LowPart = (DWORD)pos;
|
||||
value.HighPart = (LONG)((UInt64)pos >> 32);
|
||||
#ifdef _SZ_FILE_SIZE_32
|
||||
/* VC 6.0 has bug with >> 32 shifts. */
|
||||
value.HighPart = 0;
|
||||
#endif
|
||||
value.LowPart = SetFilePointer(s->File, value.LowPart, &value.HighPart, FILE_BEGIN);
|
||||
if (value.LowPart == 0xFFFFFFFF)
|
||||
if(GetLastError() != NO_ERROR)
|
||||
return SZE_FAIL;
|
||||
return SZ_OK;
|
||||
}
|
||||
#else
|
||||
int res = fseek(s->File, (long)pos, SEEK_SET);
|
||||
if (res == 0)
|
||||
return SZ_OK;
|
||||
return SZE_FAIL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void PrintError(char *sz)
|
||||
{
|
||||
printf("\nERROR: %s\n", sz);
|
||||
}
|
||||
|
||||
int main(int numargs, char *args[])
|
||||
{
|
||||
CFileInStream archiveStream;
|
||||
CArchiveDatabaseEx db;
|
||||
SZ_RESULT res;
|
||||
ISzAlloc allocImp;
|
||||
ISzAlloc allocTempImp;
|
||||
|
||||
printf("\n7z ANSI-C Decoder 4.48 Copyright (c) 1999-2007 Igor Pavlov 2007-06-21\n");
|
||||
if (numargs == 1)
|
||||
{
|
||||
printf(
|
||||
"\nUsage: 7zDec <command> <archive_name>\n\n"
|
||||
"<Commands>\n"
|
||||
" e: Extract files from archive\n"
|
||||
" l: List contents of archive\n"
|
||||
" t: Test integrity of archive\n");
|
||||
return 0;
|
||||
}
|
||||
if (numargs < 3)
|
||||
{
|
||||
PrintError("incorrect command");
|
||||
return 1;
|
||||
}
|
||||
|
||||
archiveStream.File =
|
||||
#ifdef USE_WINDOWS_FUNCTIONS
|
||||
CreateFile(args[2], GENERIC_READ, FILE_SHARE_READ,
|
||||
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (archiveStream.File == INVALID_HANDLE_VALUE)
|
||||
#else
|
||||
archiveStream.File = fopen(args[2], "rb");
|
||||
if (archiveStream.File == 0)
|
||||
#endif
|
||||
{
|
||||
PrintError("can not open input file");
|
||||
return 1;
|
||||
}
|
||||
|
||||
archiveStream.InStream.Read = SzFileReadImp;
|
||||
archiveStream.InStream.Seek = SzFileSeekImp;
|
||||
|
||||
allocImp.Alloc = SzAlloc;
|
||||
allocImp.Free = SzFree;
|
||||
|
||||
allocTempImp.Alloc = SzAllocTemp;
|
||||
allocTempImp.Free = SzFreeTemp;
|
||||
|
||||
CrcGenerateTable();
|
||||
|
||||
SzArDbExInit(&db);
|
||||
res = SzArchiveOpen(&archiveStream.InStream, &db, &allocImp, &allocTempImp);
|
||||
if (res == SZ_OK)
|
||||
{
|
||||
char *command = args[1];
|
||||
int listCommand = 0;
|
||||
int testCommand = 0;
|
||||
int extractCommand = 0;
|
||||
if (strcmp(command, "l") == 0)
|
||||
listCommand = 1;
|
||||
if (strcmp(command, "t") == 0)
|
||||
testCommand = 1;
|
||||
else if (strcmp(command, "e") == 0)
|
||||
extractCommand = 1;
|
||||
|
||||
if (listCommand)
|
||||
{
|
||||
UInt32 i;
|
||||
for (i = 0; i < db.Database.NumFiles; i++)
|
||||
{
|
||||
CFileItem *f = db.Database.Files + i;
|
||||
char s[32], t[32];
|
||||
ConvertNumberToString(f->Size, s);
|
||||
if (f->IsLastWriteTimeDefined)
|
||||
ConvertFileTimeToString(&f->LastWriteTime, t);
|
||||
else
|
||||
strcpy(t, " ");
|
||||
|
||||
printf("%10s %s %s\n", s, t, f->Name);
|
||||
}
|
||||
}
|
||||
else if (testCommand || extractCommand)
|
||||
{
|
||||
UInt32 i;
|
||||
|
||||
/*
|
||||
if you need cache, use these 3 variables.
|
||||
if you use external function, you can make these variable as static.
|
||||
*/
|
||||
UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call (if outBuffer = 0) */
|
||||
Byte *outBuffer = 0; /* it must be 0 before first call for each new archive. */
|
||||
size_t outBufferSize = 0; /* it can have any value before first call (if outBuffer = 0) */
|
||||
|
||||
printf("\n");
|
||||
for (i = 0; i < db.Database.NumFiles; i++)
|
||||
{
|
||||
size_t offset;
|
||||
size_t outSizeProcessed;
|
||||
CFileItem *f = db.Database.Files + i;
|
||||
if (f->IsDirectory)
|
||||
printf("Directory ");
|
||||
else
|
||||
printf(testCommand ?
|
||||
"Testing ":
|
||||
"Extracting");
|
||||
printf(" %s", f->Name);
|
||||
if (f->IsDirectory)
|
||||
{
|
||||
printf("\n");
|
||||
continue;
|
||||
}
|
||||
res = SzExtract(&archiveStream.InStream, &db, i,
|
||||
&blockIndex, &outBuffer, &outBufferSize,
|
||||
&offset, &outSizeProcessed,
|
||||
&allocImp, &allocTempImp);
|
||||
if (res != SZ_OK)
|
||||
break;
|
||||
if (!testCommand)
|
||||
{
|
||||
MY_FILE_HANDLE outputHandle;
|
||||
size_t processedSize;
|
||||
char *fileName = f->Name;
|
||||
size_t nameLen = strlen(f->Name);
|
||||
for (; nameLen > 0; nameLen--)
|
||||
if (f->Name[nameLen - 1] == '/')
|
||||
{
|
||||
fileName = f->Name + nameLen;
|
||||
break;
|
||||
}
|
||||
|
||||
outputHandle =
|
||||
#ifdef USE_WINDOWS_FUNCTIONS
|
||||
CreateFile(fileName, GENERIC_WRITE, FILE_SHARE_READ,
|
||||
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (outputHandle == INVALID_HANDLE_VALUE)
|
||||
#else
|
||||
fopen(fileName, "wb+");
|
||||
if (outputHandle == 0)
|
||||
#endif
|
||||
{
|
||||
PrintError("can not open output file");
|
||||
res = SZE_FAIL;
|
||||
break;
|
||||
}
|
||||
processedSize = MyWriteFile(outputHandle, outBuffer + offset, outSizeProcessed);
|
||||
if (processedSize != outSizeProcessed)
|
||||
{
|
||||
PrintError("can not write output file");
|
||||
res = SZE_FAIL;
|
||||
break;
|
||||
}
|
||||
if (MyCloseFile(outputHandle))
|
||||
{
|
||||
PrintError("can not close output file");
|
||||
res = SZE_FAIL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
allocImp.Free(outBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintError("incorrect command");
|
||||
res = SZE_FAIL;
|
||||
}
|
||||
}
|
||||
SzArDbExFree(&db, allocImp.Free);
|
||||
|
||||
MyCloseFile(archiveStream.File);
|
||||
if (res == SZ_OK)
|
||||
{
|
||||
printf("\nEverything is Ok\n");
|
||||
return 0;
|
||||
}
|
||||
if (res == (SZ_RESULT)SZE_NOTIMPL)
|
||||
PrintError("decoder doesn't support this archive");
|
||||
else if (res == (SZ_RESULT)SZE_OUTOFMEMORY)
|
||||
PrintError("can not allocate memory");
|
||||
else if (res == (SZ_RESULT)SZE_CRC_ERROR)
|
||||
PrintError("CRC error");
|
||||
else
|
||||
printf("\nERROR #%d\n", res);
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/* 7zMethodID.c */
|
||||
|
||||
#include "7zMethodID.h"
|
||||
|
||||
/*
|
||||
int AreMethodsEqual(CMethodID *a1, CMethodID *a2)
|
||||
{
|
||||
return (*a1 == *a2) ? 1 : 0;
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,10 @@
|
||||
/* 7zMethodID.h */
|
||||
|
||||
#ifndef __7Z_METHOD_ID_H
|
||||
#define __7Z_METHOD_ID_H
|
||||
|
||||
#include "../../Types.h"
|
||||
|
||||
typedef UInt64 CMethodID;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,211 @@
|
||||
# Microsoft Developer Studio Project File - Name="7z_C" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
CFG=7z_C - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "7z_C.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "7z_C.mak" CFG="7z_C - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "7z_C - Win32 Release" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "7z_C - Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "7z_C - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W4 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_LZMA_PROB32" /D "_LZMA_IN_CB" /YX /FD /c
|
||||
# ADD BASE RSC /l 0x419 /d "NDEBUG"
|
||||
# ADD RSC /l 0x419 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"Release/7zDec.exe" /opt:NOWIN98
|
||||
# SUBTRACT LINK32 /pdb:none
|
||||
|
||||
!ELSEIF "$(CFG)" == "7z_C - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /W4 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_LZMA_PROB32" /D "_LZMA_IN_CB" /YX /FD /GZ /c
|
||||
# ADD BASE RSC /l 0x419 /d "_DEBUG"
|
||||
# ADD RSC /l 0x419 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"Debug/7zDec.exe" /pdbtype:sept
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "7z_C - Win32 Release"
|
||||
# Name "7z_C - Win32 Debug"
|
||||
# Begin Group "LZMA"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Compress\Lzma\LzmaDecode.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Compress\Lzma\LzmaDecode.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Compress\Lzma\LzmaTypes.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Common"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\7zCrc.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\7zCrc.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Types.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Branch"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Compress\Branch\BranchTypes.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Compress\Branch\BranchX86.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Compress\Branch\BranchX86.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Compress\Branch\BranchX86_2.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Compress\Branch\BranchX86_2.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zAlloc.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zAlloc.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zBuffer.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zBuffer.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zDecode.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zDecode.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zExtract.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zExtract.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zHeader.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zHeader.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zIn.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zIn.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zItem.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zItem.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zMain.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zMethodID.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\7zMethodID.h
|
||||
# End Source File
|
||||
# End Target
|
||||
# End Project
|
||||
@@ -0,0 +1,29 @@
|
||||
Microsoft Developer Studio Workspace File, Format Version 6.00
|
||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "7z_C"=.\7z_C.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Global:
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<3>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
PROG = 7zDec.exe
|
||||
|
||||
!IFDEF CPU
|
||||
LIBS = $(LIBS) bufferoverflowU.lib
|
||||
CFLAGS = $(CFLAGS) -GS- -Zc:forScope -WX -GS- -Gy -W4
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF O
|
||||
!IFDEF CPU
|
||||
O=$(CPU)
|
||||
!ELSE
|
||||
O=O
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
CFLAGS = $(CFLAGS) -nologo -c -Fo$O/ -D_LZMA_IN_CB
|
||||
CFLAGS_O1 = $(CFLAGS) -O1
|
||||
CFLAGS_O2 = $(CFLAGS) -O2
|
||||
|
||||
LFLAGS = $(LFLAGS) -nologo -OPT:NOWIN98 -OPT:REF
|
||||
|
||||
PROGPATH = $O\$(PROG)
|
||||
|
||||
COMPL_O1 = $(CPP) $(CFLAGS_O1) $**
|
||||
COMPL_O2 = $(CPP) $(CFLAGS_O2) $**
|
||||
COMPL = $(CPP) $(CFLAGS_O1) $**
|
||||
|
||||
C_OBJS = \
|
||||
$O\7zCrc.obj \
|
||||
|
||||
|
||||
7Z_OBJS = \
|
||||
$O\7zAlloc.obj \
|
||||
$O\7zBuffer.obj \
|
||||
$O\7zDecode.obj \
|
||||
$O\7zExtract.obj \
|
||||
$O\7zHeader.obj \
|
||||
$O\7zIn.obj \
|
||||
$O\7zItem.obj \
|
||||
$O\7zMain.obj \
|
||||
$O\7zMethodID.obj \
|
||||
|
||||
OBJS = \
|
||||
$(7Z_OBJS) \
|
||||
$O\LzmaDecode.obj \
|
||||
$O\BranchX86.obj \
|
||||
$O\BranchX86_2.obj \
|
||||
$(C_OBJS) \
|
||||
|
||||
all: $(PROGPATH)
|
||||
|
||||
clean:
|
||||
-del /Q $(PROGPATH) $O\*.exe $O\*.dll $O\*.obj $O\*.lib $O\*.exp $O\*.res $O\*.pch
|
||||
|
||||
$O:
|
||||
if not exist "$O" mkdir "$O"
|
||||
|
||||
$(PROGPATH): $O $(OBJS)
|
||||
link $(LFLAGS) -out:$(PROGPATH) $(OBJS) $(LIBS)
|
||||
|
||||
|
||||
$(7Z_OBJS): $(*B).c
|
||||
$(COMPL)
|
||||
$O\LzmaDecode.obj: ../../Compress/Lzma/$(*B).c
|
||||
$(COMPL_O2)
|
||||
|
||||
$O\BranchX86.obj: ../../Compress/Branch/$(*B).c
|
||||
$(COMPL_O2)
|
||||
|
||||
$O\BranchX86_2.obj: ../../Compress/Branch/$(*B).c
|
||||
$(COMPL_O2)
|
||||
|
||||
$(C_OBJS): ../../$(*B).c
|
||||
$(COMPL_O2)
|
||||
@@ -0,0 +1,55 @@
|
||||
PROG = 7zDec
|
||||
CXX = g++
|
||||
LIB =
|
||||
RM = rm -f
|
||||
CFLAGS = -c -O2 -Wall -D_LZMA_IN_CB
|
||||
|
||||
OBJS = 7zAlloc.o 7zBuffer.o 7zCrc.o 7zDecode.o 7zExtract.o 7zHeader.o 7zIn.o 7zItem.o 7zMain.o 7zMethodID.o LzmaDecode.o BranchX86.o BranchX86_2.o
|
||||
|
||||
all: $(PROG)
|
||||
|
||||
$(PROG): $(OBJS)
|
||||
$(CXX) -o $(PROG) $(LDFLAGS) $(OBJS) $(LIB)
|
||||
|
||||
7zAlloc.o: 7zAlloc.c
|
||||
$(CXX) $(CFLAGS) 7zAlloc.c
|
||||
|
||||
7zBuffer.o: 7zBuffer.c
|
||||
$(CXX) $(CFLAGS) 7zBuffer.c
|
||||
|
||||
7zCrc.o: ../../7zCrc.c
|
||||
$(CXX) $(CFLAGS) ../../7zCrc.c
|
||||
|
||||
7zDecode.o: 7zDecode.c
|
||||
$(CXX) $(CFLAGS) 7zDecode.c
|
||||
|
||||
7zExtract.o: 7zExtract.c
|
||||
$(CXX) $(CFLAGS) 7zExtract.c
|
||||
|
||||
7zHeader.o: 7zHeader.c
|
||||
$(CXX) $(CFLAGS) 7zHeader.c
|
||||
|
||||
7zIn.o: 7zIn.c
|
||||
$(CXX) $(CFLAGS) 7zIn.c
|
||||
|
||||
7zItem.o: 7zItem.c
|
||||
$(CXX) $(CFLAGS) 7zItem.c
|
||||
|
||||
7zMain.o: 7zMain.c
|
||||
$(CXX) $(CFLAGS) 7zMain.c
|
||||
|
||||
7zMethodID.o: 7zMethodID.c
|
||||
$(CXX) $(CFLAGS) 7zMethodID.c
|
||||
|
||||
LzmaDecode.o: ../../Compress/Lzma/LzmaDecode.c
|
||||
$(CXX) $(CFLAGS) ../../Compress/Lzma/LzmaDecode.c
|
||||
|
||||
BranchX86.o: ../../Compress/Branch/BranchX86.c
|
||||
$(CXX) $(CFLAGS) ../../Compress/Branch/BranchX86.c
|
||||
|
||||
BranchX86_2.o: ../../Compress/Branch/BranchX86_2.c
|
||||
$(CXX) $(CFLAGS) ../../Compress/Branch/BranchX86_2.c
|
||||
|
||||
clean:
|
||||
-$(RM) $(PROG) $(OBJS)
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/* BranchARM.c */
|
||||
|
||||
#include "BranchARM.h"
|
||||
|
||||
UInt32 ARM_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding)
|
||||
{
|
||||
UInt32 i;
|
||||
for (i = 0; i + 4 <= size; i += 4)
|
||||
{
|
||||
if (data[i + 3] == 0xEB)
|
||||
{
|
||||
UInt32 dest;
|
||||
UInt32 src = (data[i + 2] << 16) | (data[i + 1] << 8) | (data[i + 0]);
|
||||
src <<= 2;
|
||||
if (encoding)
|
||||
dest = nowPos + i + 8 + src;
|
||||
else
|
||||
dest = src - (nowPos + i + 8);
|
||||
dest >>= 2;
|
||||
data[i + 2] = (Byte)(dest >> 16);
|
||||
data[i + 1] = (Byte)(dest >> 8);
|
||||
data[i + 0] = (Byte)dest;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/* BranchARM.h */
|
||||
|
||||
#ifndef __BRANCH_ARM_H
|
||||
#define __BRANCH_ARM_H
|
||||
|
||||
#include "BranchTypes.h"
|
||||
|
||||
UInt32 ARM_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
/* BranchARMThumb.c */
|
||||
|
||||
#include "BranchARMThumb.h"
|
||||
|
||||
UInt32 ARMThumb_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding)
|
||||
{
|
||||
UInt32 i;
|
||||
for (i = 0; i + 4 <= size; i += 2)
|
||||
{
|
||||
if ((data[i + 1] & 0xF8) == 0xF0 &&
|
||||
(data[i + 3] & 0xF8) == 0xF8)
|
||||
{
|
||||
UInt32 dest;
|
||||
UInt32 src =
|
||||
((data[i + 1] & 0x7) << 19) |
|
||||
(data[i + 0] << 11) |
|
||||
((data[i + 3] & 0x7) << 8) |
|
||||
(data[i + 2]);
|
||||
|
||||
src <<= 1;
|
||||
if (encoding)
|
||||
dest = nowPos + i + 4 + src;
|
||||
else
|
||||
dest = src - (nowPos + i + 4);
|
||||
dest >>= 1;
|
||||
|
||||
data[i + 1] = (Byte)(0xF0 | ((dest >> 19) & 0x7));
|
||||
data[i + 0] = (Byte)(dest >> 11);
|
||||
data[i + 3] = (Byte)(0xF8 | ((dest >> 8) & 0x7));
|
||||
data[i + 2] = (Byte)dest;
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/* BranchARMThumb.h */
|
||||
|
||||
#ifndef __BRANCH_ARM_THUMB_H
|
||||
#define __BRANCH_ARM_THUMB_H
|
||||
|
||||
#include "BranchTypes.h"
|
||||
|
||||
UInt32 ARMThumb_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,66 @@
|
||||
/* BranchIA64.c */
|
||||
|
||||
#include "BranchIA64.h"
|
||||
|
||||
const Byte kBranchTable[32] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
4, 4, 6, 6, 0, 0, 7, 7,
|
||||
4, 4, 0, 0, 4, 4, 0, 0
|
||||
};
|
||||
|
||||
UInt32 IA64_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding)
|
||||
{
|
||||
UInt32 i;
|
||||
for (i = 0; i + 16 <= size; i += 16)
|
||||
{
|
||||
UInt32 instrTemplate = data[i] & 0x1F;
|
||||
UInt32 mask = kBranchTable[instrTemplate];
|
||||
UInt32 bitPos = 5;
|
||||
int slot;
|
||||
for (slot = 0; slot < 3; slot++, bitPos += 41)
|
||||
{
|
||||
UInt32 bytePos, bitRes;
|
||||
UInt64 instruction, instNorm;
|
||||
int j;
|
||||
if (((mask >> slot) & 1) == 0)
|
||||
continue;
|
||||
bytePos = (bitPos >> 3);
|
||||
bitRes = bitPos & 0x7;
|
||||
instruction = 0;
|
||||
for (j = 0; j < 6; j++)
|
||||
instruction += (UInt64)(data[i + j + bytePos]) << (8 * j);
|
||||
|
||||
instNorm = instruction >> bitRes;
|
||||
if (((instNorm >> 37) & 0xF) == 0x5
|
||||
&& ((instNorm >> 9) & 0x7) == 0
|
||||
/* && (instNorm & 0x3F)== 0 */
|
||||
)
|
||||
{
|
||||
UInt32 src = (UInt32)((instNorm >> 13) & 0xFFFFF);
|
||||
UInt32 dest;
|
||||
src |= ((UInt32)(instNorm >> 36) & 1) << 20;
|
||||
|
||||
src <<= 4;
|
||||
|
||||
if (encoding)
|
||||
dest = nowPos + i + src;
|
||||
else
|
||||
dest = src - (nowPos + i);
|
||||
|
||||
dest >>= 4;
|
||||
|
||||
instNorm &= ~((UInt64)(0x8FFFFF) << 13);
|
||||
instNorm |= ((UInt64)(dest & 0xFFFFF) << 13);
|
||||
instNorm |= ((UInt64)(dest & 0x100000) << (36 - 20));
|
||||
|
||||
instruction &= (1 << bitRes) - 1;
|
||||
instruction |= (instNorm << bitRes);
|
||||
for (j = 0; j < 6; j++)
|
||||
data[i + j + bytePos] = (Byte)(instruction >> (8 * j));
|
||||
}
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/* BranchIA64.h */
|
||||
|
||||
#ifndef __BRANCH_IA64_H
|
||||
#define __BRANCH_IA64_H
|
||||
|
||||
#include "BranchTypes.h"
|
||||
|
||||
UInt32 IA64_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
/* BranchPPC.c */
|
||||
|
||||
#include "BranchPPC.h"
|
||||
|
||||
UInt32 PPC_B_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding)
|
||||
{
|
||||
UInt32 i;
|
||||
for (i = 0; i + 4 <= size; i += 4)
|
||||
{
|
||||
/* PowerPC branch 6(48) 24(Offset) 1(Abs) 1(Link) */
|
||||
if ((data[i] >> 2) == 0x12 &&
|
||||
(
|
||||
(data[i + 3] & 3) == 1
|
||||
/* || (data[i+3] & 3) == 3 */
|
||||
)
|
||||
)
|
||||
{
|
||||
UInt32 src = ((data[i + 0] & 3) << 24) |
|
||||
(data[i + 1] << 16) |
|
||||
(data[i + 2] << 8) |
|
||||
(data[i + 3] & (~3));
|
||||
|
||||
UInt32 dest;
|
||||
if (encoding)
|
||||
dest = nowPos + i + src;
|
||||
else
|
||||
dest = src - (nowPos + i);
|
||||
data[i + 0] = (Byte)(0x48 | ((dest >> 24) & 0x3));
|
||||
data[i + 1] = (Byte)(dest >> 16);
|
||||
data[i + 2] = (Byte)(dest >> 8);
|
||||
data[i + 3] &= 0x3;
|
||||
data[i + 3] |= dest;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/* BranchPPC.h */
|
||||
|
||||
#ifndef __BRANCH_PPC_H
|
||||
#define __BRANCH_PPC_H
|
||||
|
||||
#include "BranchTypes.h"
|
||||
|
||||
UInt32 PPC_B_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
/* BranchSPARC.c */
|
||||
|
||||
#include "BranchSPARC.h"
|
||||
|
||||
UInt32 SPARC_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding)
|
||||
{
|
||||
UInt32 i;
|
||||
for (i = 0; i + 4 <= size; i += 4)
|
||||
{
|
||||
if (data[i] == 0x40 && (data[i + 1] & 0xC0) == 0x00 ||
|
||||
data[i] == 0x7F && (data[i + 1] & 0xC0) == 0xC0)
|
||||
{
|
||||
UInt32 src =
|
||||
((UInt32)data[i + 0] << 24) |
|
||||
((UInt32)data[i + 1] << 16) |
|
||||
((UInt32)data[i + 2] << 8) |
|
||||
((UInt32)data[i + 3]);
|
||||
UInt32 dest;
|
||||
|
||||
src <<= 2;
|
||||
if (encoding)
|
||||
dest = nowPos + i + src;
|
||||
else
|
||||
dest = src - (nowPos + i);
|
||||
dest >>= 2;
|
||||
|
||||
dest = (((0 - ((dest >> 22) & 1)) << 22) & 0x3FFFFFFF) | (dest & 0x3FFFFF) | 0x40000000;
|
||||
|
||||
data[i + 0] = (Byte)(dest >> 24);
|
||||
data[i + 1] = (Byte)(dest >> 16);
|
||||
data[i + 2] = (Byte)(dest >> 8);
|
||||
data[i + 3] = (Byte)dest;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/* BranchSPARC.h */
|
||||
|
||||
#ifndef __BRANCH_SPARC_H
|
||||
#define __BRANCH_SPARC_H
|
||||
|
||||
#include "BranchTypes.h"
|
||||
|
||||
UInt32 SPARC_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
/* BranchTypes.h */
|
||||
|
||||
#ifndef __BRANCHTYPES_H
|
||||
#define __BRANCHTYPES_H
|
||||
|
||||
#ifndef _7ZIP_BYTE_DEFINED
|
||||
#define _7ZIP_BYTE_DEFINED
|
||||
typedef unsigned char Byte;
|
||||
#endif
|
||||
|
||||
#ifndef _7ZIP_UINT16_DEFINED
|
||||
#define _7ZIP_UINT16_DEFINED
|
||||
typedef unsigned short UInt16;
|
||||
#endif
|
||||
|
||||
#ifndef _7ZIP_UINT32_DEFINED
|
||||
#define _7ZIP_UINT32_DEFINED
|
||||
#ifdef _LZMA_UINT32_IS_ULONG
|
||||
typedef unsigned long UInt32;
|
||||
#else
|
||||
typedef unsigned int UInt32;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef _7ZIP_UINT64_DEFINED
|
||||
#define _7ZIP_UINT64_DEFINED
|
||||
#ifdef _SZ_NO_INT_64
|
||||
typedef unsigned long UInt64;
|
||||
#else
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
typedef unsigned __int64 UInt64;
|
||||
#else
|
||||
typedef unsigned long long int UInt64;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* #define _LZMA_NO_SYSTEM_SIZE_T */
|
||||
/* You can use it, if you don't want <stddef.h> */
|
||||
|
||||
#ifndef _7ZIP_SIZET_DEFINED
|
||||
#define _7ZIP_SIZET_DEFINED
|
||||
#ifdef _LZMA_NO_SYSTEM_SIZE_T
|
||||
typedef UInt32 SizeT;
|
||||
#else
|
||||
#include <stddef.h>
|
||||
typedef size_t SizeT;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,84 @@
|
||||
/* BranchX86.c */
|
||||
|
||||
#include "BranchX86.h"
|
||||
|
||||
#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF)
|
||||
|
||||
const Byte kMaskToAllowedStatus[8] = {1, 1, 1, 0, 1, 0, 0, 0};
|
||||
const Byte kMaskToBitNumber[8] = {0, 1, 2, 2, 3, 3, 3, 3};
|
||||
|
||||
SizeT x86_Convert(Byte *buffer, SizeT endPos, UInt32 nowPos, UInt32 *prevMaskMix, int encoding)
|
||||
{
|
||||
SizeT bufferPos = 0, prevPosT;
|
||||
UInt32 prevMask = *prevMaskMix & 0x7;
|
||||
if (endPos < 5)
|
||||
return 0;
|
||||
nowPos += 5;
|
||||
prevPosT = (SizeT)0 - 1;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
Byte *p = buffer + bufferPos;
|
||||
Byte *limit = buffer + endPos - 4;
|
||||
for (; p < limit; p++)
|
||||
if ((*p & 0xFE) == 0xE8)
|
||||
break;
|
||||
bufferPos = (SizeT)(p - buffer);
|
||||
if (p >= limit)
|
||||
break;
|
||||
prevPosT = bufferPos - prevPosT;
|
||||
if (prevPosT > 3)
|
||||
prevMask = 0;
|
||||
else
|
||||
{
|
||||
prevMask = (prevMask << ((int)prevPosT - 1)) & 0x7;
|
||||
if (prevMask != 0)
|
||||
{
|
||||
Byte b = p[4 - kMaskToBitNumber[prevMask]];
|
||||
if (!kMaskToAllowedStatus[prevMask] || Test86MSByte(b))
|
||||
{
|
||||
prevPosT = bufferPos;
|
||||
prevMask = ((prevMask << 1) & 0x7) | 1;
|
||||
bufferPos++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
prevPosT = bufferPos;
|
||||
|
||||
if (Test86MSByte(p[4]))
|
||||
{
|
||||
UInt32 src = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]);
|
||||
UInt32 dest;
|
||||
for (;;)
|
||||
{
|
||||
Byte b;
|
||||
int index;
|
||||
if (encoding)
|
||||
dest = (nowPos + (UInt32)bufferPos) + src;
|
||||
else
|
||||
dest = src - (nowPos + (UInt32)bufferPos);
|
||||
if (prevMask == 0)
|
||||
break;
|
||||
index = kMaskToBitNumber[prevMask] * 8;
|
||||
b = (Byte)(dest >> (24 - index));
|
||||
if (!Test86MSByte(b))
|
||||
break;
|
||||
src = dest ^ ((1 << (32 - index)) - 1);
|
||||
}
|
||||
p[4] = (Byte)(~(((dest >> 24) & 1) - 1));
|
||||
p[3] = (Byte)(dest >> 16);
|
||||
p[2] = (Byte)(dest >> 8);
|
||||
p[1] = (Byte)dest;
|
||||
bufferPos += 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
prevMask = ((prevMask << 1) & 0x7) | 1;
|
||||
bufferPos++;
|
||||
}
|
||||
}
|
||||
prevPosT = bufferPos - prevPosT;
|
||||
*prevMaskMix = ((prevPosT > 3) ? 0 : ((prevMask << ((int)prevPosT - 1)) & 0x7));
|
||||
return bufferPos;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/* BranchX86.h */
|
||||
|
||||
#ifndef __BRANCHX86_H
|
||||
#define __BRANCHX86_H
|
||||
|
||||
#include "BranchTypes.h"
|
||||
|
||||
#define x86_Convert_Init(state) { state = 0; }
|
||||
|
||||
SizeT x86_Convert(Byte *buffer, SizeT endPos, UInt32 nowPos, UInt32 *state, int encoding);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,135 @@
|
||||
// BranchX86_2.c
|
||||
|
||||
#include "BranchX86_2.h"
|
||||
|
||||
#include "../../Alloc.h"
|
||||
|
||||
#ifdef _LZMA_PROB32
|
||||
#define CProb UInt32
|
||||
#else
|
||||
#define CProb UInt16
|
||||
#endif
|
||||
|
||||
#define IsJcc(b0, b1) ((b0) == 0x0F && ((b1) & 0xF0) == 0x80)
|
||||
#define IsJ(b0, b1) ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1))
|
||||
|
||||
#define kNumTopBits 24
|
||||
#define kTopValue ((UInt32)1 << kNumTopBits)
|
||||
|
||||
#define kNumBitModelTotalBits 11
|
||||
#define kBitModelTotal (1 << kNumBitModelTotalBits)
|
||||
#define kNumMoveBits 5
|
||||
|
||||
#define RC_READ_BYTE (*Buffer++)
|
||||
|
||||
#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \
|
||||
{ int i; for(i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) | RC_READ_BYTE; }}
|
||||
|
||||
#define RC_TEST { if (Buffer == BufferLim) return BCJ2_RESULT_DATA_ERROR; }
|
||||
|
||||
#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2
|
||||
|
||||
#define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; }
|
||||
|
||||
#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound)
|
||||
#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits;
|
||||
#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits;
|
||||
// #define UpdateBit0(p) Range = bound; *(p) = (CProb)(*(p) + ((kBitModelTotal - *(p)) >> kNumMoveBits));
|
||||
// #define UpdateBit1(p) Range -= bound; Code -= bound; *(p) = (CProb)(*(p) - (*(p) >> kNumMoveBits));
|
||||
|
||||
int x86_2_Decode(
|
||||
const Byte *buf0, SizeT size0,
|
||||
const Byte *buf1, SizeT size1,
|
||||
const Byte *buf2, SizeT size2,
|
||||
const Byte *buf3, SizeT size3,
|
||||
Byte *outBuf, SizeT outSize)
|
||||
{
|
||||
CProb p[256 + 2];
|
||||
SizeT inPos = 0, outPos = 0;
|
||||
|
||||
const Byte *Buffer, *BufferLim;
|
||||
UInt32 Range, Code;
|
||||
Byte prevByte = 0;
|
||||
|
||||
unsigned int i;
|
||||
for (i = 0; i < sizeof(p) / sizeof(p[0]); i++)
|
||||
p[i] = kBitModelTotal >> 1;
|
||||
RC_INIT(buf3, size3);
|
||||
|
||||
if (outSize == 0)
|
||||
return BCJ2_RESULT_OK;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
Byte b;
|
||||
CProb *prob;
|
||||
UInt32 bound;
|
||||
|
||||
SizeT limit = size0 - inPos;
|
||||
if (outSize - outPos < limit)
|
||||
limit = outSize - outPos;
|
||||
while (limit != 0)
|
||||
{
|
||||
Byte b = buf0[inPos];
|
||||
outBuf[outPos++] = b;
|
||||
if (IsJ(prevByte, b))
|
||||
break;
|
||||
inPos++;
|
||||
prevByte = b;
|
||||
limit--;
|
||||
}
|
||||
|
||||
if (limit == 0 || outPos == outSize)
|
||||
break;
|
||||
|
||||
b = buf0[inPos++];
|
||||
|
||||
if (b == 0xE8)
|
||||
prob = p + prevByte;
|
||||
else if (b == 0xE9)
|
||||
prob = p + 256;
|
||||
else
|
||||
prob = p + 257;
|
||||
|
||||
IfBit0(prob)
|
||||
{
|
||||
UpdateBit0(prob)
|
||||
prevByte = b;
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 dest;
|
||||
const Byte *v;
|
||||
UpdateBit1(prob)
|
||||
if (b == 0xE8)
|
||||
{
|
||||
v = buf1;
|
||||
if (size1 < 4)
|
||||
return BCJ2_RESULT_DATA_ERROR;
|
||||
buf1 += 4;
|
||||
size1 -= 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
v = buf2;
|
||||
if (size2 < 4)
|
||||
return BCJ2_RESULT_DATA_ERROR;
|
||||
buf2 += 4;
|
||||
size2 -= 4;
|
||||
}
|
||||
dest = (((UInt32)v[0] << 24) | ((UInt32)v[1] << 16) |
|
||||
((UInt32)v[2] << 8) | ((UInt32)v[3])) - ((UInt32)outPos + 4);
|
||||
outBuf[outPos++] = (Byte)dest;
|
||||
if (outPos == outSize)
|
||||
break;
|
||||
outBuf[outPos++] = (Byte)(dest >> 8);
|
||||
if (outPos == outSize)
|
||||
break;
|
||||
outBuf[outPos++] = (Byte)(dest >> 16);
|
||||
if (outPos == outSize)
|
||||
break;
|
||||
outBuf[outPos++] = prevByte = (Byte)(dest >> 24);
|
||||
}
|
||||
}
|
||||
return (outPos == outSize) ? BCJ2_RESULT_OK : BCJ2_RESULT_DATA_ERROR;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// BranchX86_2.h
|
||||
|
||||
#ifndef __BRANCHX86_2_H
|
||||
#define __BRANCHX86_2_H
|
||||
|
||||
#include "BranchTypes.h"
|
||||
|
||||
#define BCJ2_RESULT_OK 0
|
||||
#define BCJ2_RESULT_DATA_ERROR 1
|
||||
|
||||
/*
|
||||
Conditions:
|
||||
outSize <= FullOutputSize,
|
||||
where FullOutputSize is full size of output stream of x86_2 filter.
|
||||
|
||||
If buf0 overlaps outBuf, there are two required conditions:
|
||||
1) (buf0 >= outBuf)
|
||||
2) (buf0 + size0 >= outBuf + FullOutputSize).
|
||||
*/
|
||||
|
||||
int x86_2_Decode(
|
||||
const Byte *buf0, SizeT size0,
|
||||
const Byte *buf1, SizeT size1,
|
||||
const Byte *buf2, SizeT size2,
|
||||
const Byte *buf3, SizeT size3,
|
||||
Byte *outBuf, SizeT outSize);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,146 @@
|
||||
/* Compress/HuffmanEncode.c */
|
||||
|
||||
#include "HuffmanEncode.h"
|
||||
#include "../../Sort.h"
|
||||
|
||||
#define kMaxLen 16
|
||||
#define NUM_BITS 10
|
||||
#define MASK ((1 << NUM_BITS) - 1)
|
||||
|
||||
#define NUM_COUNTERS 64
|
||||
|
||||
/* use BLOCK_SORT_EXTERNAL_FLAGS if blockSize > 1M */
|
||||
#define HUFFMAN_SPEED_OPT
|
||||
|
||||
void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 numSymbols, UInt32 maxLen)
|
||||
{
|
||||
UInt32 num = 0;
|
||||
/* if (maxLen > 10) maxLen = 10; */
|
||||
{
|
||||
UInt32 i;
|
||||
|
||||
#ifdef HUFFMAN_SPEED_OPT
|
||||
|
||||
UInt32 counters[NUM_COUNTERS];
|
||||
for (i = 0; i < NUM_COUNTERS; i++)
|
||||
counters[i] = 0;
|
||||
for (i = 0; i < numSymbols; i++)
|
||||
{
|
||||
UInt32 freq = freqs[i];
|
||||
counters[(freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1]++;
|
||||
}
|
||||
|
||||
for (i = 1; i < NUM_COUNTERS; i++)
|
||||
{
|
||||
UInt32 temp = counters[i];
|
||||
counters[i] = num;
|
||||
num += temp;
|
||||
}
|
||||
|
||||
for (i = 0; i < numSymbols; i++)
|
||||
{
|
||||
UInt32 freq = freqs[i];
|
||||
if (freq == 0)
|
||||
lens[i] = 0;
|
||||
else
|
||||
p[counters[((freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1)]++] = i | (freq << NUM_BITS);
|
||||
}
|
||||
counters[0] = 0;
|
||||
HeapSort(p + counters[NUM_COUNTERS - 2], counters[NUM_COUNTERS - 1] - counters[NUM_COUNTERS - 2]);
|
||||
|
||||
#else
|
||||
|
||||
for (i = 0; i < numSymbols; i++)
|
||||
{
|
||||
UInt32 freq = freqs[i];
|
||||
if (freq == 0)
|
||||
lens[i] = 0;
|
||||
else
|
||||
p[num++] = i | (freq << NUM_BITS);
|
||||
}
|
||||
HeapSort(p, num);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
if (num < 2)
|
||||
{
|
||||
int minCode = 0;
|
||||
int maxCode = 1;
|
||||
if (num == 1)
|
||||
{
|
||||
maxCode = p[0] & MASK;
|
||||
if (maxCode == 0)
|
||||
maxCode++;
|
||||
}
|
||||
p[minCode] = 0;
|
||||
p[maxCode] = 1;
|
||||
lens[minCode] = lens[maxCode] = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
UInt32 b, e, i;
|
||||
|
||||
i = b = e = 0;
|
||||
do
|
||||
{
|
||||
UInt32 n, m, freq;
|
||||
n = (i != num && (b == e || (p[i] >> NUM_BITS) <= (p[b] >> NUM_BITS))) ? i++ : b++;
|
||||
freq = (p[n] & ~MASK);
|
||||
p[n] = (p[n] & MASK) | (e << NUM_BITS);
|
||||
m = (i != num && (b == e || (p[i] >> NUM_BITS) <= (p[b] >> NUM_BITS))) ? i++ : b++;
|
||||
freq += (p[m] & ~MASK);
|
||||
p[m] = (p[m] & MASK) | (e << NUM_BITS);
|
||||
p[e] = (p[e] & MASK) | freq;
|
||||
e++;
|
||||
}
|
||||
while (num - e > 1);
|
||||
|
||||
{
|
||||
UInt32 lenCounters[kMaxLen + 1];
|
||||
for (i = 0; i <= kMaxLen; i++)
|
||||
lenCounters[i] = 0;
|
||||
|
||||
p[--e] &= MASK;
|
||||
lenCounters[1] = 2;
|
||||
while (e > 0)
|
||||
{
|
||||
UInt32 len = (p[p[--e] >> NUM_BITS] >> NUM_BITS) + 1;
|
||||
p[e] = (p[e] & MASK) | (len << NUM_BITS);
|
||||
if (len >= maxLen)
|
||||
for (len = maxLen - 1; lenCounters[len] == 0; len--);
|
||||
lenCounters[len]--;
|
||||
lenCounters[len + 1] += 2;
|
||||
}
|
||||
|
||||
{
|
||||
UInt32 len;
|
||||
i = 0;
|
||||
for (len = maxLen; len != 0; len--)
|
||||
{
|
||||
UInt32 num;
|
||||
for (num = lenCounters[len]; num != 0; num--)
|
||||
lens[p[i++] & MASK] = (Byte)len;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
UInt32 nextCodes[kMaxLen + 1];
|
||||
{
|
||||
UInt32 code = 0;
|
||||
UInt32 len;
|
||||
for (len = 1; len <= kMaxLen; len++)
|
||||
nextCodes[len] = code = (code + lenCounters[len - 1]) << 1;
|
||||
}
|
||||
/* if (code + lenCounters[kMaxLen] - 1 != (1 << kMaxLen) - 1) throw 1; */
|
||||
|
||||
{
|
||||
UInt32 i;
|
||||
for (i = 0; i < numSymbols; i++)
|
||||
p[i] = nextCodes[lens[i]]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/* Compress/HuffmanEncode.h */
|
||||
|
||||
#ifndef __COMPRESS_HUFFMANENCODE_H
|
||||
#define __COMPRESS_HUFFMANENCODE_H
|
||||
|
||||
#include "../../Types.h"
|
||||
|
||||
/*
|
||||
Conditions:
|
||||
num <= 1024 = 2 ^ NUM_BITS
|
||||
Sum(freqs) < 4M = 2 ^ (32 - NUM_BITS)
|
||||
maxLen <= 16 = kMaxLen
|
||||
Num_Items(p) >= HUFFMAN_TEMP_SIZE(num)
|
||||
*/
|
||||
|
||||
void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 num, UInt32 maxLen);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,53 @@
|
||||
/* LzHash.h */
|
||||
|
||||
#ifndef __C_LZHASH_H
|
||||
#define __C_LZHASH_H
|
||||
|
||||
#define kHash2Size (1 << 10)
|
||||
#define kHash3Size (1 << 16)
|
||||
#define kHash4Size (1 << 20)
|
||||
|
||||
#define kFix3HashSize (kHash2Size)
|
||||
#define kFix4HashSize (kHash2Size + kHash3Size)
|
||||
#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
|
||||
|
||||
#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8);
|
||||
|
||||
#define HASH3_CALC { \
|
||||
UInt32 temp = g_CrcTable[cur[0]] ^ cur[1]; \
|
||||
hash2Value = temp & (kHash2Size - 1); \
|
||||
hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; }
|
||||
|
||||
#define HASH4_CALC { \
|
||||
UInt32 temp = g_CrcTable[cur[0]] ^ cur[1]; \
|
||||
hash2Value = temp & (kHash2Size - 1); \
|
||||
hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
|
||||
hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (g_CrcTable[cur[3]] << 5)) & p->hashMask; }
|
||||
|
||||
#define HASH5_CALC { \
|
||||
UInt32 temp = g_CrcTable[cur[0]] ^ cur[1]; \
|
||||
hash2Value = temp & (kHash2Size - 1); \
|
||||
hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
|
||||
hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (g_CrcTable[cur[3]] << 5)); \
|
||||
hashValue = (hash4Value ^ (g_CrcTable[cur[4]] << 3)) & p->hashMask; \
|
||||
hash4Value &= (kHash4Size - 1); }
|
||||
|
||||
/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ g_CrcTable[cur[2]]) & 0xFFFF; */
|
||||
#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ g_CrcTable[cur[1]]) & 0xFFFF;
|
||||
|
||||
|
||||
#define MT_HASH2_CALC \
|
||||
hash2Value = (g_CrcTable[cur[0]] ^ cur[1]) & (kHash2Size - 1);
|
||||
|
||||
#define MT_HASH3_CALC { \
|
||||
UInt32 temp = g_CrcTable[cur[0]] ^ cur[1]; \
|
||||
hash2Value = temp & (kHash2Size - 1); \
|
||||
hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); }
|
||||
|
||||
#define MT_HASH4_CALC { \
|
||||
UInt32 temp = g_CrcTable[cur[0]] ^ cur[1]; \
|
||||
hash2Value = temp & (kHash2Size - 1); \
|
||||
hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
|
||||
hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (g_CrcTable[cur[3]] << 5)) & (kHash4Size - 1); }
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,742 @@
|
||||
/* MatchFinder.c */
|
||||
/* Please call InitCrcTable before */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "MatchFinder.h"
|
||||
#include "LzHash.h"
|
||||
|
||||
#include "../../7zCrc.h"
|
||||
|
||||
#define kEmptyHashValue 0
|
||||
#define kMaxValForNormalize ((UInt32)0xFFFFFFFF)
|
||||
#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */
|
||||
#define kNormalizeMask (~(kNormalizeStepMin - 1))
|
||||
#define kMaxHistorySize ((UInt32)3 << 30)
|
||||
|
||||
#define kStartMaxLen 3
|
||||
|
||||
void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc)
|
||||
{
|
||||
if (!p->directInput)
|
||||
{
|
||||
alloc->Free(p->bufferBase);
|
||||
p->bufferBase = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */
|
||||
|
||||
int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc)
|
||||
{
|
||||
UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
|
||||
if (p->directInput)
|
||||
{
|
||||
p->blockSize = blockSize;
|
||||
return 1;
|
||||
}
|
||||
if (p->bufferBase == 0 || p->blockSize != blockSize)
|
||||
{
|
||||
LzInWindow_Free(p, alloc);
|
||||
p->blockSize = blockSize;
|
||||
p->bufferBase = (Byte *)alloc->Alloc(blockSize);
|
||||
}
|
||||
return (p->bufferBase != 0);
|
||||
}
|
||||
|
||||
Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
|
||||
Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; }
|
||||
|
||||
UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
|
||||
|
||||
void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
|
||||
{
|
||||
p->posLimit -= subValue;
|
||||
p->pos -= subValue;
|
||||
p->streamPos -= subValue;
|
||||
}
|
||||
|
||||
void MatchFinder_ReadBlock(CMatchFinder *p)
|
||||
{
|
||||
if (p->streamEndWasReached || p->result != SZ_OK)
|
||||
return;
|
||||
for (;;)
|
||||
{
|
||||
Byte *dest = p->buffer + (p->streamPos - p->pos);
|
||||
UInt32 numReadBytes;
|
||||
UInt32 size = (UInt32)(p->bufferBase + p->blockSize - dest);
|
||||
if (size == 0)
|
||||
return;
|
||||
p->result = p->stream->Read(p->stream, dest, size, &numReadBytes);
|
||||
if (p->result != SZ_OK)
|
||||
return;
|
||||
if (numReadBytes == 0)
|
||||
{
|
||||
p->streamEndWasReached = 1;
|
||||
return;
|
||||
}
|
||||
p->streamPos += numReadBytes;
|
||||
if (p->streamPos - p->pos > p->keepSizeAfter)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void MatchFinder_MoveBlock(CMatchFinder *p)
|
||||
{
|
||||
memmove(p->bufferBase,
|
||||
p->buffer - p->keepSizeBefore,
|
||||
p->streamPos - p->pos + p->keepSizeBefore);
|
||||
p->buffer = p->bufferBase + p->keepSizeBefore;
|
||||
}
|
||||
|
||||
int MatchFinder_NeedMove(CMatchFinder *p)
|
||||
{
|
||||
/* if (p->streamEndWasReached) return 0; */
|
||||
return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
|
||||
}
|
||||
|
||||
void MatchFinder_ReadIfRequired(CMatchFinder *p)
|
||||
{
|
||||
if (p->streamEndWasReached)
|
||||
return;
|
||||
if (p->keepSizeAfter >= p->streamPos - p->pos)
|
||||
MatchFinder_ReadBlock(p);
|
||||
}
|
||||
|
||||
void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)
|
||||
{
|
||||
if (MatchFinder_NeedMove(p))
|
||||
MatchFinder_MoveBlock(p);
|
||||
MatchFinder_ReadBlock(p);
|
||||
}
|
||||
|
||||
void MatchFinder_SetDefaultSettings(CMatchFinder *p)
|
||||
{
|
||||
p->cutValue = 32;
|
||||
p->btMode = 1;
|
||||
p->numHashBytes = 4;
|
||||
/* p->skipModeBits = 0; */
|
||||
p->directInput = 0;
|
||||
p->bigHash = 0;
|
||||
}
|
||||
|
||||
void MatchFinder_Construct(CMatchFinder *p)
|
||||
{
|
||||
p->bufferBase = 0;
|
||||
p->directInput = 0;
|
||||
p->hash = 0;
|
||||
MatchFinder_SetDefaultSettings(p);
|
||||
}
|
||||
|
||||
void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc)
|
||||
{
|
||||
alloc->Free(p->hash);
|
||||
p->hash = 0;
|
||||
}
|
||||
|
||||
void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc)
|
||||
{
|
||||
MatchFinder_FreeThisClassMemory(p, alloc);
|
||||
LzInWindow_Free(p, alloc);
|
||||
}
|
||||
|
||||
CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc)
|
||||
{
|
||||
size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
|
||||
if (sizeInBytes / sizeof(CLzRef) != num)
|
||||
return 0;
|
||||
return (CLzRef *)alloc->Alloc(sizeInBytes);
|
||||
}
|
||||
|
||||
int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
|
||||
UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
|
||||
ISzAlloc *alloc)
|
||||
{
|
||||
UInt32 sizeReserv;
|
||||
if (historySize > kMaxHistorySize)
|
||||
{
|
||||
MatchFinder_Free(p, alloc);
|
||||
return 0;
|
||||
}
|
||||
sizeReserv = historySize >> 1;
|
||||
if (historySize > ((UInt32)2 << 30))
|
||||
sizeReserv = historySize >> 2;
|
||||
sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19);
|
||||
|
||||
p->keepSizeBefore = historySize + keepAddBufferBefore + 1;
|
||||
p->keepSizeAfter = matchMaxLen + keepAddBufferAfter;
|
||||
/* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */
|
||||
if (LzInWindow_Create(p, sizeReserv, alloc))
|
||||
{
|
||||
UInt32 newCyclicBufferSize = (historySize /* >> p->skipModeBits */) + 1;
|
||||
UInt32 hs;
|
||||
p->matchMaxLen = matchMaxLen;
|
||||
{
|
||||
p->fixedHashSize = 0;
|
||||
if (p->numHashBytes == 2)
|
||||
hs = (1 << 16) - 1;
|
||||
else
|
||||
{
|
||||
hs = historySize - 1;
|
||||
hs |= (hs >> 1);
|
||||
hs |= (hs >> 2);
|
||||
hs |= (hs >> 4);
|
||||
hs |= (hs >> 8);
|
||||
hs >>= 1;
|
||||
/* hs >>= p->skipModeBits; */
|
||||
hs |= 0xFFFF; /* don't change it! It's required for Deflate */
|
||||
if (hs > (1 << 24))
|
||||
{
|
||||
if (p->numHashBytes == 3)
|
||||
hs = (1 << 24) - 1;
|
||||
else
|
||||
hs >>= 1;
|
||||
}
|
||||
}
|
||||
p->hashMask = hs;
|
||||
hs++;
|
||||
if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size;
|
||||
if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size;
|
||||
if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size;
|
||||
hs += p->fixedHashSize;
|
||||
}
|
||||
|
||||
{
|
||||
UInt32 prevSize = p->hashSizeSum + p->numSons;
|
||||
UInt32 newSize;
|
||||
p->historySize = historySize;
|
||||
p->hashSizeSum = hs;
|
||||
p->cyclicBufferSize = newCyclicBufferSize;
|
||||
p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize);
|
||||
newSize = p->hashSizeSum + p->numSons;
|
||||
if (p->hash != 0 && prevSize == newSize)
|
||||
return 1;
|
||||
MatchFinder_FreeThisClassMemory(p, alloc);
|
||||
p->hash = AllocRefs(newSize, alloc);
|
||||
if (p->hash != 0)
|
||||
{
|
||||
p->son = p->hash + p->hashSizeSum;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
MatchFinder_Free(p, alloc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MatchFinder_SetLimits(CMatchFinder *p)
|
||||
{
|
||||
UInt32 limit = kMaxValForNormalize - p->pos;
|
||||
UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos;
|
||||
if (limit2 < limit)
|
||||
limit = limit2;
|
||||
limit2 = p->streamPos - p->pos;
|
||||
if (limit2 <= p->keepSizeAfter)
|
||||
{
|
||||
if (limit2 > 0)
|
||||
limit2 = 1;
|
||||
}
|
||||
else
|
||||
limit2 -= p->keepSizeAfter;
|
||||
if (limit2 < limit)
|
||||
limit = limit2;
|
||||
{
|
||||
UInt32 lenLimit = p->streamPos - p->pos;
|
||||
if (lenLimit > p->matchMaxLen)
|
||||
lenLimit = p->matchMaxLen;
|
||||
p->lenLimit = lenLimit;
|
||||
}
|
||||
p->posLimit = p->pos + limit;
|
||||
}
|
||||
|
||||
void MatchFinder_Init(CMatchFinder *p)
|
||||
{
|
||||
UInt32 i;
|
||||
for(i = 0; i < p->hashSizeSum; i++)
|
||||
p->hash[i] = kEmptyHashValue;
|
||||
p->cyclicBufferPos = 0;
|
||||
p->buffer = p->bufferBase;
|
||||
p->pos = p->streamPos = p->cyclicBufferSize;
|
||||
p->result = SZ_OK;
|
||||
p->streamEndWasReached = 0;
|
||||
MatchFinder_ReadBlock(p);
|
||||
MatchFinder_SetLimits(p);
|
||||
}
|
||||
|
||||
UInt32 MatchFinder_GetSubValue(CMatchFinder *p)
|
||||
{
|
||||
return (p->pos - p->historySize - 1) & kNormalizeMask;
|
||||
}
|
||||
|
||||
void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
|
||||
{
|
||||
UInt32 i;
|
||||
for (i = 0; i < numItems; i++)
|
||||
{
|
||||
UInt32 value = items[i];
|
||||
if (value <= subValue)
|
||||
value = kEmptyHashValue;
|
||||
else
|
||||
value -= subValue;
|
||||
items[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void MatchFinder_Normalize(CMatchFinder *p)
|
||||
{
|
||||
UInt32 subValue = MatchFinder_GetSubValue(p);
|
||||
MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons);
|
||||
MatchFinder_ReduceOffsets(p, subValue);
|
||||
}
|
||||
|
||||
void MatchFinder_CheckLimits(CMatchFinder *p)
|
||||
{
|
||||
if (p->pos == kMaxValForNormalize)
|
||||
MatchFinder_Normalize(p);
|
||||
if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos)
|
||||
MatchFinder_CheckAndMoveAndRead(p);
|
||||
if (p->cyclicBufferPos == p->cyclicBufferSize)
|
||||
p->cyclicBufferPos = 0;
|
||||
MatchFinder_SetLimits(p);
|
||||
}
|
||||
|
||||
UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
|
||||
UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
|
||||
UInt32 *distances, UInt32 maxLen)
|
||||
{
|
||||
son[_cyclicBufferPos] = curMatch;
|
||||
for (;;)
|
||||
{
|
||||
UInt32 delta = pos - curMatch;
|
||||
if (cutValue-- == 0 || delta >= _cyclicBufferSize)
|
||||
return distances;
|
||||
{
|
||||
const Byte *pb = cur - delta;
|
||||
curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
|
||||
if (pb[maxLen] == cur[maxLen] && *pb == *cur)
|
||||
{
|
||||
UInt32 len = 0;
|
||||
while(++len != lenLimit)
|
||||
if (pb[len] != cur[len])
|
||||
break;
|
||||
if (maxLen < len)
|
||||
{
|
||||
*distances++ = maxLen = len;
|
||||
*distances++ = delta - 1;
|
||||
if (len == lenLimit)
|
||||
return distances;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
|
||||
UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
|
||||
UInt32 *distances, UInt32 maxLen)
|
||||
{
|
||||
CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
|
||||
CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
|
||||
UInt32 len0 = 0, len1 = 0;
|
||||
for (;;)
|
||||
{
|
||||
UInt32 delta = pos - curMatch;
|
||||
if (cutValue-- == 0 || delta >= _cyclicBufferSize)
|
||||
{
|
||||
*ptr0 = *ptr1 = kEmptyHashValue;
|
||||
return distances;
|
||||
}
|
||||
{
|
||||
CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
|
||||
const Byte *pb = cur - delta;
|
||||
UInt32 len = (len0 < len1 ? len0 : len1);
|
||||
if (pb[len] == cur[len])
|
||||
{
|
||||
if (++len != lenLimit && pb[len] == cur[len])
|
||||
while(++len != lenLimit)
|
||||
if (pb[len] != cur[len])
|
||||
break;
|
||||
if (maxLen < len)
|
||||
{
|
||||
*distances++ = maxLen = len;
|
||||
*distances++ = delta - 1;
|
||||
if (len == lenLimit)
|
||||
{
|
||||
*ptr1 = pair[0];
|
||||
*ptr0 = pair[1];
|
||||
return distances;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pb[len] < cur[len])
|
||||
{
|
||||
*ptr1 = curMatch;
|
||||
ptr1 = pair + 1;
|
||||
curMatch = *ptr1;
|
||||
len1 = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*ptr0 = curMatch;
|
||||
ptr0 = pair;
|
||||
curMatch = *ptr0;
|
||||
len0 = len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
|
||||
UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue)
|
||||
{
|
||||
CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
|
||||
CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
|
||||
UInt32 len0 = 0, len1 = 0;
|
||||
for (;;)
|
||||
{
|
||||
UInt32 delta = pos - curMatch;
|
||||
if (cutValue-- == 0 || delta >= _cyclicBufferSize)
|
||||
{
|
||||
*ptr0 = *ptr1 = kEmptyHashValue;
|
||||
return;
|
||||
}
|
||||
{
|
||||
CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
|
||||
const Byte *pb = cur - delta;
|
||||
UInt32 len = (len0 < len1 ? len0 : len1);
|
||||
if (pb[len] == cur[len])
|
||||
{
|
||||
while(++len != lenLimit)
|
||||
if (pb[len] != cur[len])
|
||||
break;
|
||||
{
|
||||
if (len == lenLimit)
|
||||
{
|
||||
*ptr1 = pair[0];
|
||||
*ptr0 = pair[1];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pb[len] < cur[len])
|
||||
{
|
||||
*ptr1 = curMatch;
|
||||
ptr1 = pair + 1;
|
||||
curMatch = *ptr1;
|
||||
len1 = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*ptr0 = curMatch;
|
||||
ptr0 = pair;
|
||||
curMatch = *ptr0;
|
||||
len0 = len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define MOVE_POS \
|
||||
++p->cyclicBufferPos; \
|
||||
p->buffer++; \
|
||||
if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p);
|
||||
|
||||
#define MOVE_POS_RET MOVE_POS return offset;
|
||||
|
||||
void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
|
||||
|
||||
#define GET_MATCHES_HEADER2(minLen, ret_op) \
|
||||
UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \
|
||||
lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
|
||||
cur = p->buffer;
|
||||
|
||||
#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0)
|
||||
#define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue)
|
||||
|
||||
#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue
|
||||
|
||||
#define GET_MATCHES_FOOTER(offset, maxLen) \
|
||||
offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \
|
||||
distances + offset, maxLen) - distances); MOVE_POS_RET;
|
||||
|
||||
#define SKIP_FOOTER \
|
||||
SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
|
||||
|
||||
UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
|
||||
{
|
||||
UInt32 offset;
|
||||
GET_MATCHES_HEADER(2)
|
||||
HASH2_CALC;
|
||||
curMatch = p->hash[hashValue];
|
||||
p->hash[hashValue] = p->pos;
|
||||
offset = 0;
|
||||
GET_MATCHES_FOOTER(offset, 1)
|
||||
}
|
||||
|
||||
UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
|
||||
{
|
||||
UInt32 offset;
|
||||
GET_MATCHES_HEADER(3)
|
||||
HASH_ZIP_CALC;
|
||||
curMatch = p->hash[hashValue];
|
||||
p->hash[hashValue] = p->pos;
|
||||
offset = 0;
|
||||
GET_MATCHES_FOOTER(offset, 2)
|
||||
}
|
||||
|
||||
UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
|
||||
{
|
||||
UInt32 hash2Value, delta2, maxLen, offset;
|
||||
GET_MATCHES_HEADER(3)
|
||||
|
||||
HASH3_CALC;
|
||||
|
||||
delta2 = p->pos - p->hash[hash2Value];
|
||||
curMatch = p->hash[kFix3HashSize + hashValue];
|
||||
|
||||
p->hash[hash2Value] =
|
||||
p->hash[kFix3HashSize + hashValue] = p->pos;
|
||||
|
||||
|
||||
maxLen = 2;
|
||||
offset = 0;
|
||||
if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
|
||||
{
|
||||
for (; maxLen != lenLimit; maxLen++)
|
||||
if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
|
||||
break;
|
||||
distances[0] = maxLen;
|
||||
distances[1] = delta2 - 1;
|
||||
offset = 2;
|
||||
if (maxLen == lenLimit)
|
||||
{
|
||||
SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
|
||||
MOVE_POS_RET;
|
||||
}
|
||||
}
|
||||
GET_MATCHES_FOOTER(offset, maxLen)
|
||||
}
|
||||
|
||||
UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
|
||||
{
|
||||
UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
|
||||
GET_MATCHES_HEADER(4)
|
||||
|
||||
HASH4_CALC;
|
||||
|
||||
delta2 = p->pos - p->hash[ hash2Value];
|
||||
delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
|
||||
curMatch = p->hash[kFix4HashSize + hashValue];
|
||||
|
||||
p->hash[ hash2Value] =
|
||||
p->hash[kFix3HashSize + hash3Value] =
|
||||
p->hash[kFix4HashSize + hashValue] = p->pos;
|
||||
|
||||
maxLen = 1;
|
||||
offset = 0;
|
||||
if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
|
||||
{
|
||||
distances[0] = maxLen = 2;
|
||||
distances[1] = delta2 - 1;
|
||||
offset = 2;
|
||||
}
|
||||
if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
|
||||
{
|
||||
maxLen = 3;
|
||||
distances[offset + 1] = delta3 - 1;
|
||||
offset += 2;
|
||||
delta2 = delta3;
|
||||
}
|
||||
if (offset != 0)
|
||||
{
|
||||
for (; maxLen != lenLimit; maxLen++)
|
||||
if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
|
||||
break;
|
||||
distances[offset - 2] = maxLen;
|
||||
if (maxLen == lenLimit)
|
||||
{
|
||||
SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
|
||||
MOVE_POS_RET;
|
||||
}
|
||||
}
|
||||
if (maxLen < 3)
|
||||
maxLen = 3;
|
||||
GET_MATCHES_FOOTER(offset, maxLen)
|
||||
}
|
||||
|
||||
UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
|
||||
{
|
||||
UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
|
||||
GET_MATCHES_HEADER(4)
|
||||
|
||||
HASH4_CALC;
|
||||
|
||||
delta2 = p->pos - p->hash[ hash2Value];
|
||||
delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
|
||||
curMatch = p->hash[kFix4HashSize + hashValue];
|
||||
|
||||
p->hash[ hash2Value] =
|
||||
p->hash[kFix3HashSize + hash3Value] =
|
||||
p->hash[kFix4HashSize + hashValue] = p->pos;
|
||||
|
||||
maxLen = 1;
|
||||
offset = 0;
|
||||
if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
|
||||
{
|
||||
distances[0] = maxLen = 2;
|
||||
distances[1] = delta2 - 1;
|
||||
offset = 2;
|
||||
}
|
||||
if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
|
||||
{
|
||||
maxLen = 3;
|
||||
distances[offset + 1] = delta3 - 1;
|
||||
offset += 2;
|
||||
delta2 = delta3;
|
||||
}
|
||||
if (offset != 0)
|
||||
{
|
||||
for (; maxLen != lenLimit; maxLen++)
|
||||
if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
|
||||
break;
|
||||
distances[offset - 2] = maxLen;
|
||||
if (maxLen == lenLimit)
|
||||
{
|
||||
p->son[p->cyclicBufferPos] = curMatch;
|
||||
MOVE_POS_RET;
|
||||
}
|
||||
}
|
||||
if (maxLen < 3)
|
||||
maxLen = 3;
|
||||
offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
|
||||
distances + offset, maxLen) - (distances));
|
||||
MOVE_POS_RET
|
||||
}
|
||||
|
||||
UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
|
||||
{
|
||||
UInt32 offset;
|
||||
GET_MATCHES_HEADER(3)
|
||||
HASH_ZIP_CALC;
|
||||
curMatch = p->hash[hashValue];
|
||||
p->hash[hashValue] = p->pos;
|
||||
offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
|
||||
distances, 2) - (distances));
|
||||
MOVE_POS_RET
|
||||
}
|
||||
|
||||
void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
|
||||
{
|
||||
do
|
||||
{
|
||||
SKIP_HEADER(2)
|
||||
HASH2_CALC;
|
||||
curMatch = p->hash[hashValue];
|
||||
p->hash[hashValue] = p->pos;
|
||||
SKIP_FOOTER
|
||||
}
|
||||
while (--num != 0);
|
||||
}
|
||||
|
||||
void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
|
||||
{
|
||||
do
|
||||
{
|
||||
SKIP_HEADER(3)
|
||||
HASH_ZIP_CALC;
|
||||
curMatch = p->hash[hashValue];
|
||||
p->hash[hashValue] = p->pos;
|
||||
SKIP_FOOTER
|
||||
}
|
||||
while (--num != 0);
|
||||
}
|
||||
|
||||
void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
|
||||
{
|
||||
do
|
||||
{
|
||||
UInt32 hash2Value;
|
||||
SKIP_HEADER(3)
|
||||
HASH3_CALC;
|
||||
curMatch = p->hash[kFix3HashSize + hashValue];
|
||||
p->hash[hash2Value] =
|
||||
p->hash[kFix3HashSize + hashValue] = p->pos;
|
||||
SKIP_FOOTER
|
||||
}
|
||||
while (--num != 0);
|
||||
}
|
||||
|
||||
void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
|
||||
{
|
||||
do
|
||||
{
|
||||
UInt32 hash2Value, hash3Value;
|
||||
SKIP_HEADER(4)
|
||||
HASH4_CALC;
|
||||
curMatch = p->hash[kFix4HashSize + hashValue];
|
||||
p->hash[ hash2Value] =
|
||||
p->hash[kFix3HashSize + hash3Value] = p->pos;
|
||||
p->hash[kFix4HashSize + hashValue] = p->pos;
|
||||
SKIP_FOOTER
|
||||
}
|
||||
while (--num != 0);
|
||||
}
|
||||
|
||||
void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
|
||||
{
|
||||
do
|
||||
{
|
||||
UInt32 hash2Value, hash3Value;
|
||||
SKIP_HEADER(4)
|
||||
HASH4_CALC;
|
||||
curMatch = p->hash[kFix4HashSize + hashValue];
|
||||
p->hash[ hash2Value] =
|
||||
p->hash[kFix3HashSize + hash3Value] =
|
||||
p->hash[kFix4HashSize + hashValue] = p->pos;
|
||||
p->son[p->cyclicBufferPos] = curMatch;
|
||||
MOVE_POS
|
||||
}
|
||||
while (--num != 0);
|
||||
}
|
||||
|
||||
void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
|
||||
{
|
||||
do
|
||||
{
|
||||
SKIP_HEADER(3)
|
||||
HASH_ZIP_CALC;
|
||||
curMatch = p->hash[hashValue];
|
||||
p->hash[hashValue] = p->pos;
|
||||
p->son[p->cyclicBufferPos] = curMatch;
|
||||
MOVE_POS
|
||||
}
|
||||
while (--num != 0);
|
||||
}
|
||||
|
||||
void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
|
||||
{
|
||||
vTable->Init = (Mf_Init_Func)MatchFinder_Init;
|
||||
vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte;
|
||||
vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
|
||||
vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
|
||||
if (!p->btMode)
|
||||
{
|
||||
vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
|
||||
vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
|
||||
}
|
||||
else if (p->numHashBytes == 2)
|
||||
{
|
||||
vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
|
||||
vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
|
||||
}
|
||||
else if (p->numHashBytes == 3)
|
||||
{
|
||||
vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
|
||||
vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
|
||||
}
|
||||
else
|
||||
{
|
||||
vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
|
||||
vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/* MatchFinder.h */
|
||||
|
||||
#ifndef __MATCHFINDER_H
|
||||
#define __MATCHFINDER_H
|
||||
|
||||
#include "../../IStream.h"
|
||||
|
||||
typedef UInt32 CLzRef;
|
||||
|
||||
typedef struct _CMatchFinder
|
||||
{
|
||||
Byte *buffer;
|
||||
UInt32 pos;
|
||||
UInt32 posLimit;
|
||||
UInt32 streamPos;
|
||||
UInt32 lenLimit;
|
||||
|
||||
UInt32 cyclicBufferPos;
|
||||
UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */
|
||||
|
||||
UInt32 matchMaxLen;
|
||||
CLzRef *hash;
|
||||
CLzRef *son;
|
||||
UInt32 hashMask;
|
||||
UInt32 cutValue;
|
||||
|
||||
Byte *bufferBase;
|
||||
ISeqInStream *stream;
|
||||
int streamEndWasReached;
|
||||
|
||||
UInt32 blockSize;
|
||||
UInt32 keepSizeBefore;
|
||||
UInt32 keepSizeAfter;
|
||||
|
||||
UInt32 numHashBytes;
|
||||
int directInput;
|
||||
int btMode;
|
||||
/* int skipModeBits; */
|
||||
int bigHash;
|
||||
UInt32 historySize;
|
||||
UInt32 fixedHashSize;
|
||||
UInt32 hashSizeSum;
|
||||
UInt32 numSons;
|
||||
|
||||
HRes result;
|
||||
} CMatchFinder;
|
||||
|
||||
#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer)
|
||||
#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)])
|
||||
|
||||
#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos)
|
||||
|
||||
int MatchFinder_NeedMove(CMatchFinder *p);
|
||||
Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p);
|
||||
void MatchFinder_MoveBlock(CMatchFinder *p);
|
||||
void MatchFinder_ReadIfRequired(CMatchFinder *p);
|
||||
|
||||
void MatchFinder_Construct(CMatchFinder *p);
|
||||
|
||||
/* Conditions:
|
||||
historySize <= 3 GB
|
||||
keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB
|
||||
*/
|
||||
int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
|
||||
UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
|
||||
ISzAlloc *alloc);
|
||||
void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc);
|
||||
void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems);
|
||||
void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);
|
||||
|
||||
UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son,
|
||||
UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
|
||||
UInt32 *distances, UInt32 maxLen);
|
||||
|
||||
/*
|
||||
Conditions:
|
||||
Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func.
|
||||
Mf_GetPointerToCurrentPos_Func's result must be used only before any other function
|
||||
*/
|
||||
|
||||
typedef void (*Mf_Init_Func)(void *object);
|
||||
typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index);
|
||||
typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object);
|
||||
typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object);
|
||||
typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances);
|
||||
typedef void (*Mf_Skip_Func)(void *object, UInt32);
|
||||
|
||||
typedef struct _IMatchFinder
|
||||
{
|
||||
Mf_Init_Func Init;
|
||||
Mf_GetIndexByte_Func GetIndexByte;
|
||||
Mf_GetNumAvailableBytes_Func GetNumAvailableBytes;
|
||||
Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos;
|
||||
Mf_GetMatches_Func GetMatches;
|
||||
Mf_Skip_Func Skip;
|
||||
} IMatchFinder;
|
||||
|
||||
void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable);
|
||||
|
||||
void MatchFinder_Init(CMatchFinder *p);
|
||||
UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
|
||||
UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
|
||||
void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
|
||||
void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,806 @@
|
||||
/* MatchFinderMt.c */
|
||||
|
||||
#ifdef _WIN32
|
||||
#define USE_ALLOCA
|
||||
#endif
|
||||
|
||||
#ifdef USE_ALLOCA
|
||||
#ifdef _WIN32
|
||||
#include <malloc.h>
|
||||
#else
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "../../7zCrc.h"
|
||||
#include "LzHash.h"
|
||||
|
||||
#include "MatchFinderMt.h"
|
||||
|
||||
void MtSync_Construct(CMtSync *p)
|
||||
{
|
||||
p->wasCreated = False;
|
||||
p->csWasInitialized = False;
|
||||
p->csWasEntered = False;
|
||||
Thread_Construct(&p->thread);
|
||||
Event_Construct(&p->canStart);
|
||||
Event_Construct(&p->wasStarted);
|
||||
Event_Construct(&p->wasStopped);
|
||||
Semaphore_Construct(&p->freeSemaphore);
|
||||
Semaphore_Construct(&p->filledSemaphore);
|
||||
}
|
||||
|
||||
void MtSync_GetNextBlock(CMtSync *p)
|
||||
{
|
||||
if (p->needStart)
|
||||
{
|
||||
p->numProcessedBlocks = 1;
|
||||
p->needStart = False;
|
||||
p->stopWriting = False;
|
||||
p->exit = False;
|
||||
Event_Reset(&p->wasStarted);
|
||||
Event_Reset(&p->wasStopped);
|
||||
|
||||
Event_Set(&p->canStart);
|
||||
Event_Wait(&p->wasStarted);
|
||||
}
|
||||
else
|
||||
{
|
||||
CriticalSection_Leave(&p->cs);
|
||||
p->csWasEntered = False;
|
||||
p->numProcessedBlocks++;
|
||||
Semaphore_Release1(&p->freeSemaphore);
|
||||
}
|
||||
Semaphore_Wait(&p->filledSemaphore);
|
||||
CriticalSection_Enter(&p->cs);
|
||||
p->csWasEntered = True;
|
||||
}
|
||||
|
||||
/* MtSync_StopWriting must be called if Writing was started */
|
||||
|
||||
void MtSync_StopWriting(CMtSync *p)
|
||||
{
|
||||
UInt32 myNumBlocks = p->numProcessedBlocks;
|
||||
if (!Thread_WasCreated(&p->thread) || p->needStart)
|
||||
return;
|
||||
p->stopWriting = True;
|
||||
if (p->csWasEntered)
|
||||
{
|
||||
CriticalSection_Leave(&p->cs);
|
||||
p->csWasEntered = False;
|
||||
}
|
||||
Semaphore_Release1(&p->freeSemaphore);
|
||||
|
||||
Event_Wait(&p->wasStopped);
|
||||
|
||||
while (myNumBlocks++ != p->numProcessedBlocks)
|
||||
{
|
||||
Semaphore_Wait(&p->filledSemaphore);
|
||||
Semaphore_Release1(&p->freeSemaphore);
|
||||
}
|
||||
p->needStart = True;
|
||||
}
|
||||
|
||||
void MtSync_Destruct(CMtSync *p)
|
||||
{
|
||||
if (Thread_WasCreated(&p->thread))
|
||||
{
|
||||
MtSync_StopWriting(p);
|
||||
p->exit = True;
|
||||
if (p->needStart)
|
||||
Event_Set(&p->canStart);
|
||||
Thread_Wait(&p->thread);
|
||||
Thread_Close(&p->thread);
|
||||
}
|
||||
if (p->csWasInitialized)
|
||||
{
|
||||
CriticalSection_Delete(&p->cs);
|
||||
p->csWasInitialized = False;
|
||||
}
|
||||
|
||||
Event_Close(&p->canStart);
|
||||
Event_Close(&p->wasStarted);
|
||||
Event_Close(&p->wasStopped);
|
||||
Semaphore_Close(&p->freeSemaphore);
|
||||
Semaphore_Close(&p->filledSemaphore);
|
||||
|
||||
p->wasCreated = False;
|
||||
}
|
||||
|
||||
HRes MtSync_Create2(CMtSync *p, unsigned (StdCall *startAddress)(void *), void *obj, UInt32 numBlocks)
|
||||
{
|
||||
if (p->wasCreated)
|
||||
return SZ_OK;
|
||||
|
||||
RINOK(CriticalSection_Init(&p->cs));
|
||||
p->csWasInitialized = True;
|
||||
|
||||
RINOK(AutoResetEvent_CreateNotSignaled(&p->canStart));
|
||||
RINOK(AutoResetEvent_CreateNotSignaled(&p->wasStarted));
|
||||
RINOK(AutoResetEvent_CreateNotSignaled(&p->wasStopped));
|
||||
|
||||
RINOK(Semaphore_Create(&p->freeSemaphore, numBlocks, numBlocks));
|
||||
RINOK(Semaphore_Create(&p->filledSemaphore, 0, numBlocks));
|
||||
|
||||
p->needStart = True;
|
||||
|
||||
RINOK(Thread_Create(&p->thread, startAddress, obj));
|
||||
p->wasCreated = True;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
HRes MtSync_Create(CMtSync *p, unsigned (StdCall *startAddress)(void *), void *obj, UInt32 numBlocks)
|
||||
{
|
||||
HRes res = MtSync_Create2(p, startAddress, obj, numBlocks);
|
||||
if (res != SZ_OK)
|
||||
MtSync_Destruct(p);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void MtSync_Init(CMtSync *p) { p->needStart = True; }
|
||||
|
||||
#define kMtMaxValForNormalize 0xFFFFFFFF
|
||||
|
||||
#define DEF_GetHeads(name, v) \
|
||||
static void GetHeads ## name(const Byte *p, UInt32 pos, \
|
||||
UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads) { \
|
||||
for (; numHeads != 0; numHeads--) { \
|
||||
const UInt32 value = (v); p++; *heads++ = pos - hash[value]; hash[value] = pos++; } }
|
||||
|
||||
DEF_GetHeads(2, (p[0] | ((UInt32)p[1] << 8)) & hashMask)
|
||||
DEF_GetHeads(3, (g_CrcTable[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8)) & hashMask)
|
||||
DEF_GetHeads(4, (g_CrcTable[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (g_CrcTable[p[3]] << 5)) & hashMask)
|
||||
DEF_GetHeads(4b, (g_CrcTable[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ ((UInt32)p[3] << 16)) & hashMask)
|
||||
DEF_GetHeads(5, (g_CrcTable[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (g_CrcTable[p[3]] << 5) ^ (g_CrcTable[p[4]] << 3)) & hashMask)
|
||||
|
||||
void HashThreadFunc(CMatchFinderMt *mt)
|
||||
{
|
||||
CMtSync *p = &mt->hashSync;
|
||||
for (;;)
|
||||
{
|
||||
UInt32 numProcessedBlocks = 0;
|
||||
Event_Wait(&p->canStart);
|
||||
Event_Set(&p->wasStarted);
|
||||
for (;;)
|
||||
{
|
||||
if (p->exit)
|
||||
return;
|
||||
if (p->stopWriting)
|
||||
{
|
||||
p->numProcessedBlocks = numProcessedBlocks;
|
||||
Event_Set(&p->wasStopped);
|
||||
break;
|
||||
}
|
||||
|
||||
{
|
||||
CMatchFinder *mf = mt->MatchFinder;
|
||||
if (MatchFinder_NeedMove(mf))
|
||||
{
|
||||
CriticalSection_Enter(&mt->btSync.cs);
|
||||
CriticalSection_Enter(&mt->hashSync.cs);
|
||||
{
|
||||
const Byte *beforePtr = MatchFinder_GetPointerToCurrentPos(mf);
|
||||
const Byte *afterPtr;
|
||||
MatchFinder_MoveBlock(mf);
|
||||
afterPtr = MatchFinder_GetPointerToCurrentPos(mf);
|
||||
mt->pointerToCurPos -= beforePtr - afterPtr;
|
||||
mt->buffer -= beforePtr - afterPtr;
|
||||
}
|
||||
CriticalSection_Leave(&mt->btSync.cs);
|
||||
CriticalSection_Leave(&mt->hashSync.cs);
|
||||
continue;
|
||||
}
|
||||
|
||||
Semaphore_Wait(&p->freeSemaphore);
|
||||
|
||||
MatchFinder_ReadIfRequired(mf);
|
||||
if (mf->pos > (kMtMaxValForNormalize - kMtHashBlockSize))
|
||||
{
|
||||
UInt32 subValue = (mf->pos - mf->historySize - 1);
|
||||
MatchFinder_ReduceOffsets(mf, subValue);
|
||||
MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, mf->hashMask + 1);
|
||||
}
|
||||
{
|
||||
UInt32 *heads = mt->hashBuf + ((numProcessedBlocks++) & kMtHashNumBlocksMask) * kMtHashBlockSize;
|
||||
UInt32 num = mf->streamPos - mf->pos;
|
||||
heads[0] = 2;
|
||||
heads[1] = num;
|
||||
if (num >= mf->numHashBytes)
|
||||
{
|
||||
num = num - mf->numHashBytes + 1;
|
||||
if (num > kMtHashBlockSize - 2)
|
||||
num = kMtHashBlockSize - 2;
|
||||
mt->GetHeadsFunc(mf->buffer, mf->pos, mf->hash + mf->fixedHashSize, mf->hashMask, heads + 2, num);
|
||||
heads[0] += num;
|
||||
}
|
||||
mf->pos += num;
|
||||
mf->buffer += num;
|
||||
}
|
||||
}
|
||||
|
||||
Semaphore_Release1(&p->filledSemaphore);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt *p)
|
||||
{
|
||||
MtSync_GetNextBlock(&p->hashSync);
|
||||
p->hashBufPosLimit = p->hashBufPos = ((p->hashSync.numProcessedBlocks - 1) & kMtHashNumBlocksMask) * kMtHashBlockSize;
|
||||
p->hashBufPosLimit += p->hashBuf[p->hashBufPos++];
|
||||
p->hashNumAvail = p->hashBuf[p->hashBufPos++];
|
||||
}
|
||||
|
||||
#define kEmptyHashValue 0
|
||||
|
||||
/* #define MFMT_GM_INLINE */
|
||||
|
||||
#ifdef MFMT_GM_INLINE
|
||||
|
||||
#if _MSC_VER >= 1300
|
||||
#define NO_INLINE __declspec(noinline) __fastcall
|
||||
#else
|
||||
#ifdef _MSC_VER
|
||||
#define NO_INLINE __fastcall
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Int32 NO_INLINE GetMatchesSpecN(UInt32 lenLimit, UInt32 pos, const Byte *cur, CLzRef *son,
|
||||
UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
|
||||
UInt32 *_distances, UInt32 _maxLen, const UInt32 *hash, Int32 limit, UInt32 size, UInt32 *posRes)
|
||||
{
|
||||
do
|
||||
{
|
||||
UInt32 *distances = _distances + 1;
|
||||
UInt32 curMatch = pos - *hash++;
|
||||
|
||||
CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
|
||||
CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
|
||||
UInt32 len0 = 0, len1 = 0;
|
||||
UInt32 cutValue = _cutValue;
|
||||
UInt32 maxLen = _maxLen;
|
||||
for (;;)
|
||||
{
|
||||
UInt32 delta = pos - curMatch;
|
||||
if (cutValue-- == 0 || delta >= _cyclicBufferSize)
|
||||
{
|
||||
*ptr0 = *ptr1 = kEmptyHashValue;
|
||||
break;
|
||||
}
|
||||
{
|
||||
CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
|
||||
const Byte *pb = cur - delta;
|
||||
UInt32 len = (len0 < len1 ? len0 : len1);
|
||||
if (pb[len] == cur[len])
|
||||
{
|
||||
if (++len != lenLimit && pb[len] == cur[len])
|
||||
while(++len != lenLimit)
|
||||
if (pb[len] != cur[len])
|
||||
break;
|
||||
if (maxLen < len)
|
||||
{
|
||||
*distances++ = maxLen = len;
|
||||
*distances++ = delta - 1;
|
||||
if (len == lenLimit)
|
||||
{
|
||||
*ptr1 = pair[0];
|
||||
*ptr0 = pair[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pb[len] < cur[len])
|
||||
{
|
||||
*ptr1 = curMatch;
|
||||
ptr1 = pair + 1;
|
||||
curMatch = *ptr1;
|
||||
len1 = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*ptr0 = curMatch;
|
||||
ptr0 = pair;
|
||||
curMatch = *ptr0;
|
||||
len0 = len;
|
||||
}
|
||||
}
|
||||
}
|
||||
pos++;
|
||||
_cyclicBufferPos++;
|
||||
cur++;
|
||||
{
|
||||
UInt32 num = (UInt32)(distances - _distances);
|
||||
*_distances = num - 1;
|
||||
_distances += num;
|
||||
limit -= num;
|
||||
}
|
||||
}
|
||||
while (limit > 0 && --size != 0);
|
||||
*posRes = pos;
|
||||
return limit;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void BtGetMatches(CMatchFinderMt *p, UInt32 *distances)
|
||||
{
|
||||
UInt32 numProcessed = 0;
|
||||
UInt32 curPos = 2;
|
||||
UInt32 limit = kMtBtBlockSize - (p->matchMaxLen * 2);
|
||||
distances[1] = p->hashNumAvail;
|
||||
while (curPos < limit)
|
||||
{
|
||||
if (p->hashBufPos == p->hashBufPosLimit)
|
||||
{
|
||||
MatchFinderMt_GetNextBlock_Hash(p);
|
||||
distances[1] = numProcessed + p->hashNumAvail;
|
||||
if (p->hashNumAvail >= p->numHashBytes)
|
||||
continue;
|
||||
for (; p->hashNumAvail != 0; p->hashNumAvail--)
|
||||
distances[curPos++] = 0;
|
||||
break;
|
||||
}
|
||||
{
|
||||
UInt32 size = p->hashBufPosLimit - p->hashBufPos;
|
||||
UInt32 lenLimit = p->matchMaxLen;
|
||||
UInt32 pos = p->pos;
|
||||
UInt32 cyclicBufferPos = p->cyclicBufferPos;
|
||||
if (lenLimit >= p->hashNumAvail)
|
||||
lenLimit = p->hashNumAvail;
|
||||
{
|
||||
UInt32 size2 = p->hashNumAvail - lenLimit + 1;
|
||||
if (size2 < size)
|
||||
size = size2;
|
||||
size2 = p->cyclicBufferSize - cyclicBufferPos;
|
||||
if (size2 < size)
|
||||
size = size2;
|
||||
}
|
||||
#ifndef MFMT_GM_INLINE
|
||||
while (curPos < limit && size-- != 0)
|
||||
{
|
||||
UInt32 *startDistances = distances + curPos;
|
||||
UInt32 num = (UInt32)(GetMatchesSpec1(lenLimit, pos - p->hashBuf[p->hashBufPos++],
|
||||
pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue,
|
||||
startDistances + 1, p->numHashBytes - 1) - startDistances);
|
||||
*startDistances = num - 1;
|
||||
curPos += num;
|
||||
cyclicBufferPos++;
|
||||
pos++;
|
||||
p->buffer++;
|
||||
}
|
||||
#else
|
||||
{
|
||||
UInt32 posRes;
|
||||
curPos = limit - GetMatchesSpecN(lenLimit, pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue,
|
||||
distances + curPos, p->numHashBytes - 1, p->hashBuf + p->hashBufPos, (Int32)(limit - curPos) , size, &posRes);
|
||||
p->hashBufPos += posRes - pos;
|
||||
cyclicBufferPos += posRes - pos;
|
||||
p->buffer += posRes - pos;
|
||||
pos = posRes;
|
||||
}
|
||||
#endif
|
||||
|
||||
numProcessed += pos - p->pos;
|
||||
p->hashNumAvail -= pos - p->pos;
|
||||
p->pos = pos;
|
||||
if (cyclicBufferPos == p->cyclicBufferSize)
|
||||
cyclicBufferPos = 0;
|
||||
p->cyclicBufferPos = cyclicBufferPos;
|
||||
}
|
||||
}
|
||||
distances[0] = curPos;
|
||||
}
|
||||
|
||||
void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex)
|
||||
{
|
||||
CMtSync *sync = &p->hashSync;
|
||||
if (!sync->needStart)
|
||||
{
|
||||
CriticalSection_Enter(&sync->cs);
|
||||
sync->csWasEntered = True;
|
||||
}
|
||||
|
||||
BtGetMatches(p, p->btBuf + (globalBlockIndex & kMtBtNumBlocksMask) * kMtBtBlockSize);
|
||||
|
||||
if (p->pos > kMtMaxValForNormalize - kMtBtBlockSize)
|
||||
{
|
||||
UInt32 subValue = p->pos - p->cyclicBufferSize;
|
||||
MatchFinder_Normalize3(subValue, p->son, p->cyclicBufferSize * 2);
|
||||
p->pos -= subValue;
|
||||
}
|
||||
|
||||
if (!sync->needStart)
|
||||
{
|
||||
CriticalSection_Leave(&sync->cs);
|
||||
sync->csWasEntered = False;
|
||||
}
|
||||
}
|
||||
|
||||
void BtThreadFunc(CMatchFinderMt *mt)
|
||||
{
|
||||
CMtSync *p = &mt->btSync;
|
||||
for (;;)
|
||||
{
|
||||
UInt32 blockIndex = 0;
|
||||
Event_Wait(&p->canStart);
|
||||
Event_Set(&p->wasStarted);
|
||||
for (;;)
|
||||
{
|
||||
if (p->exit)
|
||||
return;
|
||||
if (p->stopWriting)
|
||||
{
|
||||
p->numProcessedBlocks = blockIndex;
|
||||
MtSync_StopWriting(&mt->hashSync);
|
||||
Event_Set(&p->wasStopped);
|
||||
break;
|
||||
}
|
||||
Semaphore_Wait(&p->freeSemaphore);
|
||||
BtFillBlock(mt, blockIndex++);
|
||||
Semaphore_Release1(&p->filledSemaphore);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MatchFinderMt_Construct(CMatchFinderMt *p)
|
||||
{
|
||||
p->hashBuf = 0;
|
||||
MtSync_Construct(&p->hashSync);
|
||||
MtSync_Construct(&p->btSync);
|
||||
}
|
||||
|
||||
void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAlloc *alloc)
|
||||
{
|
||||
alloc->Free(p->hashBuf);
|
||||
p->hashBuf = 0;
|
||||
}
|
||||
|
||||
void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAlloc *alloc)
|
||||
{
|
||||
MtSync_Destruct(&p->hashSync);
|
||||
MtSync_Destruct(&p->btSync);
|
||||
MatchFinderMt_FreeMem(p, alloc);
|
||||
}
|
||||
|
||||
#define kHashBufferSize (kMtHashBlockSize * kMtHashNumBlocks)
|
||||
#define kBtBufferSize (kMtBtBlockSize * kMtBtNumBlocks)
|
||||
|
||||
static unsigned StdCall HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p); return 0; }
|
||||
static unsigned StdCall BtThreadFunc2(void *p)
|
||||
{
|
||||
#ifdef USE_ALLOCA
|
||||
alloca(0x180);
|
||||
#endif
|
||||
BtThreadFunc((CMatchFinderMt *)p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
HRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore,
|
||||
UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc)
|
||||
{
|
||||
CMatchFinder *mf = p->MatchFinder;
|
||||
p->historySize = historySize;
|
||||
if (kMtBtBlockSize <= matchMaxLen * 4)
|
||||
return E_INVALIDARG;
|
||||
if (p->hashBuf == 0)
|
||||
{
|
||||
p->hashBuf = (UInt32 *)alloc->Alloc((kHashBufferSize + kBtBufferSize) * sizeof(UInt32));
|
||||
if (p->hashBuf == 0)
|
||||
return SZE_OUTOFMEMORY;
|
||||
p->btBuf = p->hashBuf + kHashBufferSize;
|
||||
}
|
||||
keepAddBufferBefore += (kHashBufferSize + kBtBufferSize);
|
||||
keepAddBufferAfter += kMtHashBlockSize;
|
||||
if (!MatchFinder_Create(mf, historySize, keepAddBufferBefore, matchMaxLen, keepAddBufferAfter, alloc))
|
||||
return SZE_OUTOFMEMORY;
|
||||
|
||||
RINOK(MtSync_Create(&p->hashSync, HashThreadFunc2, p, kMtHashNumBlocks));
|
||||
RINOK(MtSync_Create(&p->btSync, BtThreadFunc2, p, kMtBtNumBlocks));
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
/* Call it after ReleaseStream / SetStream */
|
||||
void MatchFinderMt_Init(CMatchFinderMt *p)
|
||||
{
|
||||
CMatchFinder *mf = p->MatchFinder;
|
||||
p->btBufPos = p->btBufPosLimit = 0;
|
||||
p->hashBufPos = p->hashBufPosLimit = 0;
|
||||
MatchFinder_Init(mf);
|
||||
p->pointerToCurPos = MatchFinder_GetPointerToCurrentPos(mf);
|
||||
p->btNumAvailBytes = 0;
|
||||
p->lzPos = p->historySize + 1;
|
||||
|
||||
p->hash = mf->hash;
|
||||
p->fixedHashSize = mf->fixedHashSize;
|
||||
|
||||
p->son = mf->son;
|
||||
p->matchMaxLen = mf->matchMaxLen;
|
||||
p->numHashBytes = mf->numHashBytes;
|
||||
p->pos = mf->pos;
|
||||
p->buffer = mf->buffer;
|
||||
p->cyclicBufferPos = mf->cyclicBufferPos;
|
||||
p->cyclicBufferSize = mf->cyclicBufferSize;
|
||||
p->cutValue = mf->cutValue;
|
||||
}
|
||||
|
||||
/* ReleaseStream is required to finish multithreading */
|
||||
void MatchFinderMt_ReleaseStream(CMatchFinderMt *p)
|
||||
{
|
||||
MtSync_StopWriting(&p->btSync);
|
||||
/* p->MatchFinder->ReleaseStream(); */
|
||||
}
|
||||
|
||||
void MatchFinderMt_Normalize(CMatchFinderMt *p)
|
||||
{
|
||||
MatchFinder_Normalize3(p->lzPos - p->historySize - 1, p->hash, p->fixedHashSize);
|
||||
p->lzPos = p->historySize + 1;
|
||||
}
|
||||
|
||||
void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p)
|
||||
{
|
||||
UInt32 blockIndex;
|
||||
MtSync_GetNextBlock(&p->btSync);
|
||||
blockIndex = ((p->btSync.numProcessedBlocks - 1) & kMtBtNumBlocksMask);
|
||||
p->btBufPosLimit = p->btBufPos = blockIndex * kMtBtBlockSize;
|
||||
p->btBufPosLimit += p->btBuf[p->btBufPos++];
|
||||
p->btNumAvailBytes = p->btBuf[p->btBufPos++];
|
||||
if (p->lzPos >= kMtMaxValForNormalize - kMtBtBlockSize)
|
||||
MatchFinderMt_Normalize(p);
|
||||
}
|
||||
|
||||
const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p)
|
||||
{
|
||||
return p->pointerToCurPos;
|
||||
}
|
||||
|
||||
#define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p);
|
||||
|
||||
UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p)
|
||||
{
|
||||
GET_NEXT_BLOCK_IF_REQUIRED;
|
||||
return p->btNumAvailBytes;
|
||||
}
|
||||
|
||||
Byte MatchFinderMt_GetIndexByte(CMatchFinderMt *p, Int32 index)
|
||||
{
|
||||
return p->pointerToCurPos[index];
|
||||
}
|
||||
|
||||
UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
|
||||
{
|
||||
UInt32 hash2Value, curMatch2;
|
||||
UInt32 *hash = p->hash;
|
||||
const Byte *cur = p->pointerToCurPos;
|
||||
UInt32 lzPos = p->lzPos;
|
||||
MT_HASH2_CALC
|
||||
|
||||
curMatch2 = hash[hash2Value];
|
||||
hash[hash2Value] = lzPos;
|
||||
|
||||
if (curMatch2 >= matchMinPos)
|
||||
if (cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
|
||||
{
|
||||
*distances++ = 2;
|
||||
*distances++ = lzPos - curMatch2 - 1;
|
||||
}
|
||||
return distances;
|
||||
}
|
||||
|
||||
UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
|
||||
{
|
||||
UInt32 hash2Value, hash3Value, curMatch2, curMatch3;
|
||||
UInt32 *hash = p->hash;
|
||||
const Byte *cur = p->pointerToCurPos;
|
||||
UInt32 lzPos = p->lzPos;
|
||||
MT_HASH3_CALC
|
||||
|
||||
curMatch2 = hash[ hash2Value];
|
||||
curMatch3 = hash[kFix3HashSize + hash3Value];
|
||||
|
||||
hash[ hash2Value] =
|
||||
hash[kFix3HashSize + hash3Value] =
|
||||
lzPos;
|
||||
|
||||
if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
|
||||
{
|
||||
distances[1] = lzPos - curMatch2 - 1;
|
||||
if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2])
|
||||
{
|
||||
distances[0] = 3;
|
||||
return distances + 2;
|
||||
}
|
||||
distances[0] = 2;
|
||||
distances += 2;
|
||||
}
|
||||
if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0])
|
||||
{
|
||||
*distances++ = 3;
|
||||
*distances++ = lzPos - curMatch3 - 1;
|
||||
}
|
||||
return distances;
|
||||
}
|
||||
|
||||
/*
|
||||
UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
|
||||
{
|
||||
UInt32 hash2Value, hash3Value, hash4Value, curMatch2, curMatch3, curMatch4;
|
||||
UInt32 *hash = p->hash;
|
||||
const Byte *cur = p->pointerToCurPos;
|
||||
UInt32 lzPos = p->lzPos;
|
||||
MT_HASH4_CALC
|
||||
|
||||
curMatch2 = hash[ hash2Value];
|
||||
curMatch3 = hash[kFix3HashSize + hash3Value];
|
||||
curMatch4 = hash[kFix4HashSize + hash4Value];
|
||||
|
||||
hash[ hash2Value] =
|
||||
hash[kFix3HashSize + hash3Value] =
|
||||
hash[kFix4HashSize + hash4Value] =
|
||||
lzPos;
|
||||
|
||||
if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
|
||||
{
|
||||
distances[1] = lzPos - curMatch2 - 1;
|
||||
if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2])
|
||||
{
|
||||
distances[0] = (cur[(ptrdiff_t)curMatch2 - lzPos + 3] == cur[3]) ? 4 : 3;
|
||||
return distances + 2;
|
||||
}
|
||||
distances[0] = 2;
|
||||
distances += 2;
|
||||
}
|
||||
if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0])
|
||||
{
|
||||
distances[1] = lzPos - curMatch3 - 1;
|
||||
if (cur[(ptrdiff_t)curMatch3 - lzPos + 3] == cur[3])
|
||||
{
|
||||
distances[0] = 4;
|
||||
return distances + 2;
|
||||
}
|
||||
distances[0] = 3;
|
||||
distances += 2;
|
||||
}
|
||||
|
||||
if (curMatch4 >= matchMinPos)
|
||||
if (
|
||||
cur[(ptrdiff_t)curMatch4 - lzPos] == cur[0] &&
|
||||
cur[(ptrdiff_t)curMatch4 - lzPos + 3] == cur[3]
|
||||
)
|
||||
{
|
||||
*distances++ = 4;
|
||||
*distances++ = lzPos - curMatch4 - 1;
|
||||
}
|
||||
return distances;
|
||||
}
|
||||
*/
|
||||
|
||||
#define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++;
|
||||
|
||||
UInt32 MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *distances)
|
||||
{
|
||||
const UInt32 *btBuf = p->btBuf + p->btBufPos;
|
||||
UInt32 len = *btBuf++;
|
||||
p->btBufPos += 1 + len;
|
||||
p->btNumAvailBytes--;
|
||||
{
|
||||
UInt32 i;
|
||||
for (i = 0; i < len; i += 2)
|
||||
{
|
||||
*distances++ = *btBuf++;
|
||||
*distances++ = *btBuf++;
|
||||
}
|
||||
}
|
||||
INCREASE_LZ_POS
|
||||
return len;
|
||||
}
|
||||
|
||||
UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances)
|
||||
{
|
||||
const UInt32 *btBuf = p->btBuf + p->btBufPos;
|
||||
UInt32 len = *btBuf++;
|
||||
p->btBufPos += 1 + len;
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
if (p->btNumAvailBytes-- >= 4)
|
||||
len = (UInt32)(p->MixMatchesFunc(p, p->lzPos - p->historySize, distances) - (distances));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Condition: there are matches in btBuf with length < p->numHashBytes */
|
||||
UInt32 *distances2;
|
||||
p->btNumAvailBytes--;
|
||||
distances2 = p->MixMatchesFunc(p, p->lzPos - btBuf[1], distances);
|
||||
do
|
||||
{
|
||||
*distances2++ = *btBuf++;
|
||||
*distances2++ = *btBuf++;
|
||||
}
|
||||
while ((len -= 2) != 0);
|
||||
len = (UInt32)(distances2 - (distances));
|
||||
}
|
||||
INCREASE_LZ_POS
|
||||
return len;
|
||||
}
|
||||
|
||||
#define SKIP_HEADER2 do { GET_NEXT_BLOCK_IF_REQUIRED
|
||||
#define SKIP_HEADER(n) SKIP_HEADER2 if (p->btNumAvailBytes-- >= (n)) { const Byte *cur = p->pointerToCurPos; UInt32 *hash = p->hash;
|
||||
#define SKIP_FOOTER } INCREASE_LZ_POS p->btBufPos += p->btBuf[p->btBufPos] + 1; } while(--num != 0);
|
||||
|
||||
void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num)
|
||||
{
|
||||
SKIP_HEADER2 { p->btNumAvailBytes--;
|
||||
SKIP_FOOTER
|
||||
}
|
||||
|
||||
void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num)
|
||||
{
|
||||
SKIP_HEADER(2)
|
||||
UInt32 hash2Value;
|
||||
MT_HASH2_CALC
|
||||
hash[hash2Value] = p->lzPos;
|
||||
SKIP_FOOTER
|
||||
}
|
||||
|
||||
void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num)
|
||||
{
|
||||
SKIP_HEADER(3)
|
||||
UInt32 hash2Value, hash3Value;
|
||||
MT_HASH3_CALC
|
||||
hash[kFix3HashSize + hash3Value] =
|
||||
hash[ hash2Value] =
|
||||
p->lzPos;
|
||||
SKIP_FOOTER
|
||||
}
|
||||
|
||||
/*
|
||||
void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num)
|
||||
{
|
||||
SKIP_HEADER(4)
|
||||
UInt32 hash2Value, hash3Value, hash4Value;
|
||||
MT_HASH4_CALC
|
||||
hash[kFix4HashSize + hash4Value] =
|
||||
hash[kFix3HashSize + hash3Value] =
|
||||
hash[ hash2Value] =
|
||||
p->lzPos;
|
||||
SKIP_FOOTER
|
||||
}
|
||||
*/
|
||||
|
||||
void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable)
|
||||
{
|
||||
vTable->Init = (Mf_Init_Func)MatchFinderMt_Init;
|
||||
vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinderMt_GetIndexByte;
|
||||
vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinderMt_GetNumAvailableBytes;
|
||||
vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinderMt_GetPointerToCurrentPos;
|
||||
vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches;
|
||||
switch(p->MatchFinder->numHashBytes)
|
||||
{
|
||||
case 2:
|
||||
p->GetHeadsFunc = GetHeads2;
|
||||
p->MixMatchesFunc = (Mf_Mix_Matches)0;
|
||||
vTable->Skip = (Mf_Skip_Func)MatchFinderMt0_Skip;
|
||||
vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt2_GetMatches;
|
||||
break;
|
||||
case 3:
|
||||
p->GetHeadsFunc = GetHeads3;
|
||||
p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches2;
|
||||
vTable->Skip = (Mf_Skip_Func)MatchFinderMt2_Skip;
|
||||
break;
|
||||
default:
|
||||
/* case 4: */
|
||||
p->GetHeadsFunc = p->MatchFinder->bigHash ? GetHeads4b : GetHeads4;
|
||||
/* p->GetHeadsFunc = GetHeads4; */
|
||||
p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches3;
|
||||
vTable->Skip = (Mf_Skip_Func)MatchFinderMt3_Skip;
|
||||
break;
|
||||
/*
|
||||
default:
|
||||
p->GetHeadsFunc = GetHeads5;
|
||||
p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches4;
|
||||
vTable->Skip = (Mf_Skip_Func)MatchFinderMt4_Skip;
|
||||
break;
|
||||
*/
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user