Browse Source

Add PhysFS 2.0.3.

rude 12 years ago
parent
commit
b170f825e8
100 changed files with 17390 additions and 0 deletions
  1. 5 0
      libs/physfs-2.0.3/.hg_archival.txt
  2. 2 0
      libs/physfs-2.0.3/.hgignore
  3. 17 0
      libs/physfs-2.0.3/.hgtags
  4. 11 0
      libs/physfs-2.0.3/CHANGELOG.txt
  5. 407 0
      libs/physfs-2.0.3/CMakeLists.txt
  6. 116 0
      libs/physfs-2.0.3/CREDITS.txt
  7. 1079 0
      libs/physfs-2.0.3/Doxyfile
  8. 153 0
      libs/physfs-2.0.3/INSTALL.txt
  9. 44 0
      libs/physfs-2.0.3/LICENSE.txt
  10. 45 0
      libs/physfs-2.0.3/TODO.txt
  11. 283 0
      libs/physfs-2.0.3/archivers/dir.c
  12. 475 0
      libs/physfs-2.0.3/archivers/grp.c
  13. 514 0
      libs/physfs-2.0.3/archivers/hog.c
  14. 736 0
      libs/physfs-2.0.3/archivers/lzma.c
  15. 471 0
      libs/physfs-2.0.3/archivers/mvl.c
  16. 633 0
      libs/physfs-2.0.3/archivers/qpak.c
  17. 531 0
      libs/physfs-2.0.3/archivers/wad.c
  18. 1472 0
      libs/physfs-2.0.3/archivers/zip.c
  19. 58 0
      libs/physfs-2.0.3/extras/PhysFS.NET/AssemblyInfo.cs
  20. 113 0
      libs/physfs-2.0.3/extras/PhysFS.NET/PhysFS.NET.csproj
  21. 21 0
      libs/physfs-2.0.3/extras/PhysFS.NET/PhysFS.NET.sln
  22. 189 0
      libs/physfs-2.0.3/extras/PhysFS.NET/PhysFS.cs
  23. 194 0
      libs/physfs-2.0.3/extras/PhysFS.NET/PhysFSFileStream.cs
  24. 113 0
      libs/physfs-2.0.3/extras/PhysFS.NET/PhysFS_DLL.cs
  25. 10 0
      libs/physfs-2.0.3/extras/PhysFS.NET/README.txt
  26. BIN
      libs/physfs-2.0.3/extras/PhysFS.NET/TestApp/App.ico
  27. 58 0
      libs/physfs-2.0.3/extras/PhysFS.NET/TestApp/AssemblyInfo.cs
  28. 116 0
      libs/physfs-2.0.3/extras/PhysFS.NET/TestApp/TestApp.csproj
  29. 27 0
      libs/physfs-2.0.3/extras/PhysFS.NET/TestApp/TestApp.sln
  30. 274 0
      libs/physfs-2.0.3/extras/PhysFS.NET/TestApp/TestAppForm.cs
  31. 102 0
      libs/physfs-2.0.3/extras/PhysFS.NET/TestApp/TestAppForm.resx
  32. 165 0
      libs/physfs-2.0.3/extras/abs-file.h
  33. 1064 0
      libs/physfs-2.0.3/extras/casefolding.txt
  34. 159 0
      libs/physfs-2.0.3/extras/globbing.c
  35. 89 0
      libs/physfs-2.0.3/extras/globbing.h
  36. 219 0
      libs/physfs-2.0.3/extras/ignorecase.c
  37. 87 0
      libs/physfs-2.0.3/extras/ignorecase.h
  38. 85 0
      libs/physfs-2.0.3/extras/makecasefoldhashtable.pl
  39. 103 0
      libs/physfs-2.0.3/extras/physfs_rb/installer.rb
  40. 9 0
      libs/physfs-2.0.3/extras/physfs_rb/physfs/extconf.rb
  41. 7 0
      libs/physfs-2.0.3/extras/physfs_rb/physfs/install.rb
  42. 9 0
      libs/physfs-2.0.3/extras/physfs_rb/physfs/make_install_test.sh
  43. 121 0
      libs/physfs-2.0.3/extras/physfs_rb/physfs/physfs.rb
  44. 192 0
      libs/physfs-2.0.3/extras/physfs_rb/physfs/physfsrwops.c
  45. 87 0
      libs/physfs-2.0.3/extras/physfs_rb/physfs/physfsrwops.h
  46. 462 0
      libs/physfs-2.0.3/extras/physfs_rb/physfs/rb_physfs.c
  47. 13 0
      libs/physfs-2.0.3/extras/physfs_rb/physfs/rb_physfs.h
  48. 226 0
      libs/physfs-2.0.3/extras/physfs_rb/physfs/rb_physfs_file.c
  49. 24 0
      libs/physfs-2.0.3/extras/physfs_rb/physfs/rb_physfs_file.h
  50. 162 0
      libs/physfs-2.0.3/extras/physfs_rb/physfs/rb_sdl_rwops.c
  51. 16 0
      libs/physfs-2.0.3/extras/physfs_rb/physfs/rb_sdl_rwops.h
  52. 358 0
      libs/physfs-2.0.3/extras/physfs_rb/physfs/test/test_physfs.rb
  53. 291 0
      libs/physfs-2.0.3/extras/physfshttpd.c
  54. 193 0
      libs/physfs-2.0.3/extras/physfsrwops.c
  55. 88 0
      libs/physfs-2.0.3/extras/physfsrwops.h
  56. 181 0
      libs/physfs-2.0.3/extras/physfsunpack.c
  57. 66 0
      libs/physfs-2.0.3/extras/selfextract.c
  58. 237 0
      libs/physfs-2.0.3/lzma/7zC.txt
  59. 471 0
      libs/physfs-2.0.3/lzma/7zFormat.txt
  60. 32 0
      libs/physfs-2.0.3/lzma/C/7zCrc.c
  61. 21 0
      libs/physfs-2.0.3/lzma/C/7zCrc.h
  62. 40 0
      libs/physfs-2.0.3/lzma/C/7zCrcT8.c
  63. 119 0
      libs/physfs-2.0.3/lzma/C/Alloc.c
  64. 29 0
      libs/physfs-2.0.3/lzma/C/Alloc.h
  65. 70 0
      libs/physfs-2.0.3/lzma/C/Archive/7z/7zAlloc.c
  66. 20 0
      libs/physfs-2.0.3/lzma/C/Archive/7z/7zAlloc.h
  67. 29 0
      libs/physfs-2.0.3/lzma/C/Archive/7z/7zBuffer.c
  68. 19 0
      libs/physfs-2.0.3/lzma/C/Archive/7z/7zBuffer.h
  69. 345 0
      libs/physfs-2.0.3/lzma/C/Archive/7z/7zDecode.c
  70. 20 0
      libs/physfs-2.0.3/lzma/C/Archive/7z/7zDecode.h
  71. 119 0
      libs/physfs-2.0.3/lzma/C/Archive/7z/7zExtract.c
  72. 40 0
      libs/physfs-2.0.3/lzma/C/Archive/7z/7zExtract.h
  73. 5 0
      libs/physfs-2.0.3/lzma/C/Archive/7z/7zHeader.c
  74. 55 0
      libs/physfs-2.0.3/lzma/C/Archive/7z/7zHeader.h
  75. 1314 0
      libs/physfs-2.0.3/lzma/C/Archive/7z/7zIn.c
  76. 55 0
      libs/physfs-2.0.3/lzma/C/Archive/7z/7zIn.h
  77. 134 0
      libs/physfs-2.0.3/lzma/C/Archive/7z/7zItem.c
  78. 95 0
      libs/physfs-2.0.3/lzma/C/Archive/7z/7zItem.h
  79. 428 0
      libs/physfs-2.0.3/lzma/C/Archive/7z/7zMain.c
  80. 10 0
      libs/physfs-2.0.3/lzma/C/Archive/7z/7zMethodID.c
  81. 10 0
      libs/physfs-2.0.3/lzma/C/Archive/7z/7zMethodID.h
  82. 211 0
      libs/physfs-2.0.3/lzma/C/Archive/7z/7z_C.dsp
  83. 29 0
      libs/physfs-2.0.3/lzma/C/Archive/7z/7z_C.dsw
  84. 74 0
      libs/physfs-2.0.3/lzma/C/Archive/7z/makefile
  85. 55 0
      libs/physfs-2.0.3/lzma/C/Archive/7z/makefile.gcc
  86. 26 0
      libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchARM.c
  87. 10 0
      libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchARM.h
  88. 35 0
      libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchARMThumb.c
  89. 10 0
      libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchARMThumb.h
  90. 66 0
      libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchIA64.c
  91. 10 0
      libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchIA64.h
  92. 36 0
      libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchPPC.c
  93. 10 0
      libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchPPC.h
  94. 36 0
      libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchSPARC.c
  95. 10 0
      libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchSPARC.h
  96. 51 0
      libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchTypes.h
  97. 84 0
      libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchX86.c
  98. 12 0
      libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchX86.h
  99. 135 0
      libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchX86_2.c
  100. 28 0
      libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchX86_2.h

+ 5 - 0
libs/physfs-2.0.3/.hg_archival.txt

@@ -0,0 +1,5 @@
+repo: 7672c9962ce627edaaa67ff54fe4ad8f9a46dc2b
+node: f94eec5e90540889a42c34a27931b8266f4af52c
+branch: stable-2.0
+latesttag: release-2.0.3
+latesttagdistance: 1

+ 2 - 0
libs/physfs-2.0.3/.hgignore

@@ -0,0 +1,2 @@
+syntax:glob
+cmake-build

+ 17 - 0
libs/physfs-2.0.3/.hgtags

@@ -0,0 +1,17 @@
+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
+94771621792f838aa4cacf9a1e1f4f86c1cb0711 release-2.0.1
+236afd18dd8cae34adb9897024bdcecc1dc8ca5d release-2.0.2
+bf155bd2127befa399105194e13737d7c3496be0 release-2.0.3

+ 11 - 0
libs/physfs-2.0.3/CHANGELOG.txt

@@ -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/
+
+

+ 407 - 0
libs/physfs-2.0.3/CMakeLists.txt

@@ -0,0 +1,407 @@
+# PhysicsFS; a portable, flexible file i/o abstraction.
+# Copyright (C) 2007  Ryan C. Gordon.
+#
+# Please see the file LICENSE.txt in the source's root directory.
+
+CMAKE_MINIMUM_REQUIRED(VERSION 2.4)
+
+PROJECT(PhysicsFS)
+SET(PHYSFS_VERSION 2.0.3)
+
+# Increment this if/when we break backwards compatibility.
+SET(PHYSFS_SOVERSION 1)
+
+# I hate that they define "WIN32" ... we're about to move to Win64...I hope!
+IF(WIN32 AND NOT WINDOWS)
+    SET(WINDOWS TRUE)
+ENDIF(WIN32 AND NOT WINDOWS)
+
+# Bleh, let's do it for "APPLE" too.
+IF(APPLE AND NOT MACOSX)
+    SET(MACOSX TRUE)
+ENDIF(APPLE AND NOT MACOSX)
+
+# For now, Haiku and BeOS are the same, as far as the build system cares.
+IF(HAIKU AND NOT BEOS)
+    SET(BEOS TRUE)
+ENDIF(HAIKU AND NOT BEOS)
+
+INCLUDE(CheckIncludeFile)
+INCLUDE(CheckLibraryExists)
+INCLUDE(CheckCSourceCompiles)
+
+INCLUDE_DIRECTORIES(.)
+#INCLUDE_DIRECTORIES(platform)
+#INCLUDE_DIRECTORIES(archivers)
+
+IF(MACOSX)
+    # Fallback to older OS X on PowerPC to support wider range of systems...
+    IF(CMAKE_OSX_ARCHITECTURES MATCHES ppc)
+        ADD_DEFINITIONS(-DMAC_OS_X_VERSION_MIN_REQUIRED=1020)
+        SET(OTHER_LDFLAGS ${OTHER_LDFLAGS} " -mmacosx-version-min=10.2")
+    ENDIF(CMAKE_OSX_ARCHITECTURES MATCHES ppc)
+
+    # Need these everywhere...
+    ADD_DEFINITIONS(-fno-common)
+    SET(OTHER_LDFLAGS ${OTHER_LDFLAGS} " -framework Carbon -framework IOKit")
+ENDIF(MACOSX)
+
+# Add some gcc-specific command lines.
+IF(CMAKE_COMPILER_IS_GNUCC)
+    # Always build with debug symbols...you can strip it later.
+    ADD_DEFINITIONS(-g -pipe -Werror -fsigned-char)
+
+    # Stupid BeOS generates warnings in the system headers.
+    IF(NOT BEOS)
+        ADD_DEFINITIONS(-Wall)
+    ENDIF(NOT BEOS)
+
+    CHECK_C_SOURCE_COMPILES("
+        #if ((defined(__GNUC__)) && (__GNUC__ >= 4))
+        int main(int argc, char **argv) { int is_gcc4 = 1; return 0; }
+        #else
+        #error This is not gcc4.
+        #endif
+    " PHYSFS_IS_GCC4)
+
+    IF(PHYSFS_IS_GCC4)
+        # Not supported on several operating systems at this time.
+        IF(NOT OS2 AND NOT SOLARIS AND NOT WINDOWS)
+             ADD_DEFINITIONS(-fvisibility=hidden)
+        ENDIF(NOT OS2 AND NOT SOLARIS AND NOT WINDOWS)
+    ENDIF(PHYSFS_IS_GCC4)
+ENDIF(CMAKE_COMPILER_IS_GNUCC)
+
+IF(MSVC)
+    # VS.NET 8.0 got really really anal about strcpy, etc, which even if we
+    #  cleaned up our code, zlib, etc still use...so disable the warning.
+    ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS=1)
+ENDIF(MSVC)
+
+# Basic chunks of source code ...
+
+SET(ZLIB_SRCS
+    zlib123/adler32.c
+    zlib123/compress.c
+    zlib123/crc32.c
+    zlib123/deflate.c
+    zlib123/gzio.c
+    zlib123/infback.c
+    zlib123/inffast.c
+    zlib123/inflate.c
+    zlib123/inftrees.c
+    zlib123/trees.c
+    zlib123/uncompr.c
+    zlib123/zutil.c
+)
+
+SET(LZMA_SRCS
+    lzma/C/7zCrc.c
+    lzma/C/Archive/7z/7zBuffer.c
+    lzma/C/Archive/7z/7zDecode.c
+    lzma/C/Archive/7z/7zExtract.c
+    lzma/C/Archive/7z/7zHeader.c
+    lzma/C/Archive/7z/7zIn.c
+    lzma/C/Archive/7z/7zItem.c
+    lzma/C/Archive/7z/7zMethodID.c
+    lzma/C/Compress/Branch/BranchX86.c
+    lzma/C/Compress/Branch/BranchX86_2.c
+    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 platform/beos.cpp)
+    FIND_LIBRARY(BE_LIBRARY be)
+    FIND_LIBRARY(ROOT_LIBRARY root)
+    SET(OPTIONAL_LIBRARY_LIBS ${OPTIONAL_LIBRARY_LIBS} ${BE_LIBRARY} ${ROOT_LIBRARY})
+ENDIF(BEOS)
+
+# Almost everything is "compiled" here, but things that don't apply to the
+#  build are #ifdef'd out. This is to make it easy to embed PhysicsFS into
+#  another project or bring up a new build system: just compile all the source
+#  code and #define the things you want.
+SET(PHYSFS_SRCS
+    physfs.c
+    physfs_byteorder.c
+    physfs_unicode.c
+    platform/os2.c
+    platform/pocketpc.c
+    platform/posix.c
+    platform/unix.c
+    platform/macosx.c
+    platform/windows.c
+    archivers/dir.c
+    archivers/grp.c
+    archivers/hog.c
+    archivers/lzma.c
+    archivers/mvl.c
+    archivers/qpak.c
+    archivers/wad.c
+    archivers/zip.c
+    ${PHYSFS_BEOS_SRCS}
+)
+
+
+# platform layers ...
+
+IF(UNIX)
+    IF(BEOS)
+        SET(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
+        SET(PHYSFS_HAVE_THREAD_SUPPORT TRUE)
+        SET(HAVE_PTHREAD_H TRUE)
+    ELSE(BEOS)
+        # !!! FIXME
+        #  AC_DEFINE([PHYSFS_HAVE_LLSEEK], 1, [define if we have llseek])
+        CHECK_INCLUDE_FILE(sys/ucred.h HAVE_UCRED_H)
+        IF(HAVE_UCRED_H)
+            ADD_DEFINITIONS(-DPHYSFS_HAVE_SYS_UCRED_H=1)
+            SET(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
+        ENDIF(HAVE_UCRED_H)
+
+        CHECK_INCLUDE_FILE(mntent.h HAVE_MNTENT_H)
+        IF(HAVE_MNTENT_H)
+            ADD_DEFINITIONS(-DPHYSFS_HAVE_MNTENT_H=1)
+            SET(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
+        ENDIF(HAVE_MNTENT_H)
+
+        CHECK_INCLUDE_FILE(pthread.h HAVE_PTHREAD_H)
+        IF(HAVE_PTHREAD_H)
+            SET(PHYSFS_HAVE_THREAD_SUPPORT TRUE)
+        ENDIF(HAVE_PTHREAD_H)
+    ENDIF(BEOS)
+ENDIF(UNIX)
+
+IF(WINDOWS)
+    SET(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
+    SET(PHYSFS_HAVE_THREAD_SUPPORT TRUE)
+ENDIF(WINDOWS)
+
+IF(NOT PHYSFS_HAVE_CDROM_SUPPORT)
+    ADD_DEFINITIONS(-DPHYSFS_NO_CDROM_SUPPORT=1)
+    MESSAGE(WARNING " ***")
+    MESSAGE(WARNING " *** There is no CD-ROM support in this build!")
+    MESSAGE(WARNING " *** PhysicsFS will just pretend there are no discs.")
+    MESSAGE(WARNING " *** This may be fine, depending on how PhysicsFS is used,")
+    MESSAGE(WARNING " ***   but is this what you REALLY wanted?")
+    MESSAGE(WARNING " *** (Maybe fix CMakeLists.txt, or write a platform driver?)")
+    MESSAGE(WARNING " ***")
+ENDIF(NOT PHYSFS_HAVE_CDROM_SUPPORT)
+
+IF(PHYSFS_HAVE_THREAD_SUPPORT)
+    ADD_DEFINITIONS(-D_REENTRANT -D_THREAD_SAFE)
+ELSE(PHYSFS_HAVE_THREAD_SUPPORT)
+    ADD_DEFINITIONS(-DPHYSFS_NO_THREAD_SUPPORT=1)
+    MESSAGE(WARNING " ***")
+    MESSAGE(WARNING " *** There is no thread support in this build!")
+    MESSAGE(WARNING " *** PhysicsFS will NOT be reentrant!")
+    MESSAGE(WARNING " *** This may be fine, depending on how PhysicsFS is used,")
+    MESSAGE(WARNING " ***   but is this what you REALLY wanted?")
+    MESSAGE(WARNING " *** (Maybe fix CMakeLists.txt, or write a platform driver?)")
+    MESSAGE(WARNING " ***")
+ENDIF(PHYSFS_HAVE_THREAD_SUPPORT)
+
+CHECK_INCLUDE_FILE(assert.h HAVE_ASSERT_H)
+IF(HAVE_ASSERT_H)
+    ADD_DEFINITIONS(-DHAVE_ASSERT_H=1)
+ENDIF(HAVE_ASSERT_H)
+
+
+
+# Archivers ...
+
+OPTION(PHYSFS_ARCHIVE_ZIP "Enable ZIP support" TRUE)
+IF(PHYSFS_ARCHIVE_ZIP)
+    ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_ZIP=1)
+    SET(PHYSFS_NEED_ZLIB TRUE)
+ENDIF(PHYSFS_ARCHIVE_ZIP)
+
+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(PHYSFS_ARCHIVE_7Z)
+
+OPTION(PHYSFS_ARCHIVE_GRP "Enable Build Engine GRP support" TRUE)
+IF(PHYSFS_ARCHIVE_GRP)
+    ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_GRP=1)
+ENDIF(PHYSFS_ARCHIVE_GRP)
+
+OPTION(PHYSFS_ARCHIVE_WAD "Enable Doom WAD support" TRUE)
+IF(PHYSFS_ARCHIVE_WAD)
+    ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_WAD=1)
+ENDIF(PHYSFS_ARCHIVE_WAD)
+
+OPTION(PHYSFS_ARCHIVE_HOG "Enable Descent I/II HOG support" TRUE)
+IF(PHYSFS_ARCHIVE_HOG)
+    ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_HOG=1)
+ENDIF(PHYSFS_ARCHIVE_HOG)
+
+OPTION(PHYSFS_ARCHIVE_MVL "Enable Descent I/II MVL support" TRUE)
+IF(PHYSFS_ARCHIVE_MVL)
+    ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_MVL=1)
+ENDIF(PHYSFS_ARCHIVE_MVL)
+
+OPTION(PHYSFS_ARCHIVE_QPAK "Enable Quake I/II QPAK support" TRUE)
+IF(PHYSFS_ARCHIVE_QPAK)
+    ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_QPAK=1)
+ENDIF(PHYSFS_ARCHIVE_QPAK)
+
+
+# See if some archiver required zlib, and see about using system version.
+
+IF(PHYSFS_NEED_ZLIB)
+    FIND_PACKAGE(ZLIB)
+
+    IF(ZLIB_FOUND)
+        OPTION(PHYSFS_INTERNAL_ZLIB "Link own zlib instead of system library" FALSE)
+    ELSE(HAVE_SYSTEM_ZLIB)
+        SET(PHYSFS_INTERNAL_ZLIB TRUE)
+    ENDIF(ZLIB_FOUND)
+
+    IF(PHYSFS_INTERNAL_ZLIB)
+        INCLUDE_DIRECTORIES(zlib123)
+        ADD_DEFINITIONS(-DZ_PREFIX=1)
+        SET(PHYSFS_SRCS ${PHYSFS_SRCS} ${ZLIB_SRCS})
+    ELSE(PHYSFS_INTERNAL_ZLIB)
+        SET(OPTIONAL_LIBRARY_LIBS ${OPTIONAL_LIBRARY_LIBS} ${ZLIB_LIBRARY})
+        INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
+    ENDIF(PHYSFS_INTERNAL_ZLIB)
+ENDIF(PHYSFS_NEED_ZLIB)
+
+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(PHYSFS_BUILD_STATIC)
+
+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(PHYSFS_BUILD_SHARED)
+
+IF(NOT PHYSFS_BUILD_SHARED AND NOT PHYSFS_BUILD_STATIC)
+    MESSAGE(FATAL "Both shared and static libraries are disabled!")
+ENDIF(NOT PHYSFS_BUILD_SHARED AND NOT PHYSFS_BUILD_STATIC)
+
+# CMake FAQ says I need this...
+IF(PHYSFS_BUILD_SHARED AND PHYSFS_BUILD_STATIC)
+    SET_TARGET_PROPERTIES(physfs PROPERTIES CLEAN_DIRECT_OUTPUT 1)
+    SET_TARGET_PROPERTIES(physfs-static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
+ENDIF(PHYSFS_BUILD_SHARED AND PHYSFS_BUILD_STATIC)
+
+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(READLINE_LIBRARY)
+    ENDIF(READLINE_H AND HISTORY_H)
+    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(PHYSFS_BUILD_TEST)
+
+OPTION(PHYSFS_BUILD_WX_TEST "Build wxWidgets test program." FALSE)
+MARK_AS_ADVANCED(PHYSFS_BUILD_WX_TEST)
+IF(PHYSFS_BUILD_WX_TEST)
+    SET(wxWidgets_USE_LIBS base core adv)
+    SET(wxWidgets_INCLUDE_DIRS_NO_SYSTEM 1)
+    FIND_PACKAGE(wxWidgets)
+    IF(wxWidgets_FOUND)
+        INCLUDE(${wxWidgets_USE_FILE})
+        ADD_EXECUTABLE(wxtest_physfs test/wxtest_physfs.cpp)
+        SET_SOURCE_FILES_PROPERTIES(test/wxtest_physfs.cpp COMPILE_FLAGS ${wxWidgets_CXX_FLAGS})
+        TARGET_LINK_LIBRARIES(wxtest_physfs ${PHYSFS_LIB_TARGET} ${wxWidgets_LIBRARIES} ${OTHER_LDFLAGS})
+        SET(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";wxtest_physfs")
+    ELSE(wxWidgets_FOUND)
+        MESSAGE(STATUS "wxWidgets not found. Disabling wx test app.")
+        SET(PHYSFS_BUILD_WX_TEST FALSE)
+    ENDIF(wxWidgets_FOUND)
+ENDIF(PHYSFS_BUILD_WX_TEST)
+
+INSTALL(TARGETS ${PHYSFS_INSTALL_TARGETS}
+        RUNTIME DESTINATION bin
+        LIBRARY DESTINATION lib${LIB_SUFFIX}
+        ARCHIVE DESTINATION lib${LIB_SUFFIX})
+INSTALL(FILES 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}/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(DOXYGEN_FOUND)
+    MESSAGE(STATUS "Doxygen not found. You won't be able to build documentation.")
+ENDIF(DOXYGEN_FOUND)
+
+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}'..."
+    )
+ENDIF(UNIX)
+
+MACRO(MESSAGE_BOOL_OPTION _NAME _VALUE)
+    IF(${_VALUE})
+        MESSAGE(STATUS "  ${_NAME}: enabled")
+    ELSE(${_VALUE})
+        MESSAGE(STATUS "  ${_NAME}: disabled")
+    ENDIF(${_VALUE})
+ENDMACRO(MESSAGE_BOOL_OPTION)
+
+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("CD-ROM drive support" PHYSFS_HAVE_CDROM_SUPPORT)
+MESSAGE_BOOL_OPTION("Thread safety" PHYSFS_HAVE_THREAD_SUPPORT)
+MESSAGE_BOOL_OPTION("Build own zlib" PHYSFS_INTERNAL_ZLIB)
+MESSAGE_BOOL_OPTION("Build static library" PHYSFS_BUILD_STATIC)
+MESSAGE_BOOL_OPTION("Build shared library" PHYSFS_BUILD_SHARED)
+MESSAGE_BOOL_OPTION("Build wxWidgets test program" PHYSFS_BUILD_WX_TEST)
+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(PHYSFS_BUILD_TEST)
+
+# end of CMakeLists.txt ...

+ 116 - 0
libs/physfs-2.0.3/CREDITS.txt

@@ -0,0 +1,116 @@
+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,
+Ruby bindings,
+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
+
+Bug fixes:
+    Lauri Kasanen
+
+Other stuff:
+    Your name here! Patches go to [email protected] ...
+
+/* end of CREDITS.txt ... */
+

+ 1079 - 0
libs/physfs-2.0.3/Doxyfile

@@ -0,0 +1,1079 @@
+# Doxyfile 1.3.4
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = physfs
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
+# This could be handy for archiving the generated documentation or 
+# if some version control system is used.
+# (CMake will set this properly at build time. --ryan.)
+PROJECT_NUMBER         = "unknown version (build with 'make docs' next time!)"
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = docs
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, 
+# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en 
+# (Japanese with English messages), Korean, Norwegian, Polish, Portuguese, 
+# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE        = English
+
+# This tag can be used to specify the encoding used in the generated output. 
+# The encoding is not always determined by the language that is chosen, 
+# but also whether or not the output is meant for Windows or non-Windows users. 
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES 
+# forces the Windows encoding (this is the default for the Windows binary), 
+# whereas setting the tag to NO uses a Unix-style encoding (the default for 
+# all platforms other than Windows).
+
+USE_WINDOWS_ENCODING   = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
+# the brief description of a member or function before the detailed description. 
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited 
+# members of a class in the documentation of that class as if those members were 
+# ordinary class members. Constructors, destructors and assignment operators of 
+# the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user-defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. It is allowed to use relative paths in the argument list.
+
+STRIP_FROM_PATH        = 
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
+# (but less readable) file names. This can be useful is your file systems 
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments will behave just like the Qt-style comments (thus requiring an 
+# explict @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
+# comments) as a brief description. This used to be the default behaviour. 
+# The new default is to treat a multi-line C++ comment block as a detailed 
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen 
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member 
+# documentation.
+
+DETAILS_AT_TOP         = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# reimplements.
+
+INHERIT_DOCS           = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that acts 
+# as commands in the documentation. An alias has the form "name=value". 
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
+# put the command \sideeffect (or @sideeffect) in the documentation, which 
+# will result in a user-defined paragraph with heading "Side Effects:". 
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                = 
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources 
+# only. Doxygen will then generate output that is more tailored for C. 
+# For instance, some of the names that are used will be different. The list 
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources 
+# only. Doxygen will then generate output that is more tailored for Java. 
+# For instance, namespaces will be presented as packages, qualified scopes 
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
+# the same type (for instance a group of public functions) to be put as a 
+# subgroup of that type (e.g. under the Public Functions section). Set it to 
+# NO to prevent subgrouping. Alternatively, this can be done per class using 
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
+# defined locally in source files will be included in the documentation. 
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these classes will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
+# friend (class|struct|union) declarations. 
+# If set to NO (the default) these declarations will be included in the 
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
+# documentation blocks found inside the body of a function. 
+# If set to NO (the default) these blocks will be appended to the 
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
+# file names in lower-case letters. If set to YES upper-case letters are also 
+# allowed. This is useful if you have classes or files whose names only differ 
+# in case and if your file system supports case sensitive file names. Windows 
+# users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put a list of the files that are included by a file in the documentation 
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or 
+# disable (NO) the bug list. This list is created by putting \bug 
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
+# disable (NO) the deprecated list. This list is created by putting 
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = 
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
+# the initial value of a variable or define consists of for it to appear in 
+# the documentation. If the initializer consists of more lines than specified 
+# here it will be hidden. Use a value of 0 to hide initializers completely. 
+# The appearance of the initializer of individual variables and defines in the 
+# documentation can be controlled using \showinitializer or \hideinitializer 
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
+# at the bottom of the documentation of classes and structs. If set to YES the 
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
+# potential errors in the documentation, such as not documenting some 
+# parameters in a documented function, or documenting parameters that 
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning 
+# and error messages should be written. If left blank the output is written 
+# to stderr.
+
+WARN_LOGFILE           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces.
+
+INPUT                  = physfs.h
+
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank the following patterns are tested: 
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp 
+# *.h++ *.idl *.odl *.cs *.php *.php3 *.inc
+
+FILE_PATTERNS          = 
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should 
+# excluded from the INPUT source files. This way you can easily exclude a 
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                = 
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories 
+# that are symbolic links (a Unix filesystem feature) are excluded from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories.
+
+EXCLUDE_PATTERNS       = 
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
+# the \include command).
+
+EXAMPLE_PATH           = 
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = 
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
+# searched for input files to be used with the \include or \dontinclude 
+# commands irrespective of the value of the RECURSIVE tag. 
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
+# the \image command).
+
+IMAGE_PATH             = 
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output.
+
+INPUT_FILTER           = 
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
+# INPUT_FILTER) will be used to filter the input files when producing source 
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default) 
+# then for each documented function all documented 
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default) 
+# then for each documented function all documented entities 
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
+# of all compounds will be generated. Enable this if the project 
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header.
+
+HTML_HEADER            = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+HTML_FOOTER            = 
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If the tag is left blank doxygen 
+# will generate a default style sheet
+
+HTML_STYLESHEET        = 
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) 
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
+# be used to specify the file name of the resulting .chm file. You 
+# can add a path in front of the file if the result should not be 
+# written to the html output dir.
+
+CHM_FILE               = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
+# be used to specify the location (absolute path including file name) of 
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
+# controls if a separate .chi index file is generated (YES) or that 
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
+# controls whether a binary table of contents is generated (YES) or a 
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
+# top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20]) 
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that 
+# is generated for HTML Help). For this to work a browser that supports 
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, 
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are 
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
+# used to set the initial width (in pixels) of the frame in which the tree 
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, a4wide, letter, legal and 
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
+# include the index chapters (such as File Index, Compound Index, etc.) 
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimised for Word 97 and may not look very pretty with 
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using WORD or other 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assigments. You only have to provide 
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    = 
+
+# Set optional variables used in the generation of an rtf document. 
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages
+
+GENERATE_MAN           = YES
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_SCHEMA             = 
+
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_DTD                = 
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see autogen.sf.net) file 
+# that captures the structure of the code including all 
+# documentation. Note that this feature is still experimental 
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
+# generate a Perl module file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
+# nicely formatted so it can be parsed by a human reader.  This is useful 
+# if you want to understand what is going on.  On the other hand, if this 
+# tag is set to NO the size of the Perl module output will be much smaller 
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file 
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
+# This is useful so different doxyrules.make files included by the same 
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX = 
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF     = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor.
+
+INCLUDE_PATH           = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used.
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed.
+
+PREDEFINED             = DOXYGEN_SHOULD_IGNORE_THIS=1 \
+                         __EXPORT__=
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      = 
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all function-like macros that are alone 
+# on a line, have an all uppercase name, and do not end with a semicolon. Such 
+# function macros are typically used for boiler-plate code, and will confuse the 
+# parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references   
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. 
+# Optionally an initial location of the external documentation 
+# can be added for each tagfile. The format of a tag file without 
+# this location is as follows: 
+#   TAGFILES = file1 file2 ... 
+# Adding location for the tag files is done as follows: 
+#   TAGFILES = file1=loc1 "file2 = loc2" ... 
+# where "loc1" and "loc2" can be relative or absolute paths or 
+# URLs. If a location is present for each tag, the installdox tool 
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen 
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               = 
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
+# in the modules index. If set to NO, only the current project's groups will 
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or 
+# super classes. Setting the tag to NO turns the diagrams off. Note that this 
+# option is superceded by the HAVE_DOT option below. This is only a fallback. It is 
+# recommended to install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS         = NO
+
+# If set to YES, the inheritance and collaboration graphs will hide 
+# inheritance and usage relations if the target is undocumented 
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = NO
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = NO
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
+# collaboration diagrams in a style similiar to the OMG's Unified Modeling 
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the 
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
+# tags are set to YES then doxygen will generate a graph for each documented 
+# file showing the direct and indirect include dependencies of the file with 
+# other documented files.
+
+INCLUDE_GRAPH          = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
+# documented header file showing the documented files that directly or 
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will 
+# generate a call dependency graph for every global function or class method. 
+# Note that enabling this option will significantly increase the time of a run. 
+# So in most cases it will be better to enable call graphs for selected 
+# functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# found. If left blank, it is assumed the dot tool can be found on the path.
+
+DOT_PATH               = 
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that 
+# contain dot files that are included in the documentation (see the 
+# \dotfile command).
+
+DOTFILE_DIRS           = 
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images.
+
+MAX_DOT_GRAPH_WIDTH    = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT   = 1024
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
+# graphs generated by dot. A depth value of 3 means that only nodes reachable 
+# from the root by following a path via at most 3 edges will be shown. Nodes that 
+# lay further from the root node will be omitted. Note that setting this option to 
+# 1 or 2 may greatly reduce the computation time needed for large code bases. Also 
+# note that a graph may be further truncated if the graph's image dimensions are 
+# not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). 
+# If 0 is used for the depth value (the default), the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
+# generate a legend page explaining the meaning of the various boxes and 
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
+# remove the intermediate dot files that are used to generate 
+# the various graphs.
+
+DOT_CLEANUP            = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine   
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be 
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = NO

+ 153 - 0
libs/physfs-2.0.3/INSTALL.txt

@@ -0,0 +1,153 @@
+
+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 [email protected].
+
+
+
+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 has not been tested on 64-bit Windows, but probably works. There is
+ no 16-bit Windows support at all. Reports of success and problems can go to
+ Ryan at [email protected] ...
+
+If someone is willing to maintain prebuilt PhysicsFS DLLs, I'd like to hear
+from you; send an email to [email protected] ...
+
+
+
+PocketPC/WindowsCE:
+
+Code exists for PocketPC support, and there are shipping titles that used
+ PhysicsFS 1.0 on PocketPC...but it isn't tested in 2.0, and is probably
+ broken with the new build system. Please send patches.
+
+
+
+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 [email protected].
+
+
+
+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 [email protected].
+
+
+
+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. ([email protected])
+

+ 44 - 0
libs/physfs-2.0.3/LICENSE.txt

@@ -0,0 +1,44 @@
+
+   Copyright (c) 2001-2012 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 <[email protected]>
+
+
+
+
+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...
+
+   zlib: if you enable ZIP archive support, PhysicsFS uses zlib. Its license
+         requirements are identical to PhysicsFS.
+         Please see zlib123/README for details.
+
+   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.
+

+ 45 - 0
libs/physfs-2.0.3/TODO.txt

@@ -0,0 +1,45 @@
+Stuff that needs to be done and wishlist:
+
+These are in no particular order.
+Some might be dupes, some might be done already.
+
+UNICODE:
+- OS/2: Codepages. No full Unicode in the filesystem, but we can probably make
+        a conversion effort.
+
+
+Stuff:
+- 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.
+- Reduce malloc() pressure all over the place. We fragment memory like mad.
+- 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.
+- OSX shouldn't use ~/.app for userdir.
+- fscanf and fprintf support in extras dir.
+- Why do we call it openArchive and dirClose?
+- Sanity check byte order at runtime.
+- Memory locking?
+- Find a better name than dvoid and fvoid.
+- Can windows.c and pocketpc.c get merged?
+- There's so much cut-and-paste between archivers...can this be reduced?
+- General code audit.
+- Multiple write dirs with mount points?
+- Deprecate PHYSFS_setSaneConfig and move it to extras?
+- Why is physfsrwops.c cut-and-pasted into the ruby bindings?
+- Replace code from SDL...
+- Should file enumeration return an error or set error state?
+- Need "getmountpoint" command in test_physfs.c ...
+- Look for calloc() calls that aren't going through the allocation hooks.
+- Write up a simple HOWTO on embedding physicsfs in another project.
+- Archivers need abstracted i/o to read from memory or files (archives in archives?)
+- Probably other stuff. Requests and recommendations are welcome.
+
+// end of TODO.txt ...
+

+ 283 - 0
libs/physfs-2.0.3/archivers/dir.c

@@ -0,0 +1,283 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "physfs.h"
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+static PHYSFS_sint64 DIR_read(fvoid *opaque, void *buffer,
+                              PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    PHYSFS_sint64 retval;
+    retval = __PHYSFS_platformRead(opaque, buffer, objSize, objCount);
+    return(retval);
+} /* DIR_read */
+
+
+static PHYSFS_sint64 DIR_write(fvoid *opaque, const void *buffer,
+                               PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    PHYSFS_sint64 retval;
+    retval = __PHYSFS_platformWrite(opaque, buffer, objSize, objCount);
+    return(retval);
+} /* DIR_write */
+
+
+static int DIR_eof(fvoid *opaque)
+{
+    return(__PHYSFS_platformEOF(opaque));
+} /* DIR_eof */
+
+
+static PHYSFS_sint64 DIR_tell(fvoid *opaque)
+{
+    return(__PHYSFS_platformTell(opaque));
+} /* DIR_tell */
+
+
+static int DIR_seek(fvoid *opaque, PHYSFS_uint64 offset)
+{
+    return(__PHYSFS_platformSeek(opaque, offset));
+} /* DIR_seek */
+
+
+static PHYSFS_sint64 DIR_fileLength(fvoid *opaque)
+{
+    return(__PHYSFS_platformFileLength(opaque));
+} /* DIR_fileLength */
+
+
+static int DIR_fileClose(fvoid *opaque)
+{
+    /*
+     * we manually flush the buffer, since that's the place a close will
+     *  most likely fail, but that will leave the file handle in an undefined
+     *  state if it fails. Flush failures we can recover from.
+     */
+    BAIL_IF_MACRO(!__PHYSFS_platformFlush(opaque), NULL, 0);
+    BAIL_IF_MACRO(!__PHYSFS_platformClose(opaque), NULL, 0);
+    return(1);
+} /* DIR_fileClose */
+
+
+static int DIR_isArchive(const char *filename, int forWriting)
+{
+    /* directories ARE archives in this driver... */
+    return(__PHYSFS_platformIsDirectory(filename));
+} /* DIR_isArchive */
+
+
+static void *DIR_openArchive(const char *name, int forWriting)
+{
+    const char *dirsep = PHYSFS_getDirSeparator();
+    char *retval = NULL;
+    size_t namelen = strlen(name);
+    size_t seplen = strlen(dirsep);
+
+    /* !!! FIXME: when is this not called right before openArchive? */
+    BAIL_IF_MACRO(!DIR_isArchive(name, forWriting),
+                    ERR_UNSUPPORTED_ARCHIVE, 0);
+
+    retval = allocator.Malloc(namelen + seplen + 1);
+    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+        /* make sure there's a dir separator at the end of the string */
+    strcpy(retval, name);
+    if (strcmp((name + namelen) - seplen, dirsep) != 0)
+        strcat(retval, dirsep);
+
+    return(retval);
+} /* DIR_openArchive */
+
+
+static void DIR_enumerateFiles(dvoid *opaque, const char *dname,
+                               int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+                               const char *origdir, void *callbackdata)
+{
+    char *d = __PHYSFS_platformCvtToDependent((char *)opaque, dname, NULL);
+    if (d != NULL)
+    {
+        __PHYSFS_platformEnumerateFiles(d, omitSymLinks, cb,
+                                        origdir, callbackdata);
+        allocator.Free(d);
+    } /* if */
+} /* DIR_enumerateFiles */
+
+
+static int DIR_exists(dvoid *opaque, const char *name)
+{
+    char *f = __PHYSFS_platformCvtToDependent((char *) opaque, name, NULL);
+    int retval;
+
+    BAIL_IF_MACRO(f == NULL, NULL, 0);
+    retval = __PHYSFS_platformExists(f);
+    allocator.Free(f);
+    return(retval);
+} /* DIR_exists */
+
+
+static int DIR_isDirectory(dvoid *opaque, const char *name, int *fileExists)
+{
+    char *d = __PHYSFS_platformCvtToDependent((char *) opaque, name, NULL);
+    int retval = 0;
+
+    BAIL_IF_MACRO(d == NULL, NULL, 0);
+    *fileExists = __PHYSFS_platformExists(d);
+    if (*fileExists)
+        retval = __PHYSFS_platformIsDirectory(d);
+    allocator.Free(d);
+    return(retval);
+} /* DIR_isDirectory */
+
+
+static int DIR_isSymLink(dvoid *opaque, const char *name, int *fileExists)
+{
+    char *f = __PHYSFS_platformCvtToDependent((char *) opaque, name, NULL);
+    int retval = 0;
+
+    BAIL_IF_MACRO(f == NULL, NULL, 0);
+    *fileExists = __PHYSFS_platformExists(f);
+    if (*fileExists)
+        retval = __PHYSFS_platformIsSymLink(f);
+    allocator.Free(f);
+    return(retval);
+} /* DIR_isSymLink */
+
+
+static PHYSFS_sint64 DIR_getLastModTime(dvoid *opaque,
+                                        const char *name,
+                                        int *fileExists)
+{
+    char *d = __PHYSFS_platformCvtToDependent((char *) opaque, name, NULL);
+    PHYSFS_sint64 retval = -1;
+
+    BAIL_IF_MACRO(d == NULL, NULL, 0);
+    *fileExists = __PHYSFS_platformExists(d);
+    if (*fileExists)
+        retval = __PHYSFS_platformGetLastModTime(d);
+    allocator.Free(d);
+    return(retval);
+} /* DIR_getLastModTime */
+
+
+static fvoid *doOpen(dvoid *opaque, const char *name,
+                     void *(*openFunc)(const char *filename),
+                     int *fileExists)
+{
+    char *f = __PHYSFS_platformCvtToDependent((char *) opaque, name, NULL);
+    void *rc = NULL;
+
+    BAIL_IF_MACRO(f == NULL, NULL, NULL);
+
+    if (fileExists != NULL)
+    {
+        *fileExists = __PHYSFS_platformExists(f);
+        if (!(*fileExists))
+        {
+            allocator.Free(f);
+            return(NULL);
+        } /* if */
+    } /* if */
+
+    rc = openFunc(f);
+    allocator.Free(f);
+
+    return((fvoid *) rc);
+} /* doOpen */
+
+
+static fvoid *DIR_openRead(dvoid *opaque, const char *fnm, int *exist)
+{
+    return(doOpen(opaque, fnm, __PHYSFS_platformOpenRead, exist));
+} /* DIR_openRead */
+
+
+static fvoid *DIR_openWrite(dvoid *opaque, const char *filename)
+{
+    return(doOpen(opaque, filename, __PHYSFS_platformOpenWrite, NULL));
+} /* DIR_openWrite */
+
+
+static fvoid *DIR_openAppend(dvoid *opaque, const char *filename)
+{
+    return(doOpen(opaque, filename, __PHYSFS_platformOpenAppend, NULL));
+} /* DIR_openAppend */
+
+
+static int DIR_remove(dvoid *opaque, const char *name)
+{
+    char *f = __PHYSFS_platformCvtToDependent((char *) opaque, name, NULL);
+    int retval;
+
+    BAIL_IF_MACRO(f == NULL, NULL, 0);
+    retval = __PHYSFS_platformDelete(f);
+    allocator.Free(f);
+    return(retval);
+} /* DIR_remove */
+
+
+static int DIR_mkdir(dvoid *opaque, const char *name)
+{
+    char *f = __PHYSFS_platformCvtToDependent((char *) opaque, name, NULL);
+    int retval;
+
+    BAIL_IF_MACRO(f == NULL, NULL, 0);
+    retval = __PHYSFS_platformMkDir(f);
+    allocator.Free(f);
+    return(retval);
+} /* DIR_mkdir */
+
+
+static void DIR_dirClose(dvoid *opaque)
+{
+    allocator.Free(opaque);
+} /* DIR_dirClose */
+
+
+
+const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_DIR =
+{
+    "",
+    DIR_ARCHIVE_DESCRIPTION,
+    "Ryan C. Gordon <[email protected]>",
+    "http://icculus.org/physfs/",
+};
+
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_DIR =
+{
+    &__PHYSFS_ArchiveInfo_DIR,
+    DIR_isArchive,          /* isArchive() method      */
+    DIR_openArchive,        /* openArchive() method    */
+    DIR_enumerateFiles,     /* enumerateFiles() method */
+    DIR_exists,             /* exists() method         */
+    DIR_isDirectory,        /* isDirectory() method    */
+    DIR_isSymLink,          /* isSymLink() method      */
+    DIR_getLastModTime,     /* getLastModTime() method */
+    DIR_openRead,           /* openRead() method       */
+    DIR_openWrite,          /* openWrite() method      */
+    DIR_openAppend,         /* openAppend() method     */
+    DIR_remove,             /* remove() method         */
+    DIR_mkdir,              /* mkdir() method          */
+    DIR_dirClose,           /* dirClose() method       */
+    DIR_read,               /* read() method           */
+    DIR_write,              /* write() method          */
+    DIR_eof,                /* eof() method            */
+    DIR_tell,               /* tell() method           */
+    DIR_seek,               /* seek() method           */
+    DIR_fileLength,         /* fileLength() method     */
+    DIR_fileClose           /* fileClose() method      */
+};
+
+/* end of dir.c ... */
+

+ 475 - 0
libs/physfs-2.0.3/archivers/grp.c

@@ -0,0 +1,475 @@
+/*
+ * 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.
+ */
+
+#if (defined PHYSFS_SUPPORTS_GRP)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "physfs.h"
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+typedef struct
+{
+    char name[13];
+    PHYSFS_uint32 startPos;
+    PHYSFS_uint32 size;
+} GRPentry;
+
+typedef struct
+{
+    char *filename;
+    PHYSFS_sint64 last_mod_time;
+    PHYSFS_uint32 entryCount;
+    GRPentry *entries;
+} GRPinfo;
+
+typedef struct
+{
+    void *handle;
+    GRPentry *entry;
+    PHYSFS_uint32 curPos;
+} GRPfileinfo;
+
+
+static void GRP_dirClose(dvoid *opaque)
+{
+    GRPinfo *info = ((GRPinfo *) opaque);
+    allocator.Free(info->filename);
+    allocator.Free(info->entries);
+    allocator.Free(info);
+} /* GRP_dirClose */
+
+
+static PHYSFS_sint64 GRP_read(fvoid *opaque, void *buffer,
+                              PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    GRPfileinfo *finfo = (GRPfileinfo *) opaque;
+    GRPentry *entry = finfo->entry;
+    PHYSFS_uint32 bytesLeft = entry->size - finfo->curPos;
+    PHYSFS_uint32 objsLeft = (bytesLeft / objSize);
+    PHYSFS_sint64 rc;
+
+    if (objsLeft < objCount)
+        objCount = objsLeft;
+
+    rc = __PHYSFS_platformRead(finfo->handle, buffer, objSize, objCount);
+    if (rc > 0)
+        finfo->curPos += (PHYSFS_uint32) (rc * objSize);
+
+    return(rc);
+} /* GRP_read */
+
+
+static PHYSFS_sint64 GRP_write(fvoid *opaque, const void *buffer,
+                               PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
+} /* GRP_write */
+
+
+static int GRP_eof(fvoid *opaque)
+{
+    GRPfileinfo *finfo = (GRPfileinfo *) opaque;
+    GRPentry *entry = finfo->entry;
+    return(finfo->curPos >= entry->size);
+} /* GRP_eof */
+
+
+static PHYSFS_sint64 GRP_tell(fvoid *opaque)
+{
+    return(((GRPfileinfo *) opaque)->curPos);
+} /* GRP_tell */
+
+
+static int GRP_seek(fvoid *opaque, PHYSFS_uint64 offset)
+{
+    GRPfileinfo *finfo = (GRPfileinfo *) opaque;
+    GRPentry *entry = finfo->entry;
+    int rc;
+
+    BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
+    BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
+    rc = __PHYSFS_platformSeek(finfo->handle, entry->startPos + offset);
+    if (rc)
+        finfo->curPos = (PHYSFS_uint32) offset;
+
+    return(rc);
+} /* GRP_seek */
+
+
+static PHYSFS_sint64 GRP_fileLength(fvoid *opaque)
+{
+    GRPfileinfo *finfo = (GRPfileinfo *) opaque;
+    return((PHYSFS_sint64) finfo->entry->size);
+} /* GRP_fileLength */
+
+
+static int GRP_fileClose(fvoid *opaque)
+{
+    GRPfileinfo *finfo = (GRPfileinfo *) opaque;
+    BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0);
+    allocator.Free(finfo);
+    return(1);
+} /* GRP_fileClose */
+
+
+static int grp_open(const char *filename, int forWriting,
+                    void **fh, PHYSFS_uint32 *count)
+{
+    PHYSFS_uint8 buf[12];
+
+    *fh = NULL;
+    BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
+
+    *fh = __PHYSFS_platformOpenRead(filename);
+    BAIL_IF_MACRO(*fh == NULL, NULL, 0);
+    
+    if (__PHYSFS_platformRead(*fh, buf, 12, 1) != 1)
+        goto openGrp_failed;
+
+    if (memcmp(buf, "KenSilverman", 12) != 0)
+    {
+        __PHYSFS_setError(ERR_UNSUPPORTED_ARCHIVE);
+        goto openGrp_failed;
+    } /* if */
+
+    if (__PHYSFS_platformRead(*fh, count, sizeof (PHYSFS_uint32), 1) != 1)
+        goto openGrp_failed;
+
+    *count = PHYSFS_swapULE32(*count);
+
+    return(1);
+
+openGrp_failed:
+    if (*fh != NULL)
+        __PHYSFS_platformClose(*fh);
+
+    *count = -1;
+    *fh = NULL;
+    return(0);
+} /* grp_open */
+
+
+static int GRP_isArchive(const char *filename, int forWriting)
+{
+    void *fh;
+    PHYSFS_uint32 fileCount;
+    int retval = grp_open(filename, forWriting, &fh, &fileCount);
+
+    if (fh != NULL)
+        __PHYSFS_platformClose(fh);
+
+    return(retval);
+} /* GRP_isArchive */
+
+
+static int grp_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
+{
+    if (one != two)
+    {
+        const GRPentry *a = (const GRPentry *) _a;
+        return(strcmp(a[one].name, a[two].name));
+    } /* if */
+
+    return 0;
+} /* grp_entry_cmp */
+
+
+static void grp_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
+{
+    if (one != two)
+    {
+        GRPentry tmp;
+        GRPentry *first = &(((GRPentry *) _a)[one]);
+        GRPentry *second = &(((GRPentry *) _a)[two]);
+        memcpy(&tmp, first, sizeof (GRPentry));
+        memcpy(first, second, sizeof (GRPentry));
+        memcpy(second, &tmp, sizeof (GRPentry));
+    } /* if */
+} /* grp_entry_swap */
+
+
+static int grp_load_entries(const char *name, int forWriting, GRPinfo *info)
+{
+    void *fh = NULL;
+    PHYSFS_uint32 fileCount;
+    PHYSFS_uint32 location = 16;  /* sizeof sig. */
+    GRPentry *entry;
+    char *ptr;
+
+    BAIL_IF_MACRO(!grp_open(name, forWriting, &fh, &fileCount), NULL, 0);
+    info->entryCount = fileCount;
+    info->entries = (GRPentry *) allocator.Malloc(sizeof(GRPentry)*fileCount);
+    if (info->entries == NULL)
+    {
+        __PHYSFS_platformClose(fh);
+        BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
+    } /* if */
+
+    location += (16 * fileCount);
+
+    for (entry = info->entries; fileCount > 0; fileCount--, entry++)
+    {
+        if (__PHYSFS_platformRead(fh, &entry->name, 12, 1) != 1)
+        {
+            __PHYSFS_platformClose(fh);
+            return(0);
+        } /* if */
+
+        entry->name[12] = '\0';  /* name isn't null-terminated in file. */
+        if ((ptr = strchr(entry->name, ' ')) != NULL)
+            *ptr = '\0';  /* trim extra spaces. */
+
+        if (__PHYSFS_platformRead(fh, &entry->size, 4, 1) != 1)
+        {
+            __PHYSFS_platformClose(fh);
+            return(0);
+        } /* if */
+
+        entry->size = PHYSFS_swapULE32(entry->size);
+        entry->startPos = location;
+        location += entry->size;
+    } /* for */
+
+    __PHYSFS_platformClose(fh);
+
+    __PHYSFS_sort(info->entries, info->entryCount,
+                  grp_entry_cmp, grp_entry_swap);
+    return(1);
+} /* grp_load_entries */
+
+
+static void *GRP_openArchive(const char *name, int forWriting)
+{
+    PHYSFS_sint64 modtime = __PHYSFS_platformGetLastModTime(name);
+    GRPinfo *info = (GRPinfo *) allocator.Malloc(sizeof (GRPinfo));
+
+    BAIL_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, 0);
+
+    memset(info, '\0', sizeof (GRPinfo));
+    info->filename = (char *) allocator.Malloc(strlen(name) + 1);
+    GOTO_IF_MACRO(!info->filename, ERR_OUT_OF_MEMORY, GRP_openArchive_failed);
+
+    if (!grp_load_entries(name, forWriting, info))
+        goto GRP_openArchive_failed;
+
+    strcpy(info->filename, name);
+    info->last_mod_time = modtime;
+
+    return(info);
+
+GRP_openArchive_failed:
+    if (info != NULL)
+    {
+        if (info->filename != NULL)
+            allocator.Free(info->filename);
+        if (info->entries != NULL)
+            allocator.Free(info->entries);
+        allocator.Free(info);
+    } /* if */
+
+    return(NULL);
+} /* GRP_openArchive */
+
+
+static void GRP_enumerateFiles(dvoid *opaque, const char *dname,
+                               int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+                               const char *origdir, void *callbackdata)
+{
+    /* no directories in GRP files. */
+    if (*dname == '\0')
+    {
+        GRPinfo *info = (GRPinfo *) opaque;
+        GRPentry *entry = info->entries;
+        PHYSFS_uint32 max = info->entryCount;
+        PHYSFS_uint32 i;
+
+        for (i = 0; i < max; i++, entry++)
+            cb(callbackdata, origdir, entry->name);
+    } /* if */
+} /* GRP_enumerateFiles */
+
+
+static GRPentry *grp_find_entry(GRPinfo *info, const char *name)
+{
+    char *ptr = strchr(name, '.');
+    GRPentry *a = info->entries;
+    PHYSFS_sint32 lo = 0;
+    PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
+    PHYSFS_sint32 middle;
+    int rc;
+
+    /*
+     * Rule out filenames to avoid unneeded processing...no dirs,
+     *   big filenames, or extensions > 3 chars.
+     */
+    BAIL_IF_MACRO((ptr) && (strlen(ptr) > 4), ERR_NO_SUCH_FILE, NULL);
+    BAIL_IF_MACRO(strlen(name) > 12, ERR_NO_SUCH_FILE, NULL);
+    BAIL_IF_MACRO(strchr(name, '/') != NULL, ERR_NO_SUCH_FILE, NULL);
+
+    while (lo <= hi)
+    {
+        middle = lo + ((hi - lo) / 2);
+        rc = strcmp(name, a[middle].name);
+        if (rc == 0)  /* found it! */
+            return(&a[middle]);
+        else if (rc > 0)
+            lo = middle + 1;
+        else
+            hi = middle - 1;
+    } /* while */
+
+    BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
+} /* grp_find_entry */
+
+
+static int GRP_exists(dvoid *opaque, const char *name)
+{
+    return(grp_find_entry((GRPinfo *) opaque, name) != NULL);
+} /* GRP_exists */
+
+
+static int GRP_isDirectory(dvoid *opaque, const char *name, int *fileExists)
+{
+    *fileExists = GRP_exists(opaque, name);
+    return(0);  /* never directories in a groupfile. */
+} /* GRP_isDirectory */
+
+
+static int GRP_isSymLink(dvoid *opaque, const char *name, int *fileExists)
+{
+    *fileExists = GRP_exists(opaque, name);
+    return(0);  /* never symlinks in a groupfile. */
+} /* GRP_isSymLink */
+
+
+static PHYSFS_sint64 GRP_getLastModTime(dvoid *opaque,
+                                        const char *name,
+                                        int *fileExists)
+{
+    GRPinfo *info = (GRPinfo *) opaque;
+    PHYSFS_sint64 retval = -1;
+
+    *fileExists = (grp_find_entry(info, name) != NULL);
+    if (*fileExists)  /* use time of GRP itself in the physical filesystem. */
+        retval = info->last_mod_time;
+
+    return(retval);
+} /* GRP_getLastModTime */
+
+
+static fvoid *GRP_openRead(dvoid *opaque, const char *fnm, int *fileExists)
+{
+    GRPinfo *info = (GRPinfo *) opaque;
+    GRPfileinfo *finfo;
+    GRPentry *entry;
+
+    entry = grp_find_entry(info, fnm);
+    *fileExists = (entry != NULL);
+    BAIL_IF_MACRO(entry == NULL, NULL, NULL);
+
+    finfo = (GRPfileinfo *) allocator.Malloc(sizeof (GRPfileinfo));
+    BAIL_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+    finfo->handle = __PHYSFS_platformOpenRead(info->filename);
+    if ( (finfo->handle == NULL) ||
+         (!__PHYSFS_platformSeek(finfo->handle, entry->startPos)) )
+    {
+        allocator.Free(finfo);
+        return(NULL);
+    } /* if */
+
+    finfo->curPos = 0;
+    finfo->entry = entry;
+    return(finfo);
+} /* GRP_openRead */
+
+
+static fvoid *GRP_openWrite(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* GRP_openWrite */
+
+
+static fvoid *GRP_openAppend(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* GRP_openAppend */
+
+
+static int GRP_remove(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* GRP_remove */
+
+
+static int GRP_mkdir(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* GRP_mkdir */
+
+
+const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_GRP =
+{
+    "GRP",
+    GRP_ARCHIVE_DESCRIPTION,
+    "Ryan C. Gordon <[email protected]>",
+    "http://icculus.org/physfs/",
+};
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_GRP =
+{
+    &__PHYSFS_ArchiveInfo_GRP,
+    GRP_isArchive,          /* isArchive() method      */
+    GRP_openArchive,        /* openArchive() method    */
+    GRP_enumerateFiles,     /* enumerateFiles() method */
+    GRP_exists,             /* exists() method         */
+    GRP_isDirectory,        /* isDirectory() method    */
+    GRP_isSymLink,          /* isSymLink() method      */
+    GRP_getLastModTime,     /* getLastModTime() method */
+    GRP_openRead,           /* openRead() method       */
+    GRP_openWrite,          /* openWrite() method      */
+    GRP_openAppend,         /* openAppend() method     */
+    GRP_remove,             /* remove() method         */
+    GRP_mkdir,              /* mkdir() method          */
+    GRP_dirClose,           /* dirClose() method       */
+    GRP_read,               /* read() method           */
+    GRP_write,              /* write() method          */
+    GRP_eof,                /* eof() method            */
+    GRP_tell,               /* tell() method           */
+    GRP_seek,               /* seek() method           */
+    GRP_fileLength,         /* fileLength() method     */
+    GRP_fileClose           /* fileClose() method      */
+};
+
+#endif  /* defined PHYSFS_SUPPORTS_GRP */
+
+/* end of grp.c ... */
+

+ 514 - 0
libs/physfs-2.0.3/archivers/hog.c

@@ -0,0 +1,514 @@
+/*
+ * 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.
+ */
+
+#if (defined PHYSFS_SUPPORTS_HOG)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "physfs.h"
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+/*
+ * One HOGentry is kept for each file in an open HOG archive.
+ */
+typedef struct
+{
+    char name[13];
+    PHYSFS_uint32 startPos;
+    PHYSFS_uint32 size;
+} HOGentry;
+
+/*
+ * One HOGinfo is kept for each open HOG archive.
+ */
+typedef struct
+{
+    char *filename;
+    PHYSFS_sint64 last_mod_time;
+    PHYSFS_uint32 entryCount;
+    HOGentry *entries;
+} HOGinfo;
+
+/*
+ * One HOGfileinfo is kept for each open file in a HOG archive.
+ */
+typedef struct
+{
+    void *handle;
+    HOGentry *entry;
+    PHYSFS_uint32 curPos;
+} HOGfileinfo;
+
+
+static void HOG_dirClose(dvoid *opaque)
+{
+    HOGinfo *info = ((HOGinfo *) opaque);
+    allocator.Free(info->filename);
+    allocator.Free(info->entries);
+    allocator.Free(info);
+} /* HOG_dirClose */
+
+
+static PHYSFS_sint64 HOG_read(fvoid *opaque, void *buffer,
+                              PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    HOGfileinfo *finfo = (HOGfileinfo *) opaque;
+    HOGentry *entry = finfo->entry;
+    PHYSFS_uint32 bytesLeft = entry->size - finfo->curPos;
+    PHYSFS_uint32 objsLeft = (bytesLeft / objSize);
+    PHYSFS_sint64 rc;
+
+    if (objsLeft < objCount)
+        objCount = objsLeft;
+
+    rc = __PHYSFS_platformRead(finfo->handle, buffer, objSize, objCount);
+    if (rc > 0)
+        finfo->curPos += (PHYSFS_uint32) (rc * objSize);
+
+    return(rc);
+} /* HOG_read */
+
+
+static PHYSFS_sint64 HOG_write(fvoid *opaque, const void *buffer,
+                               PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
+} /* HOG_write */
+
+
+static int HOG_eof(fvoid *opaque)
+{
+    HOGfileinfo *finfo = (HOGfileinfo *) opaque;
+    HOGentry *entry = finfo->entry;
+    return(finfo->curPos >= entry->size);
+} /* HOG_eof */
+
+
+static PHYSFS_sint64 HOG_tell(fvoid *opaque)
+{
+    return(((HOGfileinfo *) opaque)->curPos);
+} /* HOG_tell */
+
+
+static int HOG_seek(fvoid *opaque, PHYSFS_uint64 offset)
+{
+    HOGfileinfo *finfo = (HOGfileinfo *) opaque;
+    HOGentry *entry = finfo->entry;
+    int rc;
+
+    BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
+    BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
+    rc = __PHYSFS_platformSeek(finfo->handle, entry->startPos + offset);
+    if (rc)
+        finfo->curPos = (PHYSFS_uint32) offset;
+
+    return(rc);
+} /* HOG_seek */
+
+
+static PHYSFS_sint64 HOG_fileLength(fvoid *opaque)
+{
+    HOGfileinfo *finfo = (HOGfileinfo *) opaque;
+    return((PHYSFS_sint64) finfo->entry->size);
+} /* HOG_fileLength */
+
+
+static int HOG_fileClose(fvoid *opaque)
+{
+    HOGfileinfo *finfo = (HOGfileinfo *) opaque;
+    BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0);
+    allocator.Free(finfo);
+    return(1);
+} /* HOG_fileClose */
+
+
+static int hog_open(const char *filename, int forWriting,
+                    void **fh, PHYSFS_uint32 *count)
+{
+    PHYSFS_uint8 buf[13];
+    PHYSFS_uint32 size;
+    PHYSFS_sint64 pos;
+
+    *count = 0;
+
+    *fh = NULL;
+    BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
+
+    *fh = __PHYSFS_platformOpenRead(filename);
+    BAIL_IF_MACRO(*fh == NULL, NULL, 0);
+
+    if (__PHYSFS_platformRead(*fh, buf, 3, 1) != 1)
+        goto openHog_failed;
+
+    if (memcmp(buf, "DHF", 3) != 0)
+    {
+        __PHYSFS_setError(ERR_UNSUPPORTED_ARCHIVE);
+        goto openHog_failed;
+    } /* if */
+
+    while (1)
+    {
+        if (__PHYSFS_platformRead(*fh, buf, 13, 1) != 1)
+            break; /* eof here is ok */
+
+        if (__PHYSFS_platformRead(*fh, &size, 4, 1) != 1)
+            goto openHog_failed;
+
+        size = PHYSFS_swapULE32(size);
+
+        (*count)++;
+
+        /* Skip over entry... */
+        pos = __PHYSFS_platformTell(*fh);
+        if (pos == -1)
+            goto openHog_failed;
+        if (!__PHYSFS_platformSeek(*fh, pos + size))
+            goto openHog_failed;
+    } /* while */
+
+    /* Rewind to start of entries... */
+    if (!__PHYSFS_platformSeek(*fh, 3))
+        goto openHog_failed;
+
+    return(1);
+
+openHog_failed:
+    if (*fh != NULL)
+        __PHYSFS_platformClose(*fh);
+
+    *count = -1;
+    *fh = NULL;
+    return(0);
+} /* hog_open */
+
+
+static int HOG_isArchive(const char *filename, int forWriting)
+{
+    void *fh;
+    PHYSFS_uint32 fileCount;
+    int retval = hog_open(filename, forWriting, &fh, &fileCount);
+
+    if (fh != NULL)
+        __PHYSFS_platformClose(fh);
+
+    return(retval);
+} /* HOG_isArchive */
+
+
+static int hog_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
+{
+    if (one != two)
+    {
+        const HOGentry *a = (const HOGentry *) _a;
+        return(__PHYSFS_stricmpASCII(a[one].name, a[two].name));
+    } /* if */
+
+    return 0;
+} /* hog_entry_cmp */
+
+
+static void hog_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
+{
+    if (one != two)
+    {
+        HOGentry tmp;
+        HOGentry *first = &(((HOGentry *) _a)[one]);
+        HOGentry *second = &(((HOGentry *) _a)[two]);
+        memcpy(&tmp, first, sizeof (HOGentry));
+        memcpy(first, second, sizeof (HOGentry));
+        memcpy(second, &tmp, sizeof (HOGentry));
+    } /* if */
+} /* hog_entry_swap */
+
+
+static int hog_load_entries(const char *name, int forWriting, HOGinfo *info)
+{
+    void *fh = NULL;
+    PHYSFS_uint32 fileCount;
+    HOGentry *entry;
+
+    BAIL_IF_MACRO(!hog_open(name, forWriting, &fh, &fileCount), NULL, 0);
+    info->entryCount = fileCount;
+    info->entries = (HOGentry *) allocator.Malloc(sizeof(HOGentry)*fileCount);
+    if (info->entries == NULL)
+    {
+        __PHYSFS_platformClose(fh);
+        BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
+    } /* if */
+
+    for (entry = info->entries; fileCount > 0; fileCount--, entry++)
+    {
+        if (__PHYSFS_platformRead(fh, &entry->name, 13, 1) != 1)
+        {
+            __PHYSFS_platformClose(fh);
+            return(0);
+        } /* if */
+
+        if (__PHYSFS_platformRead(fh, &entry->size, 4, 1) != 1)
+        {
+            __PHYSFS_platformClose(fh);
+            return(0);
+        } /* if */
+
+        entry->size = PHYSFS_swapULE32(entry->size);
+        entry->startPos = (unsigned int) __PHYSFS_platformTell(fh);
+        if (entry->startPos == -1)
+        {
+            __PHYSFS_platformClose(fh);
+            return(0);
+        }
+
+        /* Skip over entry */
+        if (!__PHYSFS_platformSeek(fh, entry->startPos + entry->size))
+        {
+            __PHYSFS_platformClose(fh);
+            return(0);
+        }
+    } /* for */
+
+    __PHYSFS_platformClose(fh);
+
+    __PHYSFS_sort(info->entries, info->entryCount,
+                  hog_entry_cmp, hog_entry_swap);
+    return(1);
+} /* hog_load_entries */
+
+
+static void *HOG_openArchive(const char *name, int forWriting)
+{
+    PHYSFS_sint64 modtime = __PHYSFS_platformGetLastModTime(name);
+    HOGinfo *info = (HOGinfo *) allocator.Malloc(sizeof (HOGinfo));
+
+    BAIL_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, 0);
+    memset(info, '\0', sizeof (HOGinfo));
+    info->filename = (char *) allocator.Malloc(strlen(name) + 1);
+    GOTO_IF_MACRO(!info->filename, ERR_OUT_OF_MEMORY, HOG_openArchive_failed);
+
+    if (!hog_load_entries(name, forWriting, info))
+        goto HOG_openArchive_failed;
+
+    strcpy(info->filename, name);
+    info->last_mod_time = modtime;
+
+    return(info);
+
+HOG_openArchive_failed:
+    if (info != NULL)
+    {
+        if (info->filename != NULL)
+            allocator.Free(info->filename);
+        if (info->entries != NULL)
+            allocator.Free(info->entries);
+        allocator.Free(info);
+    } /* if */
+
+    return(NULL);
+} /* HOG_openArchive */
+
+
+static void HOG_enumerateFiles(dvoid *opaque, const char *dname,
+                               int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+                               const char *origdir, void *callbackdata)
+{
+    /* no directories in HOG files. */
+    if (*dname == '\0')
+    {
+        HOGinfo *info = (HOGinfo *) opaque;
+        HOGentry *entry = info->entries;
+        PHYSFS_uint32 max = info->entryCount;
+        PHYSFS_uint32 i;
+
+        for (i = 0; i < max; i++, entry++)
+            cb(callbackdata, origdir, entry->name);
+    } /* if */
+} /* HOG_enumerateFiles */
+
+
+static HOGentry *hog_find_entry(HOGinfo *info, const char *name)
+{
+    char *ptr = strchr(name, '.');
+    HOGentry *a = info->entries;
+    PHYSFS_sint32 lo = 0;
+    PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
+    PHYSFS_sint32 middle;
+    int rc;
+
+    /*
+     * Rule out filenames to avoid unneeded processing...no dirs,
+     *   big filenames, or extensions > 3 chars.
+     */
+    BAIL_IF_MACRO((ptr) && (strlen(ptr) > 4), ERR_NO_SUCH_FILE, NULL);
+    BAIL_IF_MACRO(strlen(name) > 12, ERR_NO_SUCH_FILE, NULL);
+    BAIL_IF_MACRO(strchr(name, '/') != NULL, ERR_NO_SUCH_FILE, NULL);
+
+    while (lo <= hi)
+    {
+        middle = lo + ((hi - lo) / 2);
+        rc = __PHYSFS_stricmpASCII(name, a[middle].name);
+        if (rc == 0)  /* found it! */
+            return(&a[middle]);
+        else if (rc > 0)
+            lo = middle + 1;
+        else
+            hi = middle - 1;
+    } /* while */
+
+    BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
+} /* hog_find_entry */
+
+
+static int HOG_exists(dvoid *opaque, const char *name)
+{
+    return(hog_find_entry(((HOGinfo *) opaque), name) != NULL);
+} /* HOG_exists */
+
+
+static int HOG_isDirectory(dvoid *opaque, const char *name, int *fileExists)
+{
+    *fileExists = HOG_exists(opaque, name);
+    return(0);  /* never directories in a groupfile. */
+} /* HOG_isDirectory */
+
+
+static int HOG_isSymLink(dvoid *opaque, const char *name, int *fileExists)
+{
+    *fileExists = HOG_exists(opaque, name);
+    return(0);  /* never symlinks in a groupfile. */
+} /* HOG_isSymLink */
+
+
+static PHYSFS_sint64 HOG_getLastModTime(dvoid *opaque,
+                                        const char *name,
+                                        int *fileExists)
+{
+    HOGinfo *info = ((HOGinfo *) opaque);
+    PHYSFS_sint64 retval = -1;
+
+    *fileExists = (hog_find_entry(info, name) != NULL);
+    if (*fileExists)  /* use time of HOG itself in the physical filesystem. */
+        retval = info->last_mod_time;
+
+    return(retval);
+} /* HOG_getLastModTime */
+
+
+static fvoid *HOG_openRead(dvoid *opaque, const char *fnm, int *fileExists)
+{
+    HOGinfo *info = ((HOGinfo *) opaque);
+    HOGfileinfo *finfo;
+    HOGentry *entry;
+
+    entry = hog_find_entry(info, fnm);
+    *fileExists = (entry != NULL);
+    BAIL_IF_MACRO(entry == NULL, NULL, NULL);
+
+    finfo = (HOGfileinfo *) allocator.Malloc(sizeof (HOGfileinfo));
+    BAIL_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+    finfo->handle = __PHYSFS_platformOpenRead(info->filename);
+    if ( (finfo->handle == NULL) ||
+         (!__PHYSFS_platformSeek(finfo->handle, entry->startPos)) )
+    {
+        allocator.Free(finfo);
+        return(NULL);
+    } /* if */
+
+    finfo->curPos = 0;
+    finfo->entry = entry;
+    return(finfo);
+} /* HOG_openRead */
+
+
+static fvoid *HOG_openWrite(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* HOG_openWrite */
+
+
+static fvoid *HOG_openAppend(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* HOG_openAppend */
+
+
+static int HOG_remove(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* HOG_remove */
+
+
+static int HOG_mkdir(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* HOG_mkdir */
+
+
+const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_HOG =
+{
+    "HOG",
+    HOG_ARCHIVE_DESCRIPTION,
+    "Bradley Bell <[email protected]>",
+    "http://icculus.org/physfs/",
+};
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_HOG =
+{
+    &__PHYSFS_ArchiveInfo_HOG,
+    HOG_isArchive,          /* isArchive() method      */
+    HOG_openArchive,        /* openArchive() method    */
+    HOG_enumerateFiles,     /* enumerateFiles() method */
+    HOG_exists,             /* exists() method         */
+    HOG_isDirectory,        /* isDirectory() method    */
+    HOG_isSymLink,          /* isSymLink() method      */
+    HOG_getLastModTime,     /* getLastModTime() method */
+    HOG_openRead,           /* openRead() method       */
+    HOG_openWrite,          /* openWrite() method      */
+    HOG_openAppend,         /* openAppend() method     */
+    HOG_remove,             /* remove() method         */
+    HOG_mkdir,              /* mkdir() method          */
+    HOG_dirClose,           /* dirClose() method       */
+    HOG_read,               /* read() method           */
+    HOG_write,              /* write() method          */
+    HOG_eof,                /* eof() method            */
+    HOG_tell,               /* tell() method           */
+    HOG_seek,               /* seek() method           */
+    HOG_fileLength,         /* fileLength() method     */
+    HOG_fileClose           /* fileClose() method      */
+};
+
+#endif  /* defined PHYSFS_SUPPORTS_HOG */
+
+/* end of hog.c ... */
+

+ 736 - 0
libs/physfs-2.0.3/archivers/lzma.c

@@ -0,0 +1,736 @@
+/*
+ * 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.
+ */
+
+#if (defined PHYSFS_SUPPORTS_7Z)
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "physfs.h"
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+#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 */
+    void *file; /* 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 = __PHYSFS_platformRead(s->file, s->buffer, 1, 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! */
+    size_t processedSizeLoc = __PHYSFS_platformRead(s->file, buffer, 1, size);
+    if (processedSize != 0)
+        *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 (__PHYSFS_platformSeek(s->file, (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, PHYSFS_uint32 one, PHYSFS_uint32 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, PHYSFS_uint32 one, PHYSFS_uint32 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(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, ERR_NO_SUCH_FILE, 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, numFiles, lzma_file_cmp, lzma_file_swap);
+
+    return(1);
+} /* lzma_load_files */
+
+
+/*
+ * Initialise specified archive
+ */
+static void lzma_archive_init(LZMAarchive *archive)
+{
+    memset(archive, 0, sizeof(*archive));
+
+    /* Prepare callbacks for 7z */
+    archive->stream.inStream.Read = SzFileReadImp;
+    archive->stream.inStream.Seek = SzFileSeekImp;
+
+    archive->stream.allocImp.Alloc = SzAllocPhysicsFS;
+    archive->stream.allocImp.Free = SzFreePhysicsFS;
+
+    archive->stream.allocTempImp.Alloc = SzAllocPhysicsFS;
+    archive->stream.allocTempImp.Free = SzFreePhysicsFS;
+}
+
+
+/*
+ * Deinitialise archive
+ */
+static void lzma_archive_exit(LZMAarchive *archive)
+{
+    /* Free arrays */
+    allocator.Free(archive->folders);
+    allocator.Free(archive->files);
+    allocator.Free(archive);
+}
+
+/*
+ * Wrap all 7z calls in this, so the physfs error state is set appropriately.
+ */
+static int lzma_err(SZ_RESULT rc)
+{
+    switch (rc)
+    {
+        case SZ_OK: /* Same as LZMA_RESULT_OK */
+            break;
+        case SZE_DATA_ERROR: /* Same as LZMA_RESULT_DATA_ERROR */
+            __PHYSFS_setError(ERR_DATA_ERROR);
+            break;
+        case SZE_OUTOFMEMORY:
+            __PHYSFS_setError(ERR_OUT_OF_MEMORY);
+            break;
+        case SZE_CRC_ERROR:
+            __PHYSFS_setError(ERR_CORRUPTED);
+            break;
+        case SZE_NOTIMPL:
+            __PHYSFS_setError(ERR_NOT_IMPLEMENTED);
+            break;
+        case SZE_FAIL:
+            __PHYSFS_setError(ERR_UNKNOWN_ERROR);  /* !!! FIXME: right? */
+            break;
+        case SZE_ARCHIVE_ERROR:
+            __PHYSFS_setError(ERR_CORRUPTED);  /* !!! FIXME: right? */
+            break;
+        default:
+            __PHYSFS_setError(ERR_UNKNOWN_ERROR);
+    } /* switch */
+
+    return(rc);
+} /* lzma_err */
+
+
+static PHYSFS_sint64 LZMA_read(fvoid *opaque, void *outBuffer,
+                               PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    LZMAfile *file = (LZMAfile *) opaque;
+
+    size_t wantedSize = objSize*objCount;
+    size_t remainingSize = file->item->Size - file->position;
+    size_t fileSize = 0;
+
+    BAIL_IF_MACRO(wantedSize == 0, NULL, 0); /* quick rejection. */
+    BAIL_IF_MACRO(remainingSize == 0, ERR_PAST_EOF, 0);
+
+    if (remainingSize < wantedSize)
+    {
+        wantedSize = remainingSize - (remainingSize % objSize);
+        objCount = (PHYSFS_uint32) (remainingSize / objSize);
+        BAIL_IF_MACRO(objCount == 0, ERR_PAST_EOF, 0); /* quick rejection. */
+        __PHYSFS_setError(ERR_PAST_EOF); /* this is always true here. */
+    } /* if */
+
+    /* Only decompress the folder if it is not allready cached */
+    if (file->folder->cache == NULL)
+    {
+        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 outBuffer */
+    memcpy(outBuffer,
+            (file->folder->cache +
+                    file->offset + file->position),
+            wantedSize);
+    file->position += wantedSize; /* Increase virtual position */
+
+    return objCount;
+} /* LZMA_read */
+
+
+static PHYSFS_sint64 LZMA_write(fvoid *opaque, const void *buf,
+                               PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
+} /* LZMA_write */
+
+
+static int LZMA_eof(fvoid *opaque)
+{
+    LZMAfile *file = (LZMAfile *) opaque;
+    return (file->position >= file->item->Size);
+} /* LZMA_eof */
+
+
+static PHYSFS_sint64 LZMA_tell(fvoid *opaque)
+{
+    LZMAfile *file = (LZMAfile *) opaque;
+    return (file->position);
+} /* LZMA_tell */
+
+
+static int LZMA_seek(fvoid *opaque, PHYSFS_uint64 offset)
+{
+    LZMAfile *file = (LZMAfile *) opaque;
+
+    BAIL_IF_MACRO(offset < 0, ERR_SEEK_OUT_OF_RANGE, 0);
+    BAIL_IF_MACRO(offset > file->item->Size, ERR_PAST_EOF, 0);
+
+    file->position = offset; /* We only use a virtual position... */
+
+    return 1;
+} /* LZMA_seek */
+
+
+static PHYSFS_sint64 LZMA_fileLength(fvoid *opaque)
+{
+    LZMAfile *file = (LZMAfile *) opaque;
+    return (file->item->Size);
+} /* LZMA_fileLength */
+
+
+static int LZMA_fileClose(fvoid *opaque)
+{
+    LZMAfile *file = (LZMAfile *) opaque;
+
+    BAIL_IF_MACRO(file->folder == NULL, ERR_NOT_A_FILE, 0);
+
+	/* 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;
+    }
+
+    return(1);
+} /* LZMA_fileClose */
+
+
+static int LZMA_isArchive(const char *filename, int forWriting)
+{
+    PHYSFS_uint8 sig[k7zSignatureSize];
+    void *in;
+
+    BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
+
+    in = __PHYSFS_platformOpenRead(filename);
+    BAIL_IF_MACRO(in == NULL, NULL, 0);
+
+    /* Read signature bytes */
+    if (__PHYSFS_platformRead(in, sig, k7zSignatureSize, 1) != 1)
+    {
+        __PHYSFS_platformClose(in); /* Don't forget to close the file before returning... */
+        BAIL_MACRO(NULL, 0);
+    }
+
+    __PHYSFS_platformClose(in);
+
+    /* Test whether sig is the 7z signature */
+    return(TestSignatureCandidate(sig));
+} /* LZMA_isArchive */
+
+
+static void *LZMA_openArchive(const char *name, int forWriting)
+{
+    size_t len = 0;
+    LZMAarchive *archive = NULL;
+
+    BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, NULL);
+    BAIL_IF_MACRO(!LZMA_isArchive(name,forWriting), ERR_UNSUPPORTED_ARCHIVE, 0);
+
+    archive = (LZMAarchive *) allocator.Malloc(sizeof (LZMAarchive));
+    BAIL_IF_MACRO(archive == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+    lzma_archive_init(archive);
+
+    if ( (archive->stream.file = __PHYSFS_platformOpenRead(name)) == NULL )
+    {
+        __PHYSFS_platformClose(archive->stream.file);
+        lzma_archive_exit(archive);
+        return(NULL); /* Error is set by platformOpenRead! */
+    }
+
+    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);
+        __PHYSFS_platformClose(archive->stream.file);
+        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);
+        __PHYSFS_platformClose(archive->stream.file);
+        lzma_archive_exit(archive);
+        BAIL_MACRO(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);
+        __PHYSFS_platformClose(archive->stream.file);
+        lzma_archive_exit(archive);
+        BAIL_MACRO(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);
+        __PHYSFS_platformClose(archive->stream.file);
+        lzma_archive_exit(archive);
+        BAIL_MACRO(ERR_UNKNOWN_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(dvoid *opaque, const char *dname,
+                                int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+                                const char *origdir, void *callbackdata)
+{
+    size_t dlen = strlen(dname),
+           dlen_inc = dlen + ((dlen > 0) ? 1 : 0);
+    LZMAarchive *archive = (LZMAarchive *) opaque;
+    LZMAfile *file = NULL,
+            *lastFile = &archive->files[archive->db.Database.NumFiles];
+        if (dlen)
+        {
+            file = lzma_find_file(archive, dname);
+            if (file != NULL) /* if 'file' is NULL it should stay so, otherwise errors will not be handled */
+                file += 1;
+        }
+        else
+        {
+            file = archive->files;
+        }
+
+    BAIL_IF_MACRO(file == NULL, ERR_NO_SUCH_FILE, );
+
+    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 int LZMA_exists(dvoid *opaque, const char *name)
+{
+    LZMAarchive *archive = (LZMAarchive *) opaque;
+    return(lzma_find_file(archive, name) != NULL);
+} /* LZMA_exists */
+
+
+static PHYSFS_sint64 LZMA_getLastModTime(dvoid *opaque,
+                                         const char *name,
+                                         int *fileExists)
+{
+    LZMAarchive *archive = (LZMAarchive *) opaque;
+    LZMAfile *file = lzma_find_file(archive, name);
+
+    *fileExists = (file != NULL);
+
+    BAIL_IF_MACRO(file == NULL, NULL, -1);
+	BAIL_IF_MACRO(!file->item->IsLastWriteTimeDefined, NULL, -1); /* write-time may not be defined for every file */
+
+    return(lzma_filetime_to_unix_timestamp(&file->item->LastWriteTime));
+} /* LZMA_getLastModTime */
+
+
+static int LZMA_isDirectory(dvoid *opaque, const char *name, int *fileExists)
+{
+    LZMAarchive *archive = (LZMAarchive *) opaque;
+    LZMAfile *file = lzma_find_file(archive, name);
+
+    *fileExists = (file != NULL);
+
+    return(file == NULL ? 0 : file->item->IsDirectory);
+} /* LZMA_isDirectory */
+
+
+static int LZMA_isSymLink(dvoid *opaque, const char *name, int *fileExists)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* LZMA_isSymLink */
+
+
+static fvoid *LZMA_openRead(dvoid *opaque, const char *name, int *fileExists)
+{
+    LZMAarchive *archive = (LZMAarchive *) opaque;
+    LZMAfile *file = lzma_find_file(archive, name);
+
+    *fileExists = (file != NULL);
+    BAIL_IF_MACRO(file == NULL, ERR_NO_SUCH_FILE, NULL);
+    BAIL_IF_MACRO(file->folder == NULL, ERR_NOT_A_FILE, NULL);
+
+    file->position = 0;
+    file->folder->references++; /* Increase refcount for automatic cleanup... */
+
+    return(file);
+} /* LZMA_openRead */
+
+
+static fvoid *LZMA_openWrite(dvoid *opaque, const char *filename)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* LZMA_openWrite */
+
+
+static fvoid *LZMA_openAppend(dvoid *opaque, const char *filename)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* LZMA_openAppend */
+
+
+static void LZMA_dirClose(dvoid *opaque)
+{
+    LZMAarchive *archive = (LZMAarchive *) opaque;
+    PHYSFS_uint32 fileIndex = 0, numFiles = archive->db.Database.NumFiles;
+
+    for (fileIndex = 0; fileIndex < numFiles; fileIndex++)
+    {
+        LZMA_fileClose(&archive->files[fileIndex]);
+    } /* for */
+
+    SzArDbExFree(&archive->db, SzFreePhysicsFS);
+    __PHYSFS_platformClose(archive->stream.file);
+    lzma_archive_exit(archive);
+} /* LZMA_dirClose */
+
+
+static int LZMA_remove(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* LZMA_remove */
+
+
+static int LZMA_mkdir(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* LZMA_mkdir */
+
+
+const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_LZMA =
+{
+    "7Z",
+    LZMA_ARCHIVE_DESCRIPTION,
+    "Dennis Schridde <[email protected]>",
+    "http://icculus.org/physfs/",
+};
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_LZMA =
+{
+    &__PHYSFS_ArchiveInfo_LZMA,
+    LZMA_isArchive,          /* isArchive() method      */
+    LZMA_openArchive,        /* openArchive() method    */
+    LZMA_enumerateFiles,     /* enumerateFiles() method */
+    LZMA_exists,             /* exists() method         */
+    LZMA_isDirectory,        /* isDirectory() method    */
+    LZMA_isSymLink,          /* isSymLink() method      */
+    LZMA_getLastModTime,     /* getLastModTime() method */
+    LZMA_openRead,           /* openRead() method       */
+    LZMA_openWrite,          /* openWrite() method      */
+    LZMA_openAppend,         /* openAppend() method     */
+    LZMA_remove,             /* remove() method         */
+    LZMA_mkdir,              /* mkdir() method          */
+    LZMA_dirClose,           /* dirClose() method       */
+    LZMA_read,               /* read() method           */
+    LZMA_write,              /* write() method          */
+    LZMA_eof,                /* eof() method            */
+    LZMA_tell,               /* tell() method           */
+    LZMA_seek,               /* seek() method           */
+    LZMA_fileLength,         /* fileLength() method     */
+    LZMA_fileClose           /* fileClose() method      */
+};
+
+#endif  /* defined PHYSFS_SUPPORTS_7Z */
+
+/* end of lzma.c ... */
+

+ 471 - 0
libs/physfs-2.0.3/archivers/mvl.c

@@ -0,0 +1,471 @@
+/*
+ * 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.
+ */
+
+#if (defined PHYSFS_SUPPORTS_MVL)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "physfs.h"
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+typedef struct
+{
+    char name[13];
+    PHYSFS_uint32 startPos;
+    PHYSFS_uint32 size;
+} MVLentry;
+
+typedef struct
+{
+    char *filename;
+    PHYSFS_sint64 last_mod_time;
+    PHYSFS_uint32 entryCount;
+    MVLentry *entries;
+} MVLinfo;
+
+typedef struct
+{
+    void *handle;
+    MVLentry *entry;
+    PHYSFS_uint32 curPos;
+} MVLfileinfo;
+
+
+static void MVL_dirClose(dvoid *opaque)
+{
+    MVLinfo *info = ((MVLinfo *) opaque);
+    allocator.Free(info->filename);
+    allocator.Free(info->entries);
+    allocator.Free(info);
+} /* MVL_dirClose */
+
+
+static PHYSFS_sint64 MVL_read(fvoid *opaque, void *buffer,
+                              PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    MVLfileinfo *finfo = (MVLfileinfo *) opaque;
+    MVLentry *entry = finfo->entry;
+    PHYSFS_uint32 bytesLeft = entry->size - finfo->curPos;
+    PHYSFS_uint32 objsLeft = (bytesLeft / objSize);
+    PHYSFS_sint64 rc;
+
+    if (objsLeft < objCount)
+        objCount = objsLeft;
+
+    rc = __PHYSFS_platformRead(finfo->handle, buffer, objSize, objCount);
+    if (rc > 0)
+        finfo->curPos += (PHYSFS_uint32) (rc * objSize);
+
+    return(rc);
+} /* MVL_read */
+
+
+static PHYSFS_sint64 MVL_write(fvoid *opaque, const void *buffer,
+                               PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
+} /* MVL_write */
+
+
+static int MVL_eof(fvoid *opaque)
+{
+    MVLfileinfo *finfo = (MVLfileinfo *) opaque;
+    MVLentry *entry = finfo->entry;
+    return(finfo->curPos >= entry->size);
+} /* MVL_eof */
+
+
+static PHYSFS_sint64 MVL_tell(fvoid *opaque)
+{
+    return(((MVLfileinfo *) opaque)->curPos);
+} /* MVL_tell */
+
+
+static int MVL_seek(fvoid *opaque, PHYSFS_uint64 offset)
+{
+    MVLfileinfo *finfo = (MVLfileinfo *) opaque;
+    MVLentry *entry = finfo->entry;
+    int rc;
+
+    BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
+    BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
+    rc = __PHYSFS_platformSeek(finfo->handle, entry->startPos + offset);
+    if (rc)
+        finfo->curPos = (PHYSFS_uint32) offset;
+
+    return(rc);
+} /* MVL_seek */
+
+
+static PHYSFS_sint64 MVL_fileLength(fvoid *opaque)
+{
+    MVLfileinfo *finfo = (MVLfileinfo *) opaque;
+    return((PHYSFS_sint64) finfo->entry->size);
+} /* MVL_fileLength */
+
+
+static int MVL_fileClose(fvoid *opaque)
+{
+    MVLfileinfo *finfo = (MVLfileinfo *) opaque;
+    BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0);
+    allocator.Free(finfo);
+    return(1);
+} /* MVL_fileClose */
+
+
+static int mvl_open(const char *filename, int forWriting,
+                    void **fh, PHYSFS_uint32 *count)
+{
+    PHYSFS_uint8 buf[4];
+
+    *fh = NULL;
+    BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
+
+    *fh = __PHYSFS_platformOpenRead(filename);
+    BAIL_IF_MACRO(*fh == NULL, NULL, 0);
+    
+    if (__PHYSFS_platformRead(*fh, buf, 4, 1) != 1)
+        goto openMvl_failed;
+
+    if (memcmp(buf, "DMVL", 4) != 0)
+    {
+        __PHYSFS_setError(ERR_UNSUPPORTED_ARCHIVE);
+        goto openMvl_failed;
+    } /* if */
+
+    if (__PHYSFS_platformRead(*fh, count, sizeof (PHYSFS_uint32), 1) != 1)
+        goto openMvl_failed;
+
+    *count = PHYSFS_swapULE32(*count);
+
+    return(1);
+
+openMvl_failed:
+    if (*fh != NULL)
+        __PHYSFS_platformClose(*fh);
+
+    *count = -1;
+    *fh = NULL;
+    return(0);
+} /* mvl_open */
+
+
+static int MVL_isArchive(const char *filename, int forWriting)
+{
+    void *fh;
+    PHYSFS_uint32 fileCount;
+    int retval = mvl_open(filename, forWriting, &fh, &fileCount);
+
+    if (fh != NULL)
+        __PHYSFS_platformClose(fh);
+
+    return(retval);
+} /* MVL_isArchive */
+
+
+static int mvl_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
+{
+    if (one != two)
+    {
+        const MVLentry *a = (const MVLentry *) _a;
+        return(strcmp(a[one].name, a[two].name));
+    } /* if */
+
+    return 0;
+} /* mvl_entry_cmp */
+
+
+static void mvl_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
+{
+    if (one != two)
+    {
+        MVLentry tmp;
+        MVLentry *first = &(((MVLentry *) _a)[one]);
+        MVLentry *second = &(((MVLentry *) _a)[two]);
+        memcpy(&tmp, first, sizeof (MVLentry));
+        memcpy(first, second, sizeof (MVLentry));
+        memcpy(second, &tmp, sizeof (MVLentry));
+    } /* if */
+} /* mvl_entry_swap */
+
+
+static int mvl_load_entries(const char *name, int forWriting, MVLinfo *info)
+{
+    void *fh = NULL;
+    PHYSFS_uint32 fileCount;
+    PHYSFS_uint32 location = 8;  /* sizeof sig. */
+    MVLentry *entry;
+
+    BAIL_IF_MACRO(!mvl_open(name, forWriting, &fh, &fileCount), NULL, 0);
+    info->entryCount = fileCount;
+    info->entries = (MVLentry *) allocator.Malloc(sizeof(MVLentry)*fileCount);
+    if (info->entries == NULL)
+    {
+        __PHYSFS_platformClose(fh);
+        BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
+    } /* if */
+
+    location += (17 * fileCount);
+
+    for (entry = info->entries; fileCount > 0; fileCount--, entry++)
+    {
+        if (__PHYSFS_platformRead(fh, &entry->name, 13, 1) != 1)
+        {
+            __PHYSFS_platformClose(fh);
+            return(0);
+        } /* if */
+
+        if (__PHYSFS_platformRead(fh, &entry->size, 4, 1) != 1)
+        {
+            __PHYSFS_platformClose(fh);
+            return(0);
+        } /* if */
+
+        entry->size = PHYSFS_swapULE32(entry->size);
+        entry->startPos = location;
+        location += entry->size;
+    } /* for */
+
+    __PHYSFS_platformClose(fh);
+
+    __PHYSFS_sort(info->entries, info->entryCount,
+                  mvl_entry_cmp, mvl_entry_swap);
+    return(1);
+} /* mvl_load_entries */
+
+
+static void *MVL_openArchive(const char *name, int forWriting)
+{
+    PHYSFS_sint64 modtime = __PHYSFS_platformGetLastModTime(name);
+    MVLinfo *info = (MVLinfo *) allocator.Malloc(sizeof (MVLinfo));
+
+    BAIL_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, NULL);
+    memset(info, '\0', sizeof (MVLinfo));
+
+    info->filename = (char *) allocator.Malloc(strlen(name) + 1);
+    GOTO_IF_MACRO(!info->filename, ERR_OUT_OF_MEMORY, MVL_openArchive_failed);
+    if (!mvl_load_entries(name, forWriting, info))
+        goto MVL_openArchive_failed;
+
+    strcpy(info->filename, name);
+    info->last_mod_time = modtime;
+    return(info);
+
+MVL_openArchive_failed:
+    if (info != NULL)
+    {
+        if (info->filename != NULL)
+            allocator.Free(info->filename);
+        if (info->entries != NULL)
+            allocator.Free(info->entries);
+        allocator.Free(info);
+    } /* if */
+
+    return(NULL);
+} /* MVL_openArchive */
+
+
+static void MVL_enumerateFiles(dvoid *opaque, const char *dname,
+                               int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+                               const char *origdir, void *callbackdata)
+{
+    /* no directories in MVL files. */
+    if (*dname == '\0')
+    {
+        MVLinfo *info = ((MVLinfo *) opaque);
+        MVLentry *entry = info->entries;
+        PHYSFS_uint32 max = info->entryCount;
+        PHYSFS_uint32 i;
+
+        for (i = 0; i < max; i++, entry++)
+            cb(callbackdata, origdir, entry->name);
+    } /* if */
+} /* MVL_enumerateFiles */
+
+
+static MVLentry *mvl_find_entry(MVLinfo *info, const char *name)
+{
+    char *ptr = strchr(name, '.');
+    MVLentry *a = info->entries;
+    PHYSFS_sint32 lo = 0;
+    PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
+    PHYSFS_sint32 middle;
+    int rc;
+
+    /*
+     * Rule out filenames to avoid unneeded processing...no dirs,
+     *   big filenames, or extensions > 3 chars.
+     */
+    BAIL_IF_MACRO((ptr) && (strlen(ptr) > 4), ERR_NO_SUCH_FILE, NULL);
+    BAIL_IF_MACRO(strlen(name) > 12, ERR_NO_SUCH_FILE, NULL);
+    BAIL_IF_MACRO(strchr(name, '/') != NULL, ERR_NO_SUCH_FILE, NULL);
+
+    while (lo <= hi)
+    {
+        middle = lo + ((hi - lo) / 2);
+        rc = __PHYSFS_stricmpASCII(name, a[middle].name);
+        if (rc == 0)  /* found it! */
+            return(&a[middle]);
+        else if (rc > 0)
+            lo = middle + 1;
+        else
+            hi = middle - 1;
+    } /* while */
+
+    BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
+} /* mvl_find_entry */
+
+
+static int MVL_exists(dvoid *opaque, const char *name)
+{
+    return(mvl_find_entry(((MVLinfo *) opaque), name) != NULL);
+} /* MVL_exists */
+
+
+static int MVL_isDirectory(dvoid *opaque, const char *name, int *fileExists)
+{
+    *fileExists = MVL_exists(opaque, name);
+    return(0);  /* never directories in a groupfile. */
+} /* MVL_isDirectory */
+
+
+static int MVL_isSymLink(dvoid *opaque, const char *name, int *fileExists)
+{
+    *fileExists = MVL_exists(opaque, name);
+    return(0);  /* never symlinks in a groupfile. */
+} /* MVL_isSymLink */
+
+
+static PHYSFS_sint64 MVL_getLastModTime(dvoid *opaque,
+                                        const char *name,
+                                        int *fileExists)
+{
+    MVLinfo *info = ((MVLinfo *) opaque);
+    PHYSFS_sint64 retval = -1;
+
+    *fileExists = (mvl_find_entry(info, name) != NULL);
+    if (*fileExists)  /* use time of MVL itself in the physical filesystem. */
+        retval = info->last_mod_time;
+
+    return(retval);
+} /* MVL_getLastModTime */
+
+
+static fvoid *MVL_openRead(dvoid *opaque, const char *fnm, int *fileExists)
+{
+    MVLinfo *info = ((MVLinfo *) opaque);
+    MVLfileinfo *finfo;
+    MVLentry *entry;
+
+    entry = mvl_find_entry(info, fnm);
+    *fileExists = (entry != NULL);
+    BAIL_IF_MACRO(entry == NULL, NULL, NULL);
+
+    finfo = (MVLfileinfo *) allocator.Malloc(sizeof (MVLfileinfo));
+    BAIL_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+    finfo->handle = __PHYSFS_platformOpenRead(info->filename);
+    if ( (finfo->handle == NULL) ||
+         (!__PHYSFS_platformSeek(finfo->handle, entry->startPos)) )
+    {
+        allocator.Free(finfo);
+        return(NULL);
+    } /* if */
+
+    finfo->curPos = 0;
+    finfo->entry = entry;
+    return(finfo);
+} /* MVL_openRead */
+
+
+static fvoid *MVL_openWrite(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* MVL_openWrite */
+
+
+static fvoid *MVL_openAppend(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* MVL_openAppend */
+
+
+static int MVL_remove(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* MVL_remove */
+
+
+static int MVL_mkdir(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* MVL_mkdir */
+
+
+const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_MVL =
+{
+    "MVL",
+    MVL_ARCHIVE_DESCRIPTION,
+    "Bradley Bell <[email protected]>",
+    "http://icculus.org/physfs/",
+};
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_MVL =
+{
+    &__PHYSFS_ArchiveInfo_MVL,
+    MVL_isArchive,          /* isArchive() method      */
+    MVL_openArchive,        /* openArchive() method    */
+    MVL_enumerateFiles,     /* enumerateFiles() method */
+    MVL_exists,             /* exists() method         */
+    MVL_isDirectory,        /* isDirectory() method    */
+    MVL_isSymLink,          /* isSymLink() method      */
+    MVL_getLastModTime,     /* getLastModTime() method */
+    MVL_openRead,           /* openRead() method       */
+    MVL_openWrite,          /* openWrite() method      */
+    MVL_openAppend,         /* openAppend() method     */
+    MVL_remove,             /* remove() method         */
+    MVL_mkdir,              /* mkdir() method          */
+    MVL_dirClose,           /* dirClose() method       */
+    MVL_read,               /* read() method           */
+    MVL_write,              /* write() method          */
+    MVL_eof,                /* eof() method            */
+    MVL_tell,               /* tell() method           */
+    MVL_seek,               /* seek() method           */
+    MVL_fileLength,         /* fileLength() method     */
+    MVL_fileClose           /* fileClose() method      */
+};
+
+#endif  /* defined PHYSFS_SUPPORTS_MVL */
+
+/* end of mvl.c ... */
+

+ 633 - 0
libs/physfs-2.0.3/archivers/qpak.c

@@ -0,0 +1,633 @@
+/*
+ * 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.
+ */
+
+#if (defined PHYSFS_SUPPORTS_QPAK)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "physfs.h"
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+#if 1  /* Make this case insensitive? */
+#define QPAK_strcmp(x, y) __PHYSFS_stricmpASCII(x, y)
+#define QPAK_strncmp(x, y, z) __PHYSFS_strnicmpASCII(x, y, z)
+#else
+#define QPAK_strcmp(x, y) strcmp(x, y)
+#define QPAK_strncmp(x, y, z) strncmp(x, y, z)
+#endif
+
+
+typedef struct
+{
+    char name[56];
+    PHYSFS_uint32 startPos;
+    PHYSFS_uint32 size;
+} QPAKentry;
+
+typedef struct
+{
+    char *filename;
+    PHYSFS_sint64 last_mod_time;
+    PHYSFS_uint32 entryCount;
+    QPAKentry *entries;
+} QPAKinfo;
+
+typedef struct
+{
+    void *handle;
+    QPAKentry *entry;
+    PHYSFS_uint32 curPos;
+} QPAKfileinfo;
+
+/* Magic numbers... */
+#define QPAK_SIG 0x4b434150   /* "PACK" in ASCII. */
+
+
+static void QPAK_dirClose(dvoid *opaque)
+{
+    QPAKinfo *info = ((QPAKinfo *) opaque);
+    allocator.Free(info->filename);
+    allocator.Free(info->entries);
+    allocator.Free(info);
+} /* QPAK_dirClose */
+
+
+static PHYSFS_sint64 QPAK_read(fvoid *opaque, void *buffer,
+                              PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    QPAKfileinfo *finfo = (QPAKfileinfo *) opaque;
+    QPAKentry *entry = finfo->entry;
+    PHYSFS_uint32 bytesLeft = entry->size - finfo->curPos;
+    PHYSFS_uint32 objsLeft = (bytesLeft / objSize);
+    PHYSFS_sint64 rc;
+
+    if (objsLeft < objCount)
+        objCount = objsLeft;
+
+    rc = __PHYSFS_platformRead(finfo->handle, buffer, objSize, objCount);
+    if (rc > 0)
+        finfo->curPos += (PHYSFS_uint32) (rc * objSize);
+
+    return(rc);
+} /* QPAK_read */
+
+
+static PHYSFS_sint64 QPAK_write(fvoid *opaque, const void *buffer,
+                               PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
+} /* QPAK_write */
+
+
+static int QPAK_eof(fvoid *opaque)
+{
+    QPAKfileinfo *finfo = (QPAKfileinfo *) opaque;
+    QPAKentry *entry = finfo->entry;
+    return(finfo->curPos >= entry->size);
+} /* QPAK_eof */
+
+
+static PHYSFS_sint64 QPAK_tell(fvoid *opaque)
+{
+    return(((QPAKfileinfo *) opaque)->curPos);
+} /* QPAK_tell */
+
+
+static int QPAK_seek(fvoid *opaque, PHYSFS_uint64 offset)
+{
+    QPAKfileinfo *finfo = (QPAKfileinfo *) opaque;
+    QPAKentry *entry = finfo->entry;
+    int rc;
+
+    BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
+    BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
+    rc = __PHYSFS_platformSeek(finfo->handle, entry->startPos + offset);
+    if (rc)
+        finfo->curPos = (PHYSFS_uint32) offset;
+
+    return(rc);
+} /* QPAK_seek */
+
+
+static PHYSFS_sint64 QPAK_fileLength(fvoid *opaque)
+{
+    QPAKfileinfo *finfo = (QPAKfileinfo *) opaque;
+    return((PHYSFS_sint64) finfo->entry->size);
+} /* QPAK_fileLength */
+
+
+static int QPAK_fileClose(fvoid *opaque)
+{
+    QPAKfileinfo *finfo = (QPAKfileinfo *) opaque;
+    BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0);
+    allocator.Free(finfo);
+    return(1);
+} /* QPAK_fileClose */
+
+
+static int qpak_open(const char *filename, int forWriting,
+                    void **fh, PHYSFS_uint32 *count)
+{
+    PHYSFS_uint32 buf;
+
+    *fh = NULL;
+    BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
+
+    *fh = __PHYSFS_platformOpenRead(filename);
+    BAIL_IF_MACRO(*fh == NULL, NULL, 0);
+    
+    if (__PHYSFS_platformRead(*fh, &buf, sizeof (PHYSFS_uint32), 1) != 1)
+        goto openQpak_failed;
+
+    buf = PHYSFS_swapULE32(buf);
+    GOTO_IF_MACRO(buf != QPAK_SIG, ERR_UNSUPPORTED_ARCHIVE, openQpak_failed);
+
+    if (__PHYSFS_platformRead(*fh, &buf, sizeof (PHYSFS_uint32), 1) != 1)
+        goto openQpak_failed;
+
+    buf = PHYSFS_swapULE32(buf);  /* directory table offset. */
+
+    if (__PHYSFS_platformRead(*fh, count, sizeof (PHYSFS_uint32), 1) != 1)
+        goto openQpak_failed;
+
+    *count = PHYSFS_swapULE32(*count);
+
+    /* corrupted archive? */
+    GOTO_IF_MACRO((*count % 64) != 0, ERR_CORRUPTED, openQpak_failed);
+
+    if (!__PHYSFS_platformSeek(*fh, buf))
+        goto openQpak_failed;
+
+    *count /= 64;
+    return(1);
+
+openQpak_failed:
+    if (*fh != NULL)
+        __PHYSFS_platformClose(*fh);
+
+    *count = -1;
+    *fh = NULL;
+    return(0);
+} /* qpak_open */
+
+
+static int QPAK_isArchive(const char *filename, int forWriting)
+{
+    void *fh;
+    PHYSFS_uint32 fileCount;
+    int retval = qpak_open(filename, forWriting, &fh, &fileCount);
+
+    if (fh != NULL)
+        __PHYSFS_platformClose(fh);
+
+    return(retval);
+} /* QPAK_isArchive */
+
+
+static int qpak_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
+{
+    if (one != two)
+    {
+        const QPAKentry *a = (const QPAKentry *) _a;
+        return(QPAK_strcmp(a[one].name, a[two].name));
+    } /* if */
+
+    return 0;
+} /* qpak_entry_cmp */
+
+
+static void qpak_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
+{
+    if (one != two)
+    {
+        QPAKentry tmp;
+        QPAKentry *first = &(((QPAKentry *) _a)[one]);
+        QPAKentry *second = &(((QPAKentry *) _a)[two]);
+        memcpy(&tmp, first, sizeof (QPAKentry));
+        memcpy(first, second, sizeof (QPAKentry));
+        memcpy(second, &tmp, sizeof (QPAKentry));
+    } /* if */
+} /* qpak_entry_swap */
+
+
+static int qpak_load_entries(const char *name, int forWriting, QPAKinfo *info)
+{
+    void *fh = NULL;
+    PHYSFS_uint32 fileCount;
+    QPAKentry *entry;
+
+    BAIL_IF_MACRO(!qpak_open(name, forWriting, &fh, &fileCount), NULL, 0);
+    info->entryCount = fileCount;
+    info->entries = (QPAKentry*) allocator.Malloc(sizeof(QPAKentry)*fileCount);
+    if (info->entries == NULL)
+    {
+        __PHYSFS_platformClose(fh);
+        BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
+    } /* if */
+
+    for (entry = info->entries; fileCount > 0; fileCount--, entry++)
+    {
+        PHYSFS_uint32 loc;
+
+        if (__PHYSFS_platformRead(fh,&entry->name,sizeof(entry->name),1) != 1)
+        {
+            __PHYSFS_platformClose(fh);
+            return(0);
+        } /* if */
+
+        if (__PHYSFS_platformRead(fh,&loc,sizeof(loc),1) != 1)
+        {
+            __PHYSFS_platformClose(fh);
+            return(0);
+        } /* if */
+
+        if (__PHYSFS_platformRead(fh,&entry->size,sizeof(entry->size),1) != 1)
+        {
+            __PHYSFS_platformClose(fh);
+            return(0);
+        } /* if */
+
+        entry->size = PHYSFS_swapULE32(entry->size);
+        entry->startPos = PHYSFS_swapULE32(loc);
+    } /* for */
+
+    __PHYSFS_platformClose(fh);
+
+    __PHYSFS_sort(info->entries, info->entryCount,
+                  qpak_entry_cmp, qpak_entry_swap);
+    return(1);
+} /* qpak_load_entries */
+
+
+static void *QPAK_openArchive(const char *name, int forWriting)
+{
+    QPAKinfo *info = (QPAKinfo *) allocator.Malloc(sizeof (QPAKinfo));
+    PHYSFS_sint64 modtime = __PHYSFS_platformGetLastModTime(name);
+
+    BAIL_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, NULL);
+    memset(info, '\0', sizeof (QPAKinfo));
+
+    info->filename = (char *) allocator.Malloc(strlen(name) + 1);
+    if (info->filename == NULL)
+    {
+        __PHYSFS_setError(ERR_OUT_OF_MEMORY);
+        goto QPAK_openArchive_failed;
+    } /* if */
+
+    if (!qpak_load_entries(name, forWriting, info))
+        goto QPAK_openArchive_failed;
+
+    strcpy(info->filename, name);
+    info->last_mod_time = modtime;
+    return(info);
+
+QPAK_openArchive_failed:
+    if (info != NULL)
+    {
+        if (info->filename != NULL)
+            allocator.Free(info->filename);
+        if (info->entries != NULL)
+            allocator.Free(info->entries);
+        allocator.Free(info);
+    } /* if */
+
+    return(NULL);
+} /* QPAK_openArchive */
+
+
+static PHYSFS_sint32 qpak_find_start_of_dir(QPAKinfo *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 = 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 = QPAK_strncmp(path, name, dlen);
+        if (rc == 0)
+        {
+            char ch = name[dlen];
+            if (ch < '/') /* make sure this isn't just a substr match. */
+                rc = -1;
+            else if (ch > '/')
+                rc = 1;
+            else 
+            {
+                if (stop_on_first_find) /* Just checking dir's existance? */
+                    return(middle);
+
+                if (name[dlen + 1] == '\0') /* Skip initial dir entry. */
+                    return(middle + 1);
+
+                /* there might be more entries earlier in the list. */
+                retval = middle;
+                hi = middle - 1;
+            } /* else */
+        } /* if */
+
+        if (rc > 0)
+            lo = middle + 1;
+        else
+            hi = middle - 1;
+    } /* while */
+
+    return(retval);
+} /* qpak_find_start_of_dir */
+
+
+/*
+ * Moved to seperate function so we can use alloca then immediately throw
+ *  away the allocated stack space...
+ */
+static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata,
+                           const char *odir, const char *str, PHYSFS_sint32 ln)
+{
+    char *newstr = __PHYSFS_smallAlloc(ln + 1);
+    if (newstr == NULL)
+        return;
+
+    memcpy(newstr, str, ln);
+    newstr[ln] = '\0';
+    cb(callbackdata, odir, newstr);
+    __PHYSFS_smallFree(newstr);
+} /* doEnumCallback */
+
+
+static void QPAK_enumerateFiles(dvoid *opaque, const char *dname,
+                                int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+                                const char *origdir, void *callbackdata)
+{
+    QPAKinfo *info = ((QPAKinfo *) opaque);
+    PHYSFS_sint32 dlen, dlen_inc, max, i;
+
+    i = qpak_find_start_of_dir(info, dname, 0);
+    if (i == -1)  /* no such directory. */
+        return;
+
+    dlen = 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) && ((QPAK_strncmp(e, dname, dlen)) || (e[dlen] != '/')))
+            break;  /* past end of this dir; we're done. */
+
+        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 ((QPAK_strncmp(e, e_new, ln) != 0) || (e_new[ln] != '/'))
+                break;
+        } /* while */
+    } /* while */
+} /* QPAK_enumerateFiles */
+
+
+/*
+ * This will find the QPAKentry associated with a path in platform-independent
+ *  notation. Directories don't have QPAKentries associated with them, but 
+ *  (*isDir) will be set to non-zero if a dir was hit.
+ */
+static QPAKentry *qpak_find_entry(QPAKinfo *info, const char *path, int *isDir)
+{
+    QPAKentry *a = info->entries;
+    PHYSFS_sint32 pathlen = 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 = QPAK_strncmp(path, thispath, pathlen);
+
+        if (rc > 0)
+            lo = middle + 1;
+
+        else if (rc < 0)
+            hi = middle - 1;
+
+        else /* substring match...might be dir or entry or nothing. */
+        {
+            if (isDir != NULL)
+            {
+                *isDir = (thispath[pathlen] == '/');
+                if (*isDir)
+                    return(NULL);
+            } /* if */
+
+            if (thispath[pathlen] == '\0') /* found entry? */
+                return(&a[middle]);
+            /* adjust search params, try again. */
+            else if (thispath[pathlen] > '/')
+                hi = middle - 1;
+            else
+                lo = middle + 1;
+        } /* if */
+    } /* while */
+
+    if (isDir != NULL)
+        *isDir = 0;
+
+    BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
+} /* qpak_find_entry */
+
+
+static int QPAK_exists(dvoid *opaque, const char *name)
+{
+    int isDir;    
+    QPAKinfo *info = (QPAKinfo *) opaque;
+    QPAKentry *entry = qpak_find_entry(info, name, &isDir);
+    return((entry != NULL) || (isDir));
+} /* QPAK_exists */
+
+
+static int QPAK_isDirectory(dvoid *opaque, const char *name, int *fileExists)
+{
+    QPAKinfo *info = (QPAKinfo *) opaque;
+    int isDir;
+    QPAKentry *entry = qpak_find_entry(info, name, &isDir);
+
+    *fileExists = ((isDir) || (entry != NULL));
+    if (isDir)
+        return(1); /* definitely a dir. */
+
+    BAIL_MACRO(ERR_NO_SUCH_FILE, 0);
+} /* QPAK_isDirectory */
+
+
+static int QPAK_isSymLink(dvoid *opaque, const char *name, int *fileExists)
+{
+    *fileExists = QPAK_exists(opaque, name);
+    return(0);  /* never symlinks in a quake pak. */
+} /* QPAK_isSymLink */
+
+
+static PHYSFS_sint64 QPAK_getLastModTime(dvoid *opaque,
+                                        const char *name,
+                                        int *fileExists)
+{
+    int isDir;
+    QPAKinfo *info = ((QPAKinfo *) opaque);
+    PHYSFS_sint64 retval = -1;
+    QPAKentry *entry = qpak_find_entry(info, name, &isDir);
+
+    *fileExists = ((isDir) || (entry != NULL));
+    if (*fileExists)  /* use time of QPAK itself in the physical filesystem. */
+        retval = info->last_mod_time;
+
+    return(retval);
+} /* QPAK_getLastModTime */
+
+
+static fvoid *QPAK_openRead(dvoid *opaque, const char *fnm, int *fileExists)
+{
+    QPAKinfo *info = ((QPAKinfo *) opaque);
+    QPAKfileinfo *finfo;
+    QPAKentry *entry;
+    int isDir;
+
+    entry = qpak_find_entry(info, fnm, &isDir);
+    *fileExists = ((entry != NULL) || (isDir));
+    BAIL_IF_MACRO(isDir, ERR_NOT_A_FILE, NULL);
+    BAIL_IF_MACRO(entry == NULL, ERR_NO_SUCH_FILE, NULL);
+
+    finfo = (QPAKfileinfo *) allocator.Malloc(sizeof (QPAKfileinfo));
+    BAIL_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+    finfo->handle = __PHYSFS_platformOpenRead(info->filename);
+    if ( (finfo->handle == NULL) ||
+         (!__PHYSFS_platformSeek(finfo->handle, entry->startPos)) )
+    {
+        allocator.Free(finfo);
+        return(NULL);
+    } /* if */
+
+    finfo->curPos = 0;
+    finfo->entry = entry;
+    return(finfo);
+} /* QPAK_openRead */
+
+
+static fvoid *QPAK_openWrite(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* QPAK_openWrite */
+
+
+static fvoid *QPAK_openAppend(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* QPAK_openAppend */
+
+
+static int QPAK_remove(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* QPAK_remove */
+
+
+static int QPAK_mkdir(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* QPAK_mkdir */
+
+
+const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_QPAK =
+{
+    "PAK",
+    QPAK_ARCHIVE_DESCRIPTION,
+    "Ryan C. Gordon <[email protected]>",
+    "http://icculus.org/physfs/",
+};
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_QPAK =
+{
+    &__PHYSFS_ArchiveInfo_QPAK,
+    QPAK_isArchive,          /* isArchive() method      */
+    QPAK_openArchive,        /* openArchive() method    */
+    QPAK_enumerateFiles,     /* enumerateFiles() method */
+    QPAK_exists,             /* exists() method         */
+    QPAK_isDirectory,        /* isDirectory() method    */
+    QPAK_isSymLink,          /* isSymLink() method      */
+    QPAK_getLastModTime,     /* getLastModTime() method */
+    QPAK_openRead,           /* openRead() method       */
+    QPAK_openWrite,          /* openWrite() method      */
+    QPAK_openAppend,         /* openAppend() method     */
+    QPAK_remove,             /* remove() method         */
+    QPAK_mkdir,              /* mkdir() method          */
+    QPAK_dirClose,           /* dirClose() method       */
+    QPAK_read,               /* read() method           */
+    QPAK_write,              /* write() method          */
+    QPAK_eof,                /* eof() method            */
+    QPAK_tell,               /* tell() method           */
+    QPAK_seek,               /* seek() method           */
+    QPAK_fileLength,         /* fileLength() method     */
+    QPAK_fileClose           /* fileClose() method      */
+};
+
+#endif  /* defined PHYSFS_SUPPORTS_QPAK */
+
+/* end of qpak.c ... */
+

+ 531 - 0
libs/physfs-2.0.3/archivers/wad.c

@@ -0,0 +1,531 @@
+/*
+ * 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.
+ */
+
+#if (defined PHYSFS_SUPPORTS_WAD)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "physfs.h"
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+typedef struct
+{
+    char name[18];
+    PHYSFS_uint32 startPos;
+    PHYSFS_uint32 size;
+} WADentry;
+
+typedef struct
+{
+    char *filename;
+    PHYSFS_sint64 last_mod_time;
+    PHYSFS_uint32 entryCount;
+    PHYSFS_uint32 entryOffset;
+    WADentry *entries;
+} WADinfo;
+
+typedef struct
+{
+    void *handle;
+    WADentry *entry;
+    PHYSFS_uint32 curPos;
+} WADfileinfo;
+
+
+static void WAD_dirClose(dvoid *opaque)
+{
+    WADinfo *info = ((WADinfo *) opaque);
+    allocator.Free(info->filename);
+    allocator.Free(info->entries);
+    allocator.Free(info);
+} /* WAD_dirClose */
+
+
+static PHYSFS_sint64 WAD_read(fvoid *opaque, void *buffer,
+                              PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    WADfileinfo *finfo = (WADfileinfo *) opaque;
+    WADentry *entry = finfo->entry;
+    PHYSFS_uint32 bytesLeft = entry->size - finfo->curPos;
+    PHYSFS_uint32 objsLeft = (bytesLeft / objSize);
+    PHYSFS_sint64 rc;
+
+    if (objsLeft < objCount)
+        objCount = objsLeft;
+
+    rc = __PHYSFS_platformRead(finfo->handle, buffer, objSize, objCount);
+    if (rc > 0)
+        finfo->curPos += (PHYSFS_uint32) (rc * objSize);
+
+    return(rc);
+} /* WAD_read */
+
+
+static PHYSFS_sint64 WAD_write(fvoid *opaque, const void *buffer,
+                               PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
+} /* WAD_write */
+
+
+static int WAD_eof(fvoid *opaque)
+{
+    WADfileinfo *finfo = (WADfileinfo *) opaque;
+    WADentry *entry = finfo->entry;
+    return(finfo->curPos >= entry->size);
+} /* WAD_eof */
+
+
+static PHYSFS_sint64 WAD_tell(fvoid *opaque)
+{
+    return(((WADfileinfo *) opaque)->curPos);
+} /* WAD_tell */
+
+
+static int WAD_seek(fvoid *opaque, PHYSFS_uint64 offset)
+{
+    WADfileinfo *finfo = (WADfileinfo *) opaque;
+    WADentry *entry = finfo->entry;
+    int rc;
+
+    BAIL_IF_MACRO(offset < 0, ERR_INVALID_ARGUMENT, 0);
+    BAIL_IF_MACRO(offset >= entry->size, ERR_PAST_EOF, 0);
+    rc = __PHYSFS_platformSeek(finfo->handle, entry->startPos + offset);
+    if (rc)
+        finfo->curPos = (PHYSFS_uint32) offset;
+
+    return(rc);
+} /* WAD_seek */
+
+
+static PHYSFS_sint64 WAD_fileLength(fvoid *opaque)
+{
+    WADfileinfo *finfo = (WADfileinfo *) opaque;
+    return((PHYSFS_sint64) finfo->entry->size);
+} /* WAD_fileLength */
+
+
+static int WAD_fileClose(fvoid *opaque)
+{
+    WADfileinfo *finfo = (WADfileinfo *) opaque;
+    BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0);
+    allocator.Free(finfo);
+    return(1);
+} /* WAD_fileClose */
+
+
+static int wad_open(const char *filename, int forWriting,
+                    void **fh, PHYSFS_uint32 *count,PHYSFS_uint32 *offset)
+{
+    PHYSFS_uint8 buf[4];
+
+    *fh = NULL;
+    BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
+
+    *fh = __PHYSFS_platformOpenRead(filename);
+    BAIL_IF_MACRO(*fh == NULL, NULL, 0);
+    
+    if (__PHYSFS_platformRead(*fh, buf, 4, 1) != 1)
+        goto openWad_failed;
+
+    if (memcmp(buf, "IWAD", 4) != 0 && memcmp(buf, "PWAD", 4) != 0)
+    {
+        __PHYSFS_setError(ERR_UNSUPPORTED_ARCHIVE);
+        goto openWad_failed;
+    } /* if */
+
+    if (__PHYSFS_platformRead(*fh, count, sizeof (PHYSFS_uint32), 1) != 1)
+        goto openWad_failed;
+
+    *count = PHYSFS_swapULE32(*count);
+
+    if (__PHYSFS_platformRead(*fh, offset, sizeof (PHYSFS_uint32), 1) != 1)
+        goto openWad_failed;
+
+    *offset = PHYSFS_swapULE32(*offset);
+
+    return(1);
+
+openWad_failed:
+    if (*fh != NULL)
+        __PHYSFS_platformClose(*fh);
+
+    *count = -1;
+    *fh = NULL;
+    return(0);
+} /* wad_open */
+
+
+static int WAD_isArchive(const char *filename, int forWriting)
+{
+    void *fh;
+    PHYSFS_uint32 fileCount,offset;
+    int retval = wad_open(filename, forWriting, &fh, &fileCount,&offset);
+
+    if (fh != NULL)
+        __PHYSFS_platformClose(fh);
+
+    return(retval);
+} /* WAD_isArchive */
+
+
+static int wad_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
+{
+    if (one != two)
+    {
+        const WADentry *a = (const WADentry *) _a;
+        return(strcmp(a[one].name, a[two].name));
+    } /* if */
+
+    return 0;
+} /* wad_entry_cmp */
+
+
+static void wad_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
+{
+    if (one != two)
+    {
+        WADentry tmp;
+        WADentry *first = &(((WADentry *) _a)[one]);
+        WADentry *second = &(((WADentry *) _a)[two]);
+        memcpy(&tmp, first, sizeof (WADentry));
+        memcpy(first, second, sizeof (WADentry));
+        memcpy(second, &tmp, sizeof (WADentry));
+    } /* if */
+} /* wad_entry_swap */
+
+
+static int wad_load_entries(const char *name, int forWriting, WADinfo *info)
+{
+    void *fh = NULL;
+    PHYSFS_uint32 fileCount;
+    PHYSFS_uint32 directoryOffset;
+    WADentry *entry;
+
+    BAIL_IF_MACRO(!wad_open(name, forWriting, &fh, &fileCount,&directoryOffset), NULL, 0);
+    info->entryCount = fileCount;
+    info->entries = (WADentry *) allocator.Malloc(sizeof(WADentry)*fileCount);
+    if (info->entries == NULL)
+    {
+        __PHYSFS_platformClose(fh);
+        BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
+    } /* if */
+
+    __PHYSFS_platformSeek(fh,directoryOffset);
+
+    for (entry = info->entries; fileCount > 0; fileCount--, entry++)
+    {
+        if (__PHYSFS_platformRead(fh, &entry->startPos, 4, 1) != 1)
+        {
+            __PHYSFS_platformClose(fh);
+            return(0);
+        } /* if */
+        
+        if (__PHYSFS_platformRead(fh, &entry->size, 4, 1) != 1)
+        {
+            __PHYSFS_platformClose(fh);
+            return(0);
+        } /* if */
+
+        if (__PHYSFS_platformRead(fh, &entry->name, 8, 1) != 1)
+        {
+            __PHYSFS_platformClose(fh);
+            return(0);
+        } /* if */
+
+        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 */
+
+    __PHYSFS_platformClose(fh);
+
+    __PHYSFS_sort(info->entries, info->entryCount,
+                  wad_entry_cmp, wad_entry_swap);
+    return(1);
+} /* wad_load_entries */
+
+
+static void *WAD_openArchive(const char *name, int forWriting)
+{
+    PHYSFS_sint64 modtime = __PHYSFS_platformGetLastModTime(name);
+    WADinfo *info = (WADinfo *) allocator.Malloc(sizeof (WADinfo));
+
+    BAIL_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, NULL);
+    memset(info, '\0', sizeof (WADinfo));
+
+    info->filename = (char *) allocator.Malloc(strlen(name) + 1);
+    GOTO_IF_MACRO(!info->filename, ERR_OUT_OF_MEMORY, WAD_openArchive_failed);
+
+    if (!wad_load_entries(name, forWriting, info))
+        goto WAD_openArchive_failed;
+
+    strcpy(info->filename, name);
+    info->last_mod_time = modtime;
+    return(info);
+
+WAD_openArchive_failed:
+    if (info != NULL)
+    {
+        if (info->filename != NULL)
+            allocator.Free(info->filename);
+        if (info->entries != NULL)
+            allocator.Free(info->entries);
+        allocator.Free(info);
+    } /* if */
+
+    return(NULL);
+} /* WAD_openArchive */
+
+
+static void WAD_enumerateFiles(dvoid *opaque, const char *dname,
+                               int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+                               const char *origdir, void *callbackdata)
+{
+    WADinfo *info = ((WADinfo *) opaque);
+    WADentry *entry = info->entries;
+    PHYSFS_uint32 max = info->entryCount;
+    PHYSFS_uint32 i;
+    const char *name;
+    char *sep;
+
+    if (*dname == '\0')  /* root directory enumeration? */
+    {
+        for (i = 0; i < max; i++, entry++)
+        {
+            name = entry->name;
+            if (strchr(name, '/') == NULL)
+                cb(callbackdata, origdir, name);
+        } /* for */
+    } /* if */
+    else
+    {
+        for (i = 0; i < max; i++, entry++)
+        {
+            name = entry->name;
+            sep = strchr(name, '/');
+            if (sep != NULL)
+            {
+                if (strncmp(dname, name, (sep - name)) == 0)
+                    cb(callbackdata, origdir, sep + 1);
+            } /* if */
+        } /* for */
+    } /* else */
+} /* WAD_enumerateFiles */
+
+
+static WADentry *wad_find_entry(WADinfo *info, const char *name)
+{
+    WADentry *a = info->entries;
+    PHYSFS_sint32 lo = 0;
+    PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
+    PHYSFS_sint32 middle;
+    int rc;
+
+    while (lo <= hi)
+    {
+        middle = lo + ((hi - lo) / 2);
+        rc = strcmp(name, a[middle].name);
+        if (rc == 0)  /* found it! */
+            return(&a[middle]);
+        else if (rc > 0)
+            lo = middle + 1;
+        else
+            hi = middle - 1;
+    } /* while */
+
+    BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
+} /* wad_find_entry */
+
+
+static int WAD_exists(dvoid *opaque, const char *name)
+{
+    return(wad_find_entry(((WADinfo *) opaque), name) != NULL);
+} /* WAD_exists */
+
+
+static int WAD_isDirectory(dvoid *opaque, const char *name, int *fileExists)
+{
+    WADentry *entry = wad_find_entry(((WADinfo *) opaque), name);
+    if (entry != NULL)
+    {
+        char *n;
+
+        *fileExists = 1;
+
+        /* Can't be a directory if it's a subdirectory. */
+        if (strchr(entry->name, '/') != NULL)
+            return(0);
+
+        /* Check if it matches "MAP??" or "E?M?" ... */
+        n = entry->name;
+        if ((n[0] == 'E' && n[2] == 'M') ||
+            (n[0] == 'M' && n[1] == 'A' && n[2] == 'P' && n[6] == 0))
+        {
+            return(1);
+        } /* if */
+        return(0);
+    } /* if */
+    else
+    {
+        *fileExists = 0;
+        return(0);
+    } /* else */
+} /* WAD_isDirectory */
+
+
+static int WAD_isSymLink(dvoid *opaque, const char *name, int *fileExists)
+{
+    *fileExists = WAD_exists(opaque, name);
+    return(0);  /* never symlinks in a wad. */
+} /* WAD_isSymLink */
+
+
+static PHYSFS_sint64 WAD_getLastModTime(dvoid *opaque,
+                                        const char *name,
+                                        int *fileExists)
+{
+    WADinfo *info = ((WADinfo *) opaque);
+    PHYSFS_sint64 retval = -1;
+
+    *fileExists = (wad_find_entry(info, name) != NULL);
+    if (*fileExists)  /* use time of WAD itself in the physical filesystem. */
+        retval = info->last_mod_time;
+
+    return(retval);
+} /* WAD_getLastModTime */
+
+
+static fvoid *WAD_openRead(dvoid *opaque, const char *fnm, int *fileExists)
+{
+    WADinfo *info = ((WADinfo *) opaque);
+    WADfileinfo *finfo;
+    WADentry *entry;
+
+    entry = wad_find_entry(info, fnm);
+    *fileExists = (entry != NULL);
+    BAIL_IF_MACRO(entry == NULL, NULL, NULL);
+
+    finfo = (WADfileinfo *) allocator.Malloc(sizeof (WADfileinfo));
+    BAIL_IF_MACRO(finfo == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+    finfo->handle = __PHYSFS_platformOpenRead(info->filename);
+    if ( (finfo->handle == NULL) ||
+         (!__PHYSFS_platformSeek(finfo->handle, entry->startPos)) )
+    {
+        allocator.Free(finfo);
+        return(NULL);
+    } /* if */
+
+    finfo->curPos = 0;
+    finfo->entry = entry;
+    return(finfo);
+} /* WAD_openRead */
+
+
+static fvoid *WAD_openWrite(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* WAD_openWrite */
+
+
+static fvoid *WAD_openAppend(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* WAD_openAppend */
+
+
+static int WAD_remove(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* WAD_remove */
+
+
+static int WAD_mkdir(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* WAD_mkdir */
+
+
+const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_WAD =
+{
+    "WAD",
+    WAD_ARCHIVE_DESCRIPTION,
+    "Travis Wells <[email protected]>",
+    "http://www.3dmm2.com/doom/",
+};
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_WAD =
+{
+    &__PHYSFS_ArchiveInfo_WAD,
+    WAD_isArchive,          /* isArchive() method      */
+    WAD_openArchive,        /* openArchive() method    */
+    WAD_enumerateFiles,     /* enumerateFiles() method */
+    WAD_exists,             /* exists() method         */
+    WAD_isDirectory,        /* isDirectory() method    */
+    WAD_isSymLink,          /* isSymLink() method      */
+    WAD_getLastModTime,     /* getLastModTime() method */
+    WAD_openRead,           /* openRead() method       */
+    WAD_openWrite,          /* openWrite() method      */
+    WAD_openAppend,         /* openAppend() method     */
+    WAD_remove,             /* remove() method         */
+    WAD_mkdir,              /* mkdir() method          */
+    WAD_dirClose,           /* dirClose() method       */
+    WAD_read,               /* read() method           */
+    WAD_write,              /* write() method          */
+    WAD_eof,                /* eof() method            */
+    WAD_tell,               /* tell() method           */
+    WAD_seek,               /* seek() method           */
+    WAD_fileLength,         /* fileLength() method     */
+    WAD_fileClose           /* fileClose() method      */
+};
+
+#endif  /* defined PHYSFS_SUPPORTS_WAD */
+
+/* end of wad.c ... */
+

+ 1472 - 0
libs/physfs-2.0.3/archivers/zip.c

@@ -0,0 +1,1472 @@
+/*
+ * ZIP support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon, with some peeking at "unzip.c"
+ *   by Gilles Vollant.
+ */
+
+#if (defined PHYSFS_SUPPORTS_ZIP)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef _WIN32_WCE
+#include <errno.h>
+#include <time.h>
+#endif
+#include "physfs.h"
+#include "zlib.h"
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+/*
+ * A buffer of ZIP_READBUFSIZE is allocated for each compressed file opened,
+ *  and is freed when you close the file; compressed data is read into
+ *  this buffer, and then is decompressed into the buffer passed to
+ *  PHYSFS_read().
+ *
+ * Uncompressed entries in a zipfile do not allocate this buffer; they just
+ *  read data directly into the buffer passed to PHYSFS_read().
+ *
+ * Depending on your speed and memory requirements, you should tweak this
+ *  value.
+ */
+#define ZIP_READBUFSIZE   (16 * 1024)
+
+
+/*
+ * Entries are "unresolved" until they are first opened. At that time,
+ *  local file headers parsed/validated, data offsets will be updated to look
+ *  at the actual file data instead of the header, and symlinks will be
+ *  followed and optimized. This means that we don't seek and read around the
+ *  archive until forced to do so, and after the first time, we had to do
+ *  less reading and parsing, which is very CD-ROM friendly.
+ */
+typedef enum
+{
+    ZIP_UNRESOLVED_FILE,
+    ZIP_UNRESOLVED_SYMLINK,
+    ZIP_RESOLVING,
+    ZIP_RESOLVED,
+    ZIP_BROKEN_FILE,
+    ZIP_BROKEN_SYMLINK
+} ZipResolveType;
+
+
+/*
+ * One ZIPentry is kept for each file in an open ZIP archive.
+ */
+typedef struct _ZIPentry
+{
+    char *name;                         /* Name of file in archive        */
+    struct _ZIPentry *symlink;          /* NULL or file we symlink to     */
+    ZipResolveType resolved;            /* Have we resolved file/symlink? */
+    PHYSFS_uint32 offset;               /* offset of data in archive      */
+    PHYSFS_uint16 version;              /* version made by                */
+    PHYSFS_uint16 version_needed;       /* version needed to extract      */
+    PHYSFS_uint16 compression_method;   /* compression method             */
+    PHYSFS_uint32 crc;                  /* crc-32                         */
+    PHYSFS_uint32 compressed_size;      /* compressed size                */
+    PHYSFS_uint32 uncompressed_size;    /* uncompressed size              */
+    PHYSFS_sint64 last_mod_time;        /* last file mod time             */
+} ZIPentry;
+
+/*
+ * One ZIPinfo is kept for each open ZIP archive.
+ */
+typedef struct
+{
+    char *archiveName;        /* path to ZIP in platform-dependent notation. */
+    PHYSFS_uint16 entryCount; /* Number of files in ZIP.                     */
+    ZIPentry *entries;        /* info on all files in ZIP.                   */
+} ZIPinfo;
+
+/*
+ * One ZIPfileinfo is kept for each open file in a ZIP archive.
+ */
+typedef struct
+{
+    ZIPentry *entry;                      /* Info on file.              */
+    void *handle;                         /* physical file handle.      */
+    PHYSFS_uint32 compressed_position;    /* offset in compressed data. */
+    PHYSFS_uint32 uncompressed_position;  /* tell() position.           */
+    PHYSFS_uint8 *buffer;                 /* decompression buffer.      */
+    z_stream stream;                      /* zlib stream state.         */
+} ZIPfileinfo;
+
+
+/* Magic numbers... */
+#define ZIP_LOCAL_FILE_SIG          0x04034b50
+#define ZIP_CENTRAL_DIR_SIG         0x02014b50
+#define ZIP_END_OF_CENTRAL_DIR_SIG  0x06054b50
+
+/* compression methods... */
+#define COMPMETH_NONE 0
+/* ...and others... */
+
+
+#define UNIX_FILETYPE_MASK    0170000
+#define UNIX_FILETYPE_SYMLINK 0120000
+
+
+/*
+ * Bridge physfs allocation functions to zlib's format...
+ */
+static voidpf zlibPhysfsAlloc(voidpf opaque, uInt items, uInt size)
+{
+    return(((PHYSFS_Allocator *) opaque)->Malloc(items * size));
+} /* zlibPhysfsAlloc */
+
+/*
+ * Bridge physfs allocation functions to zlib's format...
+ */
+static void zlibPhysfsFree(voidpf opaque, voidpf address)
+{
+    ((PHYSFS_Allocator *) opaque)->Free(address);
+} /* zlibPhysfsFree */
+
+
+/*
+ * Construct a new z_stream to a sane state.
+ */
+static void initializeZStream(z_stream *pstr)
+{
+    memset(pstr, '\0', sizeof (z_stream));
+    pstr->zalloc = zlibPhysfsAlloc;
+    pstr->zfree = zlibPhysfsFree;
+    pstr->opaque = &allocator;
+} /* initializeZStream */
+
+
+static const char *zlib_error_string(int rc)
+{
+    switch (rc)
+    {
+        case Z_OK: return(NULL);  /* not an error. */
+        case Z_STREAM_END: return(NULL); /* not an error. */
+#ifndef _WIN32_WCE
+        case Z_ERRNO: return(strerror(errno));
+#endif
+        case Z_NEED_DICT: return(ERR_NEED_DICT);
+        case Z_DATA_ERROR: return(ERR_DATA_ERROR);
+        case Z_MEM_ERROR: return(ERR_MEMORY_ERROR);
+        case Z_BUF_ERROR: return(ERR_BUFFER_ERROR);
+        case Z_VERSION_ERROR: return(ERR_VERSION_ERROR);
+        default: return(ERR_UNKNOWN_ERROR);
+    } /* switch */
+
+    return(NULL);
+} /* zlib_error_string */
+
+
+/*
+ * Wrap all zlib calls in this, so the physfs error state is set appropriately.
+ */
+static int zlib_err(int rc)
+{
+    const char *str = zlib_error_string(rc);
+    if (str != NULL)
+        __PHYSFS_setError(str);
+    return(rc);
+} /* zlib_err */
+
+
+/*
+ * Read an unsigned 32-bit int and swap to native byte order.
+ */
+static int readui32(void *in, PHYSFS_uint32 *val)
+{
+    PHYSFS_uint32 v;
+    BAIL_IF_MACRO(__PHYSFS_platformRead(in, &v, sizeof (v), 1) != 1, NULL, 0);
+    *val = PHYSFS_swapULE32(v);
+    return(1);
+} /* readui32 */
+
+
+/*
+ * Read an unsigned 16-bit int and swap to native byte order.
+ */
+static int readui16(void *in, PHYSFS_uint16 *val)
+{
+    PHYSFS_uint16 v;
+    BAIL_IF_MACRO(__PHYSFS_platformRead(in, &v, sizeof (v), 1) != 1, NULL, 0);
+    *val = PHYSFS_swapULE16(v);
+    return(1);
+} /* readui16 */
+
+
+static PHYSFS_sint64 ZIP_read(fvoid *opaque, void *buf,
+                              PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    ZIPfileinfo *finfo = (ZIPfileinfo *) opaque;
+    ZIPentry *entry = finfo->entry;
+    PHYSFS_sint64 retval = 0;
+    PHYSFS_sint64 maxread = ((PHYSFS_sint64) objSize) * objCount;
+    PHYSFS_sint64 avail = entry->uncompressed_size -
+                          finfo->uncompressed_position;
+
+    BAIL_IF_MACRO(maxread == 0, NULL, 0);    /* quick rejection. */
+
+    if (avail < maxread)
+    {
+        maxread = avail - (avail % objSize);
+        objCount = (PHYSFS_uint32) (maxread / objSize);
+        BAIL_IF_MACRO(objCount == 0, ERR_PAST_EOF, 0);  /* quick rejection. */
+        __PHYSFS_setError(ERR_PAST_EOF);   /* this is always true here. */
+    } /* if */
+
+    if (entry->compression_method == COMPMETH_NONE)
+    {
+        retval = __PHYSFS_platformRead(finfo->handle, buf, objSize, objCount);
+    } /* if */
+
+    else
+    {
+        finfo->stream.next_out = buf;
+        finfo->stream.avail_out = objSize * objCount;
+
+        while (retval < maxread)
+        {
+            PHYSFS_uint32 before = finfo->stream.total_out;
+            int rc;
+
+            if (finfo->stream.avail_in == 0)
+            {
+                PHYSFS_sint64 br;
+
+                br = entry->compressed_size - finfo->compressed_position;
+                if (br > 0)
+                {
+                    if (br > ZIP_READBUFSIZE)
+                        br = ZIP_READBUFSIZE;
+
+                    br = __PHYSFS_platformRead(finfo->handle,
+                                               finfo->buffer,
+                                               1, (PHYSFS_uint32) br);
+                    if (br <= 0)
+                        break;
+
+                    finfo->compressed_position += (PHYSFS_uint32) br;
+                    finfo->stream.next_in = finfo->buffer;
+                    finfo->stream.avail_in = (PHYSFS_uint32) br;
+                } /* if */
+            } /* if */
+
+            rc = zlib_err(inflate(&finfo->stream, Z_SYNC_FLUSH));
+            retval += (finfo->stream.total_out - before);
+
+            if (rc != Z_OK)
+                break;
+        } /* while */
+
+        retval /= objSize;
+    } /* else */
+
+    if (retval > 0)
+        finfo->uncompressed_position += (PHYSFS_uint32) (retval * objSize);
+
+    return(retval);
+} /* ZIP_read */
+
+
+static PHYSFS_sint64 ZIP_write(fvoid *opaque, const void *buf,
+                               PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, -1);
+} /* ZIP_write */
+
+
+static int ZIP_eof(fvoid *opaque)
+{
+    ZIPfileinfo *finfo = (ZIPfileinfo *) opaque;
+    return(finfo->uncompressed_position >= finfo->entry->uncompressed_size);
+} /* ZIP_eof */
+
+
+static PHYSFS_sint64 ZIP_tell(fvoid *opaque)
+{
+    return(((ZIPfileinfo *) opaque)->uncompressed_position);
+} /* ZIP_tell */
+
+
+static int ZIP_seek(fvoid *opaque, PHYSFS_uint64 offset)
+{
+    ZIPfileinfo *finfo = (ZIPfileinfo *) opaque;
+    ZIPentry *entry = finfo->entry;
+    void *in = finfo->handle;
+
+    BAIL_IF_MACRO(offset > entry->uncompressed_size, ERR_PAST_EOF, 0);
+
+    if (entry->compression_method == COMPMETH_NONE)
+    {
+        PHYSFS_sint64 newpos = offset + entry->offset;
+        BAIL_IF_MACRO(!__PHYSFS_platformSeek(in, newpos), NULL, 0);
+        finfo->uncompressed_position = (PHYSFS_uint32) offset;
+    } /* if */
+
+    else
+    {
+        /*
+         * If seeking backwards, we need to redecode the file
+         *  from the start and throw away the compressed bits until we hit
+         *  the offset we need. If seeking forward, we still need to
+         *  decode, but we don't rewind first.
+         */
+        if (offset < finfo->uncompressed_position)
+        {
+            /* we do a copy so state is sane if inflateInit2() fails. */
+            z_stream str;
+            initializeZStream(&str);
+            if (zlib_err(inflateInit2(&str, -MAX_WBITS)) != Z_OK)
+                return(0);
+
+            if (!__PHYSFS_platformSeek(in, entry->offset))
+                return(0);
+
+            inflateEnd(&finfo->stream);
+            memcpy(&finfo->stream, &str, sizeof (z_stream));
+            finfo->uncompressed_position = finfo->compressed_position = 0;
+        } /* if */
+
+        while (finfo->uncompressed_position != offset)
+        {
+            PHYSFS_uint8 buf[512];
+            PHYSFS_uint32 maxread;
+
+            maxread = (PHYSFS_uint32) (offset - finfo->uncompressed_position);
+            if (maxread > sizeof (buf))
+                maxread = sizeof (buf);
+
+            if (ZIP_read(finfo, buf, maxread, 1) != 1)
+                return(0);
+        } /* while */
+    } /* else */
+
+    return(1);
+} /* ZIP_seek */
+
+
+static PHYSFS_sint64 ZIP_fileLength(fvoid *opaque)
+{
+    ZIPfileinfo *finfo = (ZIPfileinfo *) opaque;
+    return(finfo->entry->uncompressed_size);
+} /* ZIP_fileLength */
+
+
+static int ZIP_fileClose(fvoid *opaque)
+{
+    ZIPfileinfo *finfo = (ZIPfileinfo *) opaque;
+    BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0);
+
+    if (finfo->entry->compression_method != COMPMETH_NONE)
+        inflateEnd(&finfo->stream);
+
+    if (finfo->buffer != NULL)
+        allocator.Free(finfo->buffer);
+
+    allocator.Free(finfo);
+    return(1);
+} /* ZIP_fileClose */
+
+
+static PHYSFS_sint64 zip_find_end_of_central_dir(void *in, PHYSFS_sint64 *len)
+{
+    PHYSFS_uint8 buf[256];
+    PHYSFS_uint8 extra[4] = { 0, 0, 0, 0 };
+    PHYSFS_sint32 i = 0;
+    PHYSFS_sint64 filelen;
+    PHYSFS_sint64 filepos;
+    PHYSFS_sint32 maxread;
+    PHYSFS_sint32 totalread = 0;
+    int found = 0;
+
+    filelen = __PHYSFS_platformFileLength(in);
+    BAIL_IF_MACRO(filelen == -1, NULL, 0);  /* !!! FIXME: unlocalized string */
+    BAIL_IF_MACRO(filelen > 0xFFFFFFFF, "ZIP bigger than 2 gigs?!", 0);
+
+    /*
+     * Jump to the end of the file and start reading backwards.
+     *  The last thing in the file is the zipfile comment, which is variable
+     *  length, and the field that specifies its size is before it in the
+     *  file (argh!)...this means that we need to scan backwards until we
+     *  hit the end-of-central-dir signature. We can then sanity check that
+     *  the comment was as big as it should be to make sure we're in the
+     *  right place. The comment length field is 16 bits, so we can stop
+     *  searching for that signature after a little more than 64k at most,
+     *  and call it a corrupted zipfile.
+     */
+
+    if (sizeof (buf) < filelen)
+    {
+        filepos = filelen - sizeof (buf);
+        maxread = sizeof (buf);
+    } /* if */
+    else
+    {
+        filepos = 0;
+        maxread = (PHYSFS_uint32) filelen;
+    } /* else */
+
+    while ((totalread < filelen) && (totalread < 65557))
+    {
+        BAIL_IF_MACRO(!__PHYSFS_platformSeek(in, filepos), NULL, -1);
+
+        /* make sure we catch a signature between buffers. */
+        if (totalread != 0)
+        {
+            if (__PHYSFS_platformRead(in, buf, maxread - 4, 1) != 1)
+                return(-1);
+            memcpy(&buf[maxread - 4], &extra, sizeof (extra));
+            totalread += maxread - 4;
+        } /* if */
+        else
+        {
+            if (__PHYSFS_platformRead(in, buf, maxread, 1) != 1)
+                return(-1);
+            totalread += maxread;
+        } /* else */
+
+        memcpy(&extra, buf, sizeof (extra));
+
+        for (i = maxread - 4; i > 0; i--)
+        {
+            if ((buf[i + 0] == 0x50) &&
+                (buf[i + 1] == 0x4B) &&
+                (buf[i + 2] == 0x05) &&
+                (buf[i + 3] == 0x06) )
+            {
+                found = 1;  /* that's the signature! */
+                break;  
+            } /* if */
+        } /* for */
+
+        if (found)
+            break;
+
+        filepos -= (maxread - 4);
+        if (filepos < 0)
+            filepos = 0;
+    } /* while */
+
+    BAIL_IF_MACRO(!found, ERR_NOT_AN_ARCHIVE, -1);
+
+    if (len != NULL)
+        *len = filelen;
+
+    return(filepos + i);
+} /* zip_find_end_of_central_dir */
+
+
+static int ZIP_isArchive(const char *filename, int forWriting)
+{
+    PHYSFS_uint32 sig;
+    int retval = 0;
+    void *in;
+
+    in = __PHYSFS_platformOpenRead(filename);
+    BAIL_IF_MACRO(in == NULL, NULL, 0);
+
+    /*
+     * The first thing in a zip file might be the signature of the
+     *  first local file record, so it makes for a quick determination.
+     */
+    if (readui32(in, &sig))
+    {
+        retval = (sig == ZIP_LOCAL_FILE_SIG);
+        if (!retval)
+        {
+            /*
+             * No sig...might be a ZIP with data at the start
+             *  (a self-extracting executable, etc), so we'll have to do
+             *  it the hard way...
+             */
+            retval = (zip_find_end_of_central_dir(in, NULL) != -1);
+        } /* if */
+    } /* if */
+
+    __PHYSFS_platformClose(in);
+    return(retval);
+} /* ZIP_isArchive */
+
+
+static void zip_free_entries(ZIPentry *entries, PHYSFS_uint32 max)
+{
+    PHYSFS_uint32 i;
+    for (i = 0; i < max; i++)
+    {
+        ZIPentry *entry = &entries[i];
+        if (entry->name != NULL)
+            allocator.Free(entry->name);
+    } /* for */
+
+    allocator.Free(entries);
+} /* zip_free_entries */
+
+
+/*
+ * This will find the ZIPentry associated with a path in platform-independent
+ *  notation. Directories don't have ZIPentries associated with them, but 
+ *  (*isDir) will be set to non-zero if a dir was hit.
+ */
+static ZIPentry *zip_find_entry(ZIPinfo *info, const char *path, int *isDir)
+{
+    ZIPentry *a = info->entries;
+    PHYSFS_sint32 pathlen = 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 = strncmp(path, thispath, pathlen);
+
+        if (rc > 0)
+            lo = middle + 1;
+
+        else if (rc < 0)
+            hi = middle - 1;
+
+        else /* substring match...might be dir or entry or nothing. */
+        {
+            int i;
+
+            if (isDir != NULL)
+            {
+                *isDir = (thispath[pathlen] == '/');
+                if (*isDir)
+                    return(NULL);
+            } /* if */
+
+            if (thispath[pathlen] == '\0') /* found entry? */
+                return(&a[middle]);
+
+            /* substring match; search remaining space to find it... */
+            for (i = lo; i < hi; i++)
+            {
+                thispath = a[i].name;
+                if (strncmp(path, thispath, pathlen) == 0)
+                {
+                    if (isDir != NULL)
+                    {
+                        *isDir = (thispath[pathlen] == '/');
+                        if (*isDir)
+                            return(NULL);
+                    } /* if */
+
+                    if (thispath[pathlen] == '\0') /* found entry? */
+                        return(&a[i]);
+                } /* if */
+            } /* for */
+            break;
+
+        } /* else */
+    } /* while */
+
+    if (isDir != NULL)
+        *isDir = 0;
+
+    BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
+} /* zip_find_entry */
+
+
+/* Convert paths from old, buggy DOS zippers... */
+static void zip_convert_dos_path(ZIPentry *entry, char *path)
+{
+    PHYSFS_uint8 hosttype = (PHYSFS_uint8) ((entry->version >> 8) & 0xFF);
+    if (hosttype == 0)  /* FS_FAT_ */
+    {
+        while (*path)
+        {
+            if (*path == '\\')
+                *path = '/';
+            path++;
+        } /* while */
+    } /* if */
+} /* zip_convert_dos_path */
+
+
+static void zip_expand_symlink_path(char *path)
+{
+    char *ptr = path;
+    char *prevptr = path;
+
+    while (1)
+    {
+        ptr = strchr(ptr, '/');
+        if (ptr == NULL)
+            break;
+
+        if (*(ptr + 1) == '.')
+        {
+            if (*(ptr + 2) == '/')
+            {
+                /* current dir in middle of string: ditch it. */
+                memmove(ptr, ptr + 2, strlen(ptr + 2) + 1);
+            } /* else if */
+
+            else if (*(ptr + 2) == '\0')
+            {
+                /* current dir at end of string: ditch it. */
+                *ptr = '\0';
+            } /* else if */
+
+            else if (*(ptr + 2) == '.')
+            {
+                if (*(ptr + 3) == '/')
+                {
+                    /* parent dir in middle: move back one, if possible. */
+                    memmove(prevptr, ptr + 4, strlen(ptr + 4) + 1);
+                    ptr = prevptr;
+                    while (prevptr != path)
+                    {
+                        prevptr--;
+                        if (*prevptr == '/')
+                        {
+                            prevptr++;
+                            break;
+                        } /* if */
+                    } /* while */
+                } /* if */
+
+                if (*(ptr + 3) == '\0')
+                {
+                    /* parent dir at end: move back one, if possible. */
+                    *prevptr = '\0';
+                } /* if */
+            } /* if */
+        } /* if */
+        else
+        {
+            prevptr = ptr;
+            ptr++;
+        } /* else */
+    } /* while */
+} /* zip_expand_symlink_path */
+
+/* (forward reference: zip_follow_symlink and zip_resolve call each other.) */
+static int zip_resolve(void *in, ZIPinfo *info, ZIPentry *entry);
+
+/*
+ * Look for the entry named by (path). If it exists, resolve it, and return
+ *  a pointer to that entry. If it's another symlink, keep resolving until you
+ *  hit a real file and then return a pointer to the final non-symlink entry.
+ *  If there's a problem, return NULL. (path) is always free()'d by this
+ *  function.
+ */
+static ZIPentry *zip_follow_symlink(void *in, ZIPinfo *info, char *path)
+{
+    ZIPentry *entry;
+
+    zip_expand_symlink_path(path);
+    entry = zip_find_entry(info, path, NULL);
+    if (entry != NULL)
+    {
+        if (!zip_resolve(in, info, entry))  /* recursive! */
+            entry = NULL;
+        else
+        {
+            if (entry->symlink != NULL)
+                entry = entry->symlink;
+        } /* else */
+    } /* if */
+
+    allocator.Free(path);
+    return(entry);
+} /* zip_follow_symlink */
+
+
+static int zip_resolve_symlink(void *in, ZIPinfo *info, ZIPentry *entry)
+{
+    char *path;
+    PHYSFS_uint32 size = entry->uncompressed_size;
+    int rc = 0;
+
+    /*
+     * We've already parsed the local file header of the symlink at this
+     *  point. Now we need to read the actual link from the file data and
+     *  follow it.
+     */
+
+    BAIL_IF_MACRO(!__PHYSFS_platformSeek(in, entry->offset), NULL, 0);
+
+    path = (char *) allocator.Malloc(size + 1);
+    BAIL_IF_MACRO(path == NULL, ERR_OUT_OF_MEMORY, 0);
+    
+    if (entry->compression_method == COMPMETH_NONE)
+        rc = (__PHYSFS_platformRead(in, path, size, 1) == 1);
+
+    else  /* symlink target path is compressed... */
+    {
+        z_stream stream;
+        PHYSFS_uint32 complen = entry->compressed_size;
+        PHYSFS_uint8 *compressed = (PHYSFS_uint8*) __PHYSFS_smallAlloc(complen);
+        if (compressed != NULL)
+        {
+            if (__PHYSFS_platformRead(in, compressed, complen, 1) == 1)
+            {
+                initializeZStream(&stream);
+                stream.next_in = compressed;
+                stream.avail_in = complen;
+                stream.next_out = (unsigned char *) path;
+                stream.avail_out = size;
+                if (zlib_err(inflateInit2(&stream, -MAX_WBITS)) == Z_OK)
+                {
+                    rc = zlib_err(inflate(&stream, Z_FINISH));
+                    inflateEnd(&stream);
+
+                    /* both are acceptable outcomes... */
+                    rc = ((rc == Z_OK) || (rc == Z_STREAM_END));
+                } /* if */
+            } /* if */
+            __PHYSFS_smallFree(compressed);
+        } /* if */
+    } /* else */
+
+    if (!rc)
+        allocator.Free(path);
+    else
+    {
+        path[entry->uncompressed_size] = '\0';    /* null-terminate it. */
+        zip_convert_dos_path(entry, path);
+        entry->symlink = zip_follow_symlink(in, info, path);
+    } /* else */
+
+    return(entry->symlink != NULL);
+} /* zip_resolve_symlink */
+
+
+/*
+ * Parse the local file header of an entry, and update entry->offset.
+ */
+static int zip_parse_local(void *in, ZIPentry *entry)
+{
+    PHYSFS_uint32 ui32;
+    PHYSFS_uint16 ui16;
+    PHYSFS_uint16 fnamelen;
+    PHYSFS_uint16 extralen;
+
+    /*
+     * crc and (un)compressed_size are always zero if this is a "JAR"
+     *  archive created with Sun's Java tools, apparently. We only
+     *  consider this archive corrupted if those entries don't match and
+     *  aren't zero. That seems to work well.
+     */
+
+    BAIL_IF_MACRO(!__PHYSFS_platformSeek(in, entry->offset), NULL, 0);
+    BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0);
+    BAIL_IF_MACRO(ui32 != ZIP_LOCAL_FILE_SIG, ERR_CORRUPTED, 0);
+    BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);
+    BAIL_IF_MACRO(ui16 != entry->version_needed, ERR_CORRUPTED, 0);
+    BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);  /* general bits. */
+    BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);
+    BAIL_IF_MACRO(ui16 != entry->compression_method, ERR_CORRUPTED, 0);
+    BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0);  /* date/time */
+    BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0);
+    BAIL_IF_MACRO(ui32 && (ui32 != entry->crc), ERR_CORRUPTED, 0);
+    BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0);
+    BAIL_IF_MACRO(ui32 && (ui32 != entry->compressed_size), ERR_CORRUPTED, 0);
+    BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0);
+    BAIL_IF_MACRO(ui32 && (ui32 != entry->uncompressed_size),ERR_CORRUPTED,0);
+    BAIL_IF_MACRO(!readui16(in, &fnamelen), NULL, 0);
+    BAIL_IF_MACRO(!readui16(in, &extralen), NULL, 0);
+
+    entry->offset += fnamelen + extralen + 30;
+    return(1);
+} /* zip_parse_local */
+
+
+static int zip_resolve(void *in, ZIPinfo *info, ZIPentry *entry)
+{
+    int retval = 1;
+    ZipResolveType resolve_type = entry->resolved;
+
+    /* Don't bother if we've failed to resolve this entry before. */
+    BAIL_IF_MACRO(resolve_type == ZIP_BROKEN_FILE, ERR_CORRUPTED, 0);
+    BAIL_IF_MACRO(resolve_type == ZIP_BROKEN_SYMLINK, ERR_CORRUPTED, 0);
+
+    /* uhoh...infinite symlink loop! */
+    BAIL_IF_MACRO(resolve_type == ZIP_RESOLVING, ERR_SYMLINK_LOOP, 0);
+
+    /*
+     * We fix up the offset to point to the actual data on the
+     *  first open, since we don't want to seek across the whole file on
+     *  archive open (can be SLOW on large, CD-stored files), but we
+     *  need to check the local file header...not just for corruption,
+     *  but since it stores offset info the central directory does not.
+     */
+    if (resolve_type != ZIP_RESOLVED)
+    {
+        entry->resolved = ZIP_RESOLVING;
+
+        retval = zip_parse_local(in, entry);
+        if (retval)
+        {
+            /*
+             * If it's a symlink, find the original file. This will cause
+             *  resolution of other entries (other symlinks and, eventually,
+             *  the real file) if all goes well.
+             */
+            if (resolve_type == ZIP_UNRESOLVED_SYMLINK)
+                retval = zip_resolve_symlink(in, info, entry);
+        } /* if */
+
+        if (resolve_type == ZIP_UNRESOLVED_SYMLINK)
+            entry->resolved = ((retval) ? ZIP_RESOLVED : ZIP_BROKEN_SYMLINK);
+        else if (resolve_type == ZIP_UNRESOLVED_FILE)
+            entry->resolved = ((retval) ? ZIP_RESOLVED : ZIP_BROKEN_FILE);
+    } /* if */
+
+    return(retval);
+} /* zip_resolve */
+
+
+static int zip_version_does_symlinks(PHYSFS_uint32 version)
+{
+    int retval = 0;
+    PHYSFS_uint8 hosttype = (PHYSFS_uint8) ((version >> 8) & 0xFF);
+
+    switch (hosttype)
+    {
+            /*
+             * These are the platforms that can NOT build an archive with
+             *  symlinks, according to the Info-ZIP project.
+             */
+        case 0:  /* FS_FAT_  */
+        case 1:  /* AMIGA_   */
+        case 2:  /* VMS_     */
+        case 4:  /* VM_CSM_  */
+        case 6:  /* FS_HPFS_ */
+        case 11: /* FS_NTFS_ */
+        case 14: /* FS_VFAT_ */
+        case 13: /* ACORN_   */
+        case 15: /* MVS_     */
+        case 18: /* THEOS_   */
+            break;  /* do nothing. */
+
+        default:  /* assume the rest to be unix-like. */
+            retval = 1;
+            break;
+    } /* switch */
+
+    return(retval);
+} /* zip_version_does_symlinks */
+
+
+static int zip_entry_is_symlink(const ZIPentry *entry)
+{
+    return((entry->resolved == ZIP_UNRESOLVED_SYMLINK) ||
+           (entry->resolved == ZIP_BROKEN_SYMLINK) ||
+           (entry->symlink));
+} /* zip_entry_is_symlink */
+
+
+static int zip_has_symlink_attr(ZIPentry *entry, PHYSFS_uint32 extern_attr)
+{
+    PHYSFS_uint16 xattr = ((extern_attr >> 16) & 0xFFFF);
+
+    return (
+              (zip_version_does_symlinks(entry->version)) &&
+              (entry->uncompressed_size > 0) &&
+              ((xattr & UNIX_FILETYPE_MASK) == UNIX_FILETYPE_SYMLINK)
+           );
+} /* zip_has_symlink_attr */
+
+
+static PHYSFS_sint64 zip_dos_time_to_physfs_time(PHYSFS_uint32 dostime)
+{
+#ifdef _WIN32_WCE
+    /* We have no struct tm and no mktime right now.
+       FIXME: This should probably be fixed at some point.
+    */
+    return -1;
+#else
+    PHYSFS_uint32 dosdate;
+    struct tm unixtime;
+    memset(&unixtime, '\0', sizeof (unixtime));
+
+    dosdate = (PHYSFS_uint32) ((dostime >> 16) & 0xFFFF);
+    dostime &= 0xFFFF;
+
+    /* dissect date */
+    unixtime.tm_year = ((dosdate >> 9) & 0x7F) + 80;
+    unixtime.tm_mon  = ((dosdate >> 5) & 0x0F) - 1;
+    unixtime.tm_mday = ((dosdate     ) & 0x1F);
+
+    /* dissect time */
+    unixtime.tm_hour = ((dostime >> 11) & 0x1F);
+    unixtime.tm_min  = ((dostime >>  5) & 0x3F);
+    unixtime.tm_sec  = ((dostime <<  1) & 0x3E);
+
+    /* let mktime calculate daylight savings time. */
+    unixtime.tm_isdst = -1;
+
+    return((PHYSFS_sint64) mktime(&unixtime));
+#endif
+} /* zip_dos_time_to_physfs_time */
+
+
+static int zip_load_entry(void *in, ZIPentry *entry, PHYSFS_uint32 ofs_fixup)
+{
+    PHYSFS_uint16 fnamelen, extralen, commentlen;
+    PHYSFS_uint32 external_attr;
+    PHYSFS_uint16 ui16;
+    PHYSFS_uint32 ui32;
+    PHYSFS_sint64 si64;
+
+    /* sanity check with central directory signature... */
+    BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0);
+    BAIL_IF_MACRO(ui32 != ZIP_CENTRAL_DIR_SIG, ERR_CORRUPTED, 0);
+
+    /* Get the pertinent parts of the record... */
+    BAIL_IF_MACRO(!readui16(in, &entry->version), NULL, 0);
+    BAIL_IF_MACRO(!readui16(in, &entry->version_needed), NULL, 0);
+    BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);  /* general bits */
+    BAIL_IF_MACRO(!readui16(in, &entry->compression_method), NULL, 0);
+    BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0);
+    entry->last_mod_time = zip_dos_time_to_physfs_time(ui32);
+    BAIL_IF_MACRO(!readui32(in, &entry->crc), NULL, 0);
+    BAIL_IF_MACRO(!readui32(in, &entry->compressed_size), NULL, 0);
+    BAIL_IF_MACRO(!readui32(in, &entry->uncompressed_size), NULL, 0);
+    BAIL_IF_MACRO(!readui16(in, &fnamelen), NULL, 0);
+    BAIL_IF_MACRO(!readui16(in, &extralen), NULL, 0);
+    BAIL_IF_MACRO(!readui16(in, &commentlen), NULL, 0);
+    BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);  /* disk number start */
+    BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);  /* internal file attribs */
+    BAIL_IF_MACRO(!readui32(in, &external_attr), NULL, 0);
+    BAIL_IF_MACRO(!readui32(in, &entry->offset), NULL, 0);
+    entry->offset += ofs_fixup;
+
+    entry->symlink = NULL;  /* will be resolved later, if necessary. */
+    entry->resolved = (zip_has_symlink_attr(entry, external_attr)) ?
+                            ZIP_UNRESOLVED_SYMLINK : ZIP_UNRESOLVED_FILE;
+
+    entry->name = (char *) allocator.Malloc(fnamelen + 1);
+    BAIL_IF_MACRO(entry->name == NULL, ERR_OUT_OF_MEMORY, 0);
+    if (__PHYSFS_platformRead(in, entry->name, fnamelen, 1) != 1)
+        goto zip_load_entry_puked;
+
+    entry->name[fnamelen] = '\0';  /* null-terminate the filename. */
+    zip_convert_dos_path(entry, entry->name);
+
+    si64 = __PHYSFS_platformTell(in);
+    if (si64 == -1)
+        goto zip_load_entry_puked;
+
+        /* seek to the start of the next entry in the central directory... */
+    if (!__PHYSFS_platformSeek(in, si64 + extralen + commentlen))
+        goto zip_load_entry_puked;
+
+    return(1);  /* success. */
+
+zip_load_entry_puked:
+    allocator.Free(entry->name);
+    return(0);  /* failure. */
+} /* zip_load_entry */
+
+
+static int zip_entry_cmp(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
+{
+    if (one != two)
+    {
+        const ZIPentry *a = (const ZIPentry *) _a;
+        return(strcmp(a[one].name, a[two].name));
+    } /* if */
+
+    return 0;
+} /* zip_entry_cmp */
+
+
+static void zip_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
+{
+    if (one != two)
+    {
+        ZIPentry tmp;
+        ZIPentry *first = &(((ZIPentry *) _a)[one]);
+        ZIPentry *second = &(((ZIPentry *) _a)[two]);
+        memcpy(&tmp, first, sizeof (ZIPentry));
+        memcpy(first, second, sizeof (ZIPentry));
+        memcpy(second, &tmp, sizeof (ZIPentry));
+    } /* if */
+} /* zip_entry_swap */
+
+
+static int zip_load_entries(void *in, ZIPinfo *info,
+                            PHYSFS_uint32 data_ofs, PHYSFS_uint32 central_ofs)
+{
+    PHYSFS_uint32 max = info->entryCount;
+    PHYSFS_uint32 i;
+
+    BAIL_IF_MACRO(!__PHYSFS_platformSeek(in, central_ofs), NULL, 0);
+
+    info->entries = (ZIPentry *) allocator.Malloc(sizeof (ZIPentry) * max);
+    BAIL_IF_MACRO(info->entries == NULL, ERR_OUT_OF_MEMORY, 0);
+
+    for (i = 0; i < max; i++)
+    {
+        if (!zip_load_entry(in, &info->entries[i], data_ofs))
+        {
+            zip_free_entries(info->entries, i);
+            return(0);
+        } /* if */
+    } /* for */
+
+    __PHYSFS_sort(info->entries, max, zip_entry_cmp, zip_entry_swap);
+    return(1);
+} /* zip_load_entries */
+
+
+static int zip_parse_end_of_central_dir(void *in, ZIPinfo *info,
+                                        PHYSFS_uint32 *data_start,
+                                        PHYSFS_uint32 *central_dir_ofs)
+{
+    PHYSFS_uint32 ui32;
+    PHYSFS_uint16 ui16;
+    PHYSFS_sint64 len;
+    PHYSFS_sint64 pos;
+
+    /* find the end-of-central-dir record, and seek to it. */
+    pos = zip_find_end_of_central_dir(in, &len);
+    BAIL_IF_MACRO(pos == -1, NULL, 0);
+    BAIL_IF_MACRO(!__PHYSFS_platformSeek(in, pos), NULL, 0);
+
+    /* check signature again, just in case. */
+    BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0);
+    BAIL_IF_MACRO(ui32 != ZIP_END_OF_CENTRAL_DIR_SIG, ERR_NOT_AN_ARCHIVE, 0);
+
+    /* number of this disk */
+    BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);
+    BAIL_IF_MACRO(ui16 != 0, ERR_UNSUPPORTED_ARCHIVE, 0);
+
+    /* number of the disk with the start of the central directory */
+    BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);
+    BAIL_IF_MACRO(ui16 != 0, ERR_UNSUPPORTED_ARCHIVE, 0);
+
+    /* total number of entries in the central dir on this disk */
+    BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);
+
+    /* total number of entries in the central dir */
+    BAIL_IF_MACRO(!readui16(in, &info->entryCount), NULL, 0);
+    BAIL_IF_MACRO(ui16 != info->entryCount, ERR_UNSUPPORTED_ARCHIVE, 0);
+
+    /* size of the central directory */
+    BAIL_IF_MACRO(!readui32(in, &ui32), NULL, 0);
+
+    /* offset of central directory */
+    BAIL_IF_MACRO(!readui32(in, central_dir_ofs), NULL, 0);
+    BAIL_IF_MACRO(pos < *central_dir_ofs + ui32, ERR_UNSUPPORTED_ARCHIVE, 0);
+
+    /*
+     * For self-extracting archives, etc, there's crapola in the file
+     *  before the zipfile records; we calculate how much data there is
+     *  prepended by determining how far the central directory offset is
+     *  from where it is supposed to be (start of end-of-central-dir minus
+     *  sizeof central dir)...the difference in bytes is how much arbitrary
+     *  data is at the start of the physical file.
+     */
+    *data_start = (PHYSFS_uint32) (pos - (*central_dir_ofs + ui32));
+
+    /* Now that we know the difference, fix up the central dir offset... */
+    *central_dir_ofs += *data_start;
+
+    /* zipfile comment length */
+    BAIL_IF_MACRO(!readui16(in, &ui16), NULL, 0);
+
+    /*
+     * Make sure that the comment length matches to the end of file...
+     *  If it doesn't, we're either in the wrong part of the file, or the
+     *  file is corrupted, but we give up either way.
+     */
+    BAIL_IF_MACRO((pos + 22 + ui16) != len, ERR_UNSUPPORTED_ARCHIVE, 0);
+
+    return(1);  /* made it. */
+} /* zip_parse_end_of_central_dir */
+
+
+static ZIPinfo *zip_create_zipinfo(const char *name)
+{
+    char *ptr;
+    ZIPinfo *info = (ZIPinfo *) allocator.Malloc(sizeof (ZIPinfo));
+    BAIL_IF_MACRO(info == NULL, ERR_OUT_OF_MEMORY, 0);
+    memset(info, '\0', sizeof (ZIPinfo));
+
+    ptr = (char *) allocator.Malloc(strlen(name) + 1);
+    if (ptr == NULL)
+    {
+        allocator.Free(info);
+        BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
+    } /* if */
+
+    info->archiveName = ptr;
+    strcpy(info->archiveName, name);
+    return(info);
+} /* zip_create_zipinfo */
+
+
+static void *ZIP_openArchive(const char *name, int forWriting)
+{
+    void *in = NULL;
+    ZIPinfo *info = NULL;
+    PHYSFS_uint32 data_start;
+    PHYSFS_uint32 cent_dir_ofs;
+
+    BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, NULL);
+
+    if ((in = __PHYSFS_platformOpenRead(name)) == NULL)
+        goto zip_openarchive_failed;
+    
+    if ((info = zip_create_zipinfo(name)) == NULL)
+        goto zip_openarchive_failed;
+
+    if (!zip_parse_end_of_central_dir(in, info, &data_start, &cent_dir_ofs))
+        goto zip_openarchive_failed;
+
+    if (!zip_load_entries(in, info, data_start, cent_dir_ofs))
+        goto zip_openarchive_failed;
+
+    __PHYSFS_platformClose(in);
+    return(info);
+
+zip_openarchive_failed:
+    if (info != NULL)
+    {
+        if (info->archiveName != NULL)
+            allocator.Free(info->archiveName);
+        allocator.Free(info);
+    } /* if */
+
+    if (in != NULL)
+        __PHYSFS_platformClose(in);
+
+    return(NULL);
+} /* ZIP_openArchive */
+
+
+static PHYSFS_sint32 zip_find_start_of_dir(ZIPinfo *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 = 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 = strncmp(path, name, dlen);
+        if (rc == 0)
+        {
+            char ch = name[dlen];
+            if ('/' < ch) /* make sure this isn't just a substr match. */
+                rc = -1;
+            else if ('/' > ch)
+                rc = 1;
+            else 
+            {
+                if (stop_on_first_find) /* Just checking dir's existance? */
+                    return(middle);
+
+                if (name[dlen + 1] == '\0') /* Skip initial dir entry. */
+                    return(middle + 1);
+
+                /* there might be more entries earlier in the list. */
+                retval = middle;
+                hi = middle - 1;
+            } /* else */
+        } /* if */
+
+        if (rc > 0)
+            lo = middle + 1;
+        else
+            hi = middle - 1;
+    } /* while */
+
+    return(retval);
+} /* zip_find_start_of_dir */
+
+
+/*
+ * Moved to seperate function so we can use alloca then immediately throw
+ *  away the allocated stack space...
+ */
+static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata,
+                           const char *odir, const char *str, PHYSFS_sint32 ln)
+{
+    char *newstr = __PHYSFS_smallAlloc(ln + 1);
+    if (newstr == NULL)
+        return;
+
+    memcpy(newstr, str, ln);
+    newstr[ln] = '\0';
+    cb(callbackdata, odir, newstr);
+    __PHYSFS_smallFree(newstr);
+} /* doEnumCallback */
+
+
+static void ZIP_enumerateFiles(dvoid *opaque, const char *dname,
+                               int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+                               const char *origdir, void *callbackdata)
+{
+    ZIPinfo *info = ((ZIPinfo *) opaque);
+    PHYSFS_sint32 dlen, dlen_inc, max, i;
+
+    i = zip_find_start_of_dir(info, dname, 0);
+    if (i == -1)  /* no such directory. */
+        return;
+
+    dlen = 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 *e = info->entries[i].name;
+        if ((dlen) && ((strncmp(e, dname, dlen) != 0) || (e[dlen] != '/')))
+            break;  /* past end of this dir; we're done. */
+
+        if ((omitSymLinks) && (zip_entry_is_symlink(&info->entries[i])))
+            i++;
+        else
+        {
+            char *add = e + dlen_inc;
+            char *ptr = strchr(add, '/');
+            PHYSFS_sint32 ln = (PHYSFS_sint32) ((ptr) ? ptr-add : strlen(add));
+            doEnumCallback(cb, callbackdata, origdir, add, ln);
+            ln += dlen_inc;  /* point past entry to children... */
+
+            /* increment counter and skip children of subdirs... */
+            while ((++i < max) && (ptr != NULL))
+            {
+                char *e_new = info->entries[i].name;
+                if ((strncmp(e, e_new, ln) != 0) || (e_new[ln] != '/'))
+                    break;
+            } /* while */
+        } /* else */
+    } /* while */
+} /* ZIP_enumerateFiles */
+
+
+static int ZIP_exists(dvoid *opaque, const char *name)
+{
+    int isDir;    
+    ZIPinfo *info = (ZIPinfo *) opaque;
+    ZIPentry *entry = zip_find_entry(info, name, &isDir);
+    return((entry != NULL) || (isDir));
+} /* ZIP_exists */
+
+
+static PHYSFS_sint64 ZIP_getLastModTime(dvoid *opaque,
+                                        const char *name,
+                                        int *fileExists)
+{
+    int isDir;
+    ZIPinfo *info = (ZIPinfo *) opaque;
+    ZIPentry *entry = zip_find_entry(info, name, &isDir);
+
+    *fileExists = ((isDir) || (entry != NULL));
+    if (isDir)
+        return(1);  /* Best I can do for a dir... */
+
+    BAIL_IF_MACRO(entry == NULL, NULL, -1);
+    return(entry->last_mod_time);
+} /* ZIP_getLastModTime */
+
+
+static int ZIP_isDirectory(dvoid *opaque, const char *name, int *fileExists)
+{
+    ZIPinfo *info = (ZIPinfo *) opaque;
+    int isDir;
+    ZIPentry *entry = zip_find_entry(info, name, &isDir);
+
+    *fileExists = ((isDir) || (entry != NULL));
+    if (isDir)
+        return(1); /* definitely a dir. */
+
+    /* Follow symlinks. This means we might need to resolve entries. */
+    BAIL_IF_MACRO(entry == NULL, ERR_NO_SUCH_FILE, 0);
+
+    if (entry->resolved == ZIP_UNRESOLVED_SYMLINK) /* gotta resolve it. */
+    {
+        int rc;
+        void *in = __PHYSFS_platformOpenRead(info->archiveName);
+        BAIL_IF_MACRO(in == NULL, NULL, 0);
+        rc = zip_resolve(in, info, entry);
+        __PHYSFS_platformClose(in);
+        if (!rc)
+            return(0);
+    } /* if */
+
+    BAIL_IF_MACRO(entry->resolved == ZIP_BROKEN_SYMLINK, NULL, 0);
+    BAIL_IF_MACRO(entry->symlink == NULL, ERR_NOT_A_DIR, 0);
+
+    return(zip_find_start_of_dir(info, entry->symlink->name, 1) >= 0);
+} /* ZIP_isDirectory */
+
+
+static int ZIP_isSymLink(dvoid *opaque, const char *name, int *fileExists)
+{
+    int isDir;
+    const ZIPentry *entry = zip_find_entry((ZIPinfo *) opaque, name, &isDir);
+    *fileExists = ((isDir) || (entry != NULL));
+    BAIL_IF_MACRO(entry == NULL, NULL, 0);
+    return(zip_entry_is_symlink(entry));
+} /* ZIP_isSymLink */
+
+
+static void *zip_get_file_handle(const char *fn, ZIPinfo *inf, ZIPentry *entry)
+{
+    int success;
+    void *retval = __PHYSFS_platformOpenRead(fn);
+    BAIL_IF_MACRO(retval == NULL, NULL, NULL);
+
+    success = zip_resolve(retval, inf, entry);
+    if (success)
+    {
+        PHYSFS_sint64 offset;
+        offset = ((entry->symlink) ? entry->symlink->offset : entry->offset);
+        success = __PHYSFS_platformSeek(retval, offset);
+    } /* if */
+
+    if (!success)
+    {
+        __PHYSFS_platformClose(retval);
+        retval = NULL;
+    } /* if */
+
+    return(retval);
+} /* zip_get_file_handle */
+
+
+static fvoid *ZIP_openRead(dvoid *opaque, const char *fnm, int *fileExists)
+{
+    ZIPinfo *info = (ZIPinfo *) opaque;
+    ZIPentry *entry = zip_find_entry(info, fnm, NULL);
+    ZIPfileinfo *finfo = NULL;
+    void *in;
+
+    *fileExists = (entry != NULL);
+    BAIL_IF_MACRO(entry == NULL, NULL, NULL);
+
+    in = zip_get_file_handle(info->archiveName, info, entry);
+    BAIL_IF_MACRO(in == NULL, NULL, NULL);
+
+    finfo = (ZIPfileinfo *) allocator.Malloc(sizeof (ZIPfileinfo));
+    if (finfo == NULL)
+    {
+        __PHYSFS_platformClose(in);
+        BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
+    } /* if */
+
+    memset(finfo, '\0', sizeof (ZIPfileinfo));
+    finfo->handle = in;
+    finfo->entry = ((entry->symlink != NULL) ? entry->symlink : entry);
+    initializeZStream(&finfo->stream);
+    if (finfo->entry->compression_method != COMPMETH_NONE)
+    {
+        if (zlib_err(inflateInit2(&finfo->stream, -MAX_WBITS)) != Z_OK)
+        {
+            ZIP_fileClose(finfo);
+            return(NULL);
+        } /* if */
+
+        finfo->buffer = (PHYSFS_uint8 *) allocator.Malloc(ZIP_READBUFSIZE);
+        if (finfo->buffer == NULL)
+        {
+            ZIP_fileClose(finfo);
+            BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
+        } /* if */
+    } /* if */
+
+    return(finfo);
+} /* ZIP_openRead */
+
+
+static fvoid *ZIP_openWrite(dvoid *opaque, const char *filename)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* ZIP_openWrite */
+
+
+static fvoid *ZIP_openAppend(dvoid *opaque, const char *filename)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* ZIP_openAppend */
+
+
+static void ZIP_dirClose(dvoid *opaque)
+{
+    ZIPinfo *zi = (ZIPinfo *) (opaque);
+    zip_free_entries(zi->entries, zi->entryCount);
+    allocator.Free(zi->archiveName);
+    allocator.Free(zi);
+} /* ZIP_dirClose */
+
+
+static int ZIP_remove(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* ZIP_remove */
+
+
+static int ZIP_mkdir(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
+} /* ZIP_mkdir */
+
+
+const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_ZIP =
+{
+    "ZIP",
+    ZIP_ARCHIVE_DESCRIPTION,
+    "Ryan C. Gordon <[email protected]>",
+    "http://icculus.org/physfs/",
+};
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_ZIP =
+{
+    &__PHYSFS_ArchiveInfo_ZIP,
+    ZIP_isArchive,          /* isArchive() method      */
+    ZIP_openArchive,        /* openArchive() method    */
+    ZIP_enumerateFiles,     /* enumerateFiles() method */
+    ZIP_exists,             /* exists() method         */
+    ZIP_isDirectory,        /* isDirectory() method    */
+    ZIP_isSymLink,          /* isSymLink() method      */
+    ZIP_getLastModTime,     /* getLastModTime() method */
+    ZIP_openRead,           /* openRead() method       */
+    ZIP_openWrite,          /* openWrite() method      */
+    ZIP_openAppend,         /* openAppend() method     */
+    ZIP_remove,             /* remove() method         */
+    ZIP_mkdir,              /* mkdir() method          */
+    ZIP_dirClose,           /* dirClose() method       */
+    ZIP_read,               /* read() method           */
+    ZIP_write,              /* write() method          */
+    ZIP_eof,                /* eof() method            */
+    ZIP_tell,               /* tell() method           */
+    ZIP_seek,               /* seek() method           */
+    ZIP_fileLength,         /* fileLength() method     */
+    ZIP_fileClose           /* fileClose() method      */
+};
+
+#endif  /* defined PHYSFS_SUPPORTS_ZIP */
+
+/* end of zip.c ... */
+

+ 58 - 0
libs/physfs-2.0.3/extras/PhysFS.NET/AssemblyInfo.cs

@@ -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
libs/physfs-2.0.3/extras/PhysFS.NET/PhysFS.NET.csproj

@@ -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
libs/physfs-2.0.3/extras/PhysFS.NET/PhysFS.NET.sln

@@ -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

+ 189 - 0
libs/physfs-2.0.3/extras/PhysFS.NET/PhysFS.cs

@@ -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
libs/physfs-2.0.3/extras/PhysFS.NET/PhysFSFileStream.cs

@@ -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
libs/physfs-2.0.3/extras/PhysFS.NET/PhysFS_DLL.cs

@@ -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
libs/physfs-2.0.3/extras/PhysFS.NET/README.txt

@@ -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
libs/physfs-2.0.3/extras/PhysFS.NET/TestApp/App.ico


+ 58 - 0
libs/physfs-2.0.3/extras/PhysFS.NET/TestApp/AssemblyInfo.cs

@@ -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
libs/physfs-2.0.3/extras/PhysFS.NET/TestApp/TestApp.csproj

@@ -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
libs/physfs-2.0.3/extras/PhysFS.NET/TestApp/TestApp.sln

@@ -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
libs/physfs-2.0.3/extras/PhysFS.NET/TestApp/TestAppForm.cs

@@ -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
libs/physfs-2.0.3/extras/PhysFS.NET/TestApp/TestAppForm.resx

@@ -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>

+ 165 - 0
libs/physfs-2.0.3/extras/abs-file.h

@@ -0,0 +1,165 @@
+/*
+ * stdio/physfs abstraction layer 2003-04-02
+ *
+ * Adam D. Moss <[email protected]> <[email protected]>
+ *
+ * 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

+ 1064 - 0
libs/physfs-2.0.3/extras/casefolding.txt

@@ -0,0 +1,1064 @@
+# CaseFolding-4.1.0.txt
+# Date: 2005-03-26, 00:24:43 GMT [MD]
+#
+# Unicode Character Database
+# Copyright (c) 1991-2005 Unicode, Inc.
+# For terms of use, see http://www.unicode.org/terms_of_use.html
+# For documentation, see UCD.html
+#
+# Case Folding Properties
+#
+# This file is a supplement to the UnicodeData file.
+# It provides a case folding mapping generated from the Unicode Character Database.
+# If all characters are mapped according to the full mapping below, then
+# case differences (according to UnicodeData.txt and SpecialCasing.txt)
+# are eliminated.
+#
+# The data supports both implementations that require simple case foldings
+# (where string lengths don't change), and implementations that allow full case folding
+# (where string lengths may grow). Note that where they can be supported, the
+# full case foldings are superior: for example, they allow "MASSE" and "Maße" to match.
+#
+# All code points not listed in this file map to themselves.
+#
+# NOTE: case folding does not preserve normalization formats!
+#
+# For information on case folding, see
+# UTR #21 Case Mappings, at http://www.unicode.org/unicode/reports/tr21/
+#
+# ================================================================================
+# Format
+# ================================================================================
+# The entries in this file are in the following machine-readable format:
+#
+# <code>; <status>; <mapping>; # <name>
+#
+# The status field is:
+# C: common case folding, common mappings shared by both simple and full mappings.
+# F: full case folding, mappings that cause strings to grow in length. Multiple characters are separated by spaces.
+# S: simple case folding, mappings to single characters where different from F.
+# T: special case for uppercase I and dotted uppercase I
+#    - For non-Turkic languages, this mapping is normally not used.
+#    - For Turkic languages (tr, az), this mapping can be used instead of the normal mapping for these characters.
+#      Note that the Turkic mappings do not maintain canonical equivalence without additional processing.
+#      See the discussions of case mapping in the Unicode Standard for more information.
+#
+# Usage:
+#  A. To do a simple case folding, use the mappings with status C + S.
+#  B. To do a full case folding, use the mappings with status C + F.
+#
+#    The mappings with status T can be used or omitted depending on the desired case-folding
+#    behavior. (The default option is to exclude them.)
+#
+# =================================================================
+
+0041; C; 0061; # LATIN CAPITAL LETTER A
+0042; C; 0062; # LATIN CAPITAL LETTER B
+0043; C; 0063; # LATIN CAPITAL LETTER C
+0044; C; 0064; # LATIN CAPITAL LETTER D
+0045; C; 0065; # LATIN CAPITAL LETTER E
+0046; C; 0066; # LATIN CAPITAL LETTER F
+0047; C; 0067; # LATIN CAPITAL LETTER G
+0048; C; 0068; # LATIN CAPITAL LETTER H
+0049; C; 0069; # LATIN CAPITAL LETTER I
+0049; T; 0131; # LATIN CAPITAL LETTER I
+004A; C; 006A; # LATIN CAPITAL LETTER J
+004B; C; 006B; # LATIN CAPITAL LETTER K
+004C; C; 006C; # LATIN CAPITAL LETTER L
+004D; C; 006D; # LATIN CAPITAL LETTER M
+004E; C; 006E; # LATIN CAPITAL LETTER N
+004F; C; 006F; # LATIN CAPITAL LETTER O
+0050; C; 0070; # LATIN CAPITAL LETTER P
+0051; C; 0071; # LATIN CAPITAL LETTER Q
+0052; C; 0072; # LATIN CAPITAL LETTER R
+0053; C; 0073; # LATIN CAPITAL LETTER S
+0054; C; 0074; # LATIN CAPITAL LETTER T
+0055; C; 0075; # LATIN CAPITAL LETTER U
+0056; C; 0076; # LATIN CAPITAL LETTER V
+0057; C; 0077; # LATIN CAPITAL LETTER W
+0058; C; 0078; # LATIN CAPITAL LETTER X
+0059; C; 0079; # LATIN CAPITAL LETTER Y
+005A; C; 007A; # LATIN CAPITAL LETTER Z
+00B5; C; 03BC; # MICRO SIGN
+00C0; C; 00E0; # LATIN CAPITAL LETTER A WITH GRAVE
+00C1; C; 00E1; # LATIN CAPITAL LETTER A WITH ACUTE
+00C2; C; 00E2; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX
+00C3; C; 00E3; # LATIN CAPITAL LETTER A WITH TILDE
+00C4; C; 00E4; # LATIN CAPITAL LETTER A WITH DIAERESIS
+00C5; C; 00E5; # LATIN CAPITAL LETTER A WITH RING ABOVE
+00C6; C; 00E6; # LATIN CAPITAL LETTER AE
+00C7; C; 00E7; # LATIN CAPITAL LETTER C WITH CEDILLA
+00C8; C; 00E8; # LATIN CAPITAL LETTER E WITH GRAVE
+00C9; C; 00E9; # LATIN CAPITAL LETTER E WITH ACUTE
+00CA; C; 00EA; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX
+00CB; C; 00EB; # LATIN CAPITAL LETTER E WITH DIAERESIS
+00CC; C; 00EC; # LATIN CAPITAL LETTER I WITH GRAVE
+00CD; C; 00ED; # LATIN CAPITAL LETTER I WITH ACUTE
+00CE; C; 00EE; # LATIN CAPITAL LETTER I WITH CIRCUMFLEX
+00CF; C; 00EF; # LATIN CAPITAL LETTER I WITH DIAERESIS
+00D0; C; 00F0; # LATIN CAPITAL LETTER ETH
+00D1; C; 00F1; # LATIN CAPITAL LETTER N WITH TILDE
+00D2; C; 00F2; # LATIN CAPITAL LETTER O WITH GRAVE
+00D3; C; 00F3; # LATIN CAPITAL LETTER O WITH ACUTE
+00D4; C; 00F4; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX
+00D5; C; 00F5; # LATIN CAPITAL LETTER O WITH TILDE
+00D6; C; 00F6; # LATIN CAPITAL LETTER O WITH DIAERESIS
+00D8; C; 00F8; # LATIN CAPITAL LETTER O WITH STROKE
+00D9; C; 00F9; # LATIN CAPITAL LETTER U WITH GRAVE
+00DA; C; 00FA; # LATIN CAPITAL LETTER U WITH ACUTE
+00DB; C; 00FB; # LATIN CAPITAL LETTER U WITH CIRCUMFLEX
+00DC; C; 00FC; # LATIN CAPITAL LETTER U WITH DIAERESIS
+00DD; C; 00FD; # LATIN CAPITAL LETTER Y WITH ACUTE
+00DE; C; 00FE; # LATIN CAPITAL LETTER THORN
+00DF; F; 0073 0073; # LATIN SMALL LETTER SHARP S
+0100; C; 0101; # LATIN CAPITAL LETTER A WITH MACRON
+0102; C; 0103; # LATIN CAPITAL LETTER A WITH BREVE
+0104; C; 0105; # LATIN CAPITAL LETTER A WITH OGONEK
+0106; C; 0107; # LATIN CAPITAL LETTER C WITH ACUTE
+0108; C; 0109; # LATIN CAPITAL LETTER C WITH CIRCUMFLEX
+010A; C; 010B; # LATIN CAPITAL LETTER C WITH DOT ABOVE
+010C; C; 010D; # LATIN CAPITAL LETTER C WITH CARON
+010E; C; 010F; # LATIN CAPITAL LETTER D WITH CARON
+0110; C; 0111; # LATIN CAPITAL LETTER D WITH STROKE
+0112; C; 0113; # LATIN CAPITAL LETTER E WITH MACRON
+0114; C; 0115; # LATIN CAPITAL LETTER E WITH BREVE
+0116; C; 0117; # LATIN CAPITAL LETTER E WITH DOT ABOVE
+0118; C; 0119; # LATIN CAPITAL LETTER E WITH OGONEK
+011A; C; 011B; # LATIN CAPITAL LETTER E WITH CARON
+011C; C; 011D; # LATIN CAPITAL LETTER G WITH CIRCUMFLEX
+011E; C; 011F; # LATIN CAPITAL LETTER G WITH BREVE
+0120; C; 0121; # LATIN CAPITAL LETTER G WITH DOT ABOVE
+0122; C; 0123; # LATIN CAPITAL LETTER G WITH CEDILLA
+0124; C; 0125; # LATIN CAPITAL LETTER H WITH CIRCUMFLEX
+0126; C; 0127; # LATIN CAPITAL LETTER H WITH STROKE
+0128; C; 0129; # LATIN CAPITAL LETTER I WITH TILDE
+012A; C; 012B; # LATIN CAPITAL LETTER I WITH MACRON
+012C; C; 012D; # LATIN CAPITAL LETTER I WITH BREVE
+012E; C; 012F; # LATIN CAPITAL LETTER I WITH OGONEK
+0130; F; 0069 0307; # LATIN CAPITAL LETTER I WITH DOT ABOVE
+0130; T; 0069; # LATIN CAPITAL LETTER I WITH DOT ABOVE
+0132; C; 0133; # LATIN CAPITAL LIGATURE IJ
+0134; C; 0135; # LATIN CAPITAL LETTER J WITH CIRCUMFLEX
+0136; C; 0137; # LATIN CAPITAL LETTER K WITH CEDILLA
+0139; C; 013A; # LATIN CAPITAL LETTER L WITH ACUTE
+013B; C; 013C; # LATIN CAPITAL LETTER L WITH CEDILLA
+013D; C; 013E; # LATIN CAPITAL LETTER L WITH CARON
+013F; C; 0140; # LATIN CAPITAL LETTER L WITH MIDDLE DOT
+0141; C; 0142; # LATIN CAPITAL LETTER L WITH STROKE
+0143; C; 0144; # LATIN CAPITAL LETTER N WITH ACUTE
+0145; C; 0146; # LATIN CAPITAL LETTER N WITH CEDILLA
+0147; C; 0148; # LATIN CAPITAL LETTER N WITH CARON
+0149; F; 02BC 006E; # LATIN SMALL LETTER N PRECEDED BY APOSTROPHE
+014A; C; 014B; # LATIN CAPITAL LETTER ENG
+014C; C; 014D; # LATIN CAPITAL LETTER O WITH MACRON
+014E; C; 014F; # LATIN CAPITAL LETTER O WITH BREVE
+0150; C; 0151; # LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
+0152; C; 0153; # LATIN CAPITAL LIGATURE OE
+0154; C; 0155; # LATIN CAPITAL LETTER R WITH ACUTE
+0156; C; 0157; # LATIN CAPITAL LETTER R WITH CEDILLA
+0158; C; 0159; # LATIN CAPITAL LETTER R WITH CARON
+015A; C; 015B; # LATIN CAPITAL LETTER S WITH ACUTE
+015C; C; 015D; # LATIN CAPITAL LETTER S WITH CIRCUMFLEX
+015E; C; 015F; # LATIN CAPITAL LETTER S WITH CEDILLA
+0160; C; 0161; # LATIN CAPITAL LETTER S WITH CARON
+0162; C; 0163; # LATIN CAPITAL LETTER T WITH CEDILLA
+0164; C; 0165; # LATIN CAPITAL LETTER T WITH CARON
+0166; C; 0167; # LATIN CAPITAL LETTER T WITH STROKE
+0168; C; 0169; # LATIN CAPITAL LETTER U WITH TILDE
+016A; C; 016B; # LATIN CAPITAL LETTER U WITH MACRON
+016C; C; 016D; # LATIN CAPITAL LETTER U WITH BREVE
+016E; C; 016F; # LATIN CAPITAL LETTER U WITH RING ABOVE
+0170; C; 0171; # LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
+0172; C; 0173; # LATIN CAPITAL LETTER U WITH OGONEK
+0174; C; 0175; # LATIN CAPITAL LETTER W WITH CIRCUMFLEX
+0176; C; 0177; # LATIN CAPITAL LETTER Y WITH CIRCUMFLEX
+0178; C; 00FF; # LATIN CAPITAL LETTER Y WITH DIAERESIS
+0179; C; 017A; # LATIN CAPITAL LETTER Z WITH ACUTE
+017B; C; 017C; # LATIN CAPITAL LETTER Z WITH DOT ABOVE
+017D; C; 017E; # LATIN CAPITAL LETTER Z WITH CARON
+017F; C; 0073; # LATIN SMALL LETTER LONG S
+0181; C; 0253; # LATIN CAPITAL LETTER B WITH HOOK
+0182; C; 0183; # LATIN CAPITAL LETTER B WITH TOPBAR
+0184; C; 0185; # LATIN CAPITAL LETTER TONE SIX
+0186; C; 0254; # LATIN CAPITAL LETTER OPEN O
+0187; C; 0188; # LATIN CAPITAL LETTER C WITH HOOK
+0189; C; 0256; # LATIN CAPITAL LETTER AFRICAN D
+018A; C; 0257; # LATIN CAPITAL LETTER D WITH HOOK
+018B; C; 018C; # LATIN CAPITAL LETTER D WITH TOPBAR
+018E; C; 01DD; # LATIN CAPITAL LETTER REVERSED E
+018F; C; 0259; # LATIN CAPITAL LETTER SCHWA
+0190; C; 025B; # LATIN CAPITAL LETTER OPEN E
+0191; C; 0192; # LATIN CAPITAL LETTER F WITH HOOK
+0193; C; 0260; # LATIN CAPITAL LETTER G WITH HOOK
+0194; C; 0263; # LATIN CAPITAL LETTER GAMMA
+0196; C; 0269; # LATIN CAPITAL LETTER IOTA
+0197; C; 0268; # LATIN CAPITAL LETTER I WITH STROKE
+0198; C; 0199; # LATIN CAPITAL LETTER K WITH HOOK
+019C; C; 026F; # LATIN CAPITAL LETTER TURNED M
+019D; C; 0272; # LATIN CAPITAL LETTER N WITH LEFT HOOK
+019F; C; 0275; # LATIN CAPITAL LETTER O WITH MIDDLE TILDE
+01A0; C; 01A1; # LATIN CAPITAL LETTER O WITH HORN
+01A2; C; 01A3; # LATIN CAPITAL LETTER OI
+01A4; C; 01A5; # LATIN CAPITAL LETTER P WITH HOOK
+01A6; C; 0280; # LATIN LETTER YR
+01A7; C; 01A8; # LATIN CAPITAL LETTER TONE TWO
+01A9; C; 0283; # LATIN CAPITAL LETTER ESH
+01AC; C; 01AD; # LATIN CAPITAL LETTER T WITH HOOK
+01AE; C; 0288; # LATIN CAPITAL LETTER T WITH RETROFLEX HOOK
+01AF; C; 01B0; # LATIN CAPITAL LETTER U WITH HORN
+01B1; C; 028A; # LATIN CAPITAL LETTER UPSILON
+01B2; C; 028B; # LATIN CAPITAL LETTER V WITH HOOK
+01B3; C; 01B4; # LATIN CAPITAL LETTER Y WITH HOOK
+01B5; C; 01B6; # LATIN CAPITAL LETTER Z WITH STROKE
+01B7; C; 0292; # LATIN CAPITAL LETTER EZH
+01B8; C; 01B9; # LATIN CAPITAL LETTER EZH REVERSED
+01BC; C; 01BD; # LATIN CAPITAL LETTER TONE FIVE
+01C4; C; 01C6; # LATIN CAPITAL LETTER DZ WITH CARON
+01C5; C; 01C6; # LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON
+01C7; C; 01C9; # LATIN CAPITAL LETTER LJ
+01C8; C; 01C9; # LATIN CAPITAL LETTER L WITH SMALL LETTER J
+01CA; C; 01CC; # LATIN CAPITAL LETTER NJ
+01CB; C; 01CC; # LATIN CAPITAL LETTER N WITH SMALL LETTER J
+01CD; C; 01CE; # LATIN CAPITAL LETTER A WITH CARON
+01CF; C; 01D0; # LATIN CAPITAL LETTER I WITH CARON
+01D1; C; 01D2; # LATIN CAPITAL LETTER O WITH CARON
+01D3; C; 01D4; # LATIN CAPITAL LETTER U WITH CARON
+01D5; C; 01D6; # LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON
+01D7; C; 01D8; # LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE
+01D9; C; 01DA; # LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON
+01DB; C; 01DC; # LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE
+01DE; C; 01DF; # LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON
+01E0; C; 01E1; # LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON
+01E2; C; 01E3; # LATIN CAPITAL LETTER AE WITH MACRON
+01E4; C; 01E5; # LATIN CAPITAL LETTER G WITH STROKE
+01E6; C; 01E7; # LATIN CAPITAL LETTER G WITH CARON
+01E8; C; 01E9; # LATIN CAPITAL LETTER K WITH CARON
+01EA; C; 01EB; # LATIN CAPITAL LETTER O WITH OGONEK
+01EC; C; 01ED; # LATIN CAPITAL LETTER O WITH OGONEK AND MACRON
+01EE; C; 01EF; # LATIN CAPITAL LETTER EZH WITH CARON
+01F0; F; 006A 030C; # LATIN SMALL LETTER J WITH CARON
+01F1; C; 01F3; # LATIN CAPITAL LETTER DZ
+01F2; C; 01F3; # LATIN CAPITAL LETTER D WITH SMALL LETTER Z
+01F4; C; 01F5; # LATIN CAPITAL LETTER G WITH ACUTE
+01F6; C; 0195; # LATIN CAPITAL LETTER HWAIR
+01F7; C; 01BF; # LATIN CAPITAL LETTER WYNN
+01F8; C; 01F9; # LATIN CAPITAL LETTER N WITH GRAVE
+01FA; C; 01FB; # LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE
+01FC; C; 01FD; # LATIN CAPITAL LETTER AE WITH ACUTE
+01FE; C; 01FF; # LATIN CAPITAL LETTER O WITH STROKE AND ACUTE
+0200; C; 0201; # LATIN CAPITAL LETTER A WITH DOUBLE GRAVE
+0202; C; 0203; # LATIN CAPITAL LETTER A WITH INVERTED BREVE
+0204; C; 0205; # LATIN CAPITAL LETTER E WITH DOUBLE GRAVE
+0206; C; 0207; # LATIN CAPITAL LETTER E WITH INVERTED BREVE
+0208; C; 0209; # LATIN CAPITAL LETTER I WITH DOUBLE GRAVE
+020A; C; 020B; # LATIN CAPITAL LETTER I WITH INVERTED BREVE
+020C; C; 020D; # LATIN CAPITAL LETTER O WITH DOUBLE GRAVE
+020E; C; 020F; # LATIN CAPITAL LETTER O WITH INVERTED BREVE
+0210; C; 0211; # LATIN CAPITAL LETTER R WITH DOUBLE GRAVE
+0212; C; 0213; # LATIN CAPITAL LETTER R WITH INVERTED BREVE
+0214; C; 0215; # LATIN CAPITAL LETTER U WITH DOUBLE GRAVE
+0216; C; 0217; # LATIN CAPITAL LETTER U WITH INVERTED BREVE
+0218; C; 0219; # LATIN CAPITAL LETTER S WITH COMMA BELOW
+021A; C; 021B; # LATIN CAPITAL LETTER T WITH COMMA BELOW
+021C; C; 021D; # LATIN CAPITAL LETTER YOGH
+021E; C; 021F; # LATIN CAPITAL LETTER H WITH CARON
+0220; C; 019E; # LATIN CAPITAL LETTER N WITH LONG RIGHT LEG
+0222; C; 0223; # LATIN CAPITAL LETTER OU
+0224; C; 0225; # LATIN CAPITAL LETTER Z WITH HOOK
+0226; C; 0227; # LATIN CAPITAL LETTER A WITH DOT ABOVE
+0228; C; 0229; # LATIN CAPITAL LETTER E WITH CEDILLA
+022A; C; 022B; # LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON
+022C; C; 022D; # LATIN CAPITAL LETTER O WITH TILDE AND MACRON
+022E; C; 022F; # LATIN CAPITAL LETTER O WITH DOT ABOVE
+0230; C; 0231; # LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON
+0232; C; 0233; # LATIN CAPITAL LETTER Y WITH MACRON
+023B; C; 023C; # LATIN CAPITAL LETTER C WITH STROKE
+023D; C; 019A; # LATIN CAPITAL LETTER L WITH BAR
+0241; C; 0294; # LATIN CAPITAL LETTER GLOTTAL STOP
+0345; C; 03B9; # COMBINING GREEK YPOGEGRAMMENI
+0386; C; 03AC; # GREEK CAPITAL LETTER ALPHA WITH TONOS
+0388; C; 03AD; # GREEK CAPITAL LETTER EPSILON WITH TONOS
+0389; C; 03AE; # GREEK CAPITAL LETTER ETA WITH TONOS
+038A; C; 03AF; # GREEK CAPITAL LETTER IOTA WITH TONOS
+038C; C; 03CC; # GREEK CAPITAL LETTER OMICRON WITH TONOS
+038E; C; 03CD; # GREEK CAPITAL LETTER UPSILON WITH TONOS
+038F; C; 03CE; # GREEK CAPITAL LETTER OMEGA WITH TONOS
+0390; F; 03B9 0308 0301; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
+0391; C; 03B1; # GREEK CAPITAL LETTER ALPHA
+0392; C; 03B2; # GREEK CAPITAL LETTER BETA
+0393; C; 03B3; # GREEK CAPITAL LETTER GAMMA
+0394; C; 03B4; # GREEK CAPITAL LETTER DELTA
+0395; C; 03B5; # GREEK CAPITAL LETTER EPSILON
+0396; C; 03B6; # GREEK CAPITAL LETTER ZETA
+0397; C; 03B7; # GREEK CAPITAL LETTER ETA
+0398; C; 03B8; # GREEK CAPITAL LETTER THETA
+0399; C; 03B9; # GREEK CAPITAL LETTER IOTA
+039A; C; 03BA; # GREEK CAPITAL LETTER KAPPA
+039B; C; 03BB; # GREEK CAPITAL LETTER LAMDA
+039C; C; 03BC; # GREEK CAPITAL LETTER MU
+039D; C; 03BD; # GREEK CAPITAL LETTER NU
+039E; C; 03BE; # GREEK CAPITAL LETTER XI
+039F; C; 03BF; # GREEK CAPITAL LETTER OMICRON
+03A0; C; 03C0; # GREEK CAPITAL LETTER PI
+03A1; C; 03C1; # GREEK CAPITAL LETTER RHO
+03A3; C; 03C3; # GREEK CAPITAL LETTER SIGMA
+03A4; C; 03C4; # GREEK CAPITAL LETTER TAU
+03A5; C; 03C5; # GREEK CAPITAL LETTER UPSILON
+03A6; C; 03C6; # GREEK CAPITAL LETTER PHI
+03A7; C; 03C7; # GREEK CAPITAL LETTER CHI
+03A8; C; 03C8; # GREEK CAPITAL LETTER PSI
+03A9; C; 03C9; # GREEK CAPITAL LETTER OMEGA
+03AA; C; 03CA; # GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
+03AB; C; 03CB; # GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
+03B0; F; 03C5 0308 0301; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
+03C2; C; 03C3; # GREEK SMALL LETTER FINAL SIGMA
+03D0; C; 03B2; # GREEK BETA SYMBOL
+03D1; C; 03B8; # GREEK THETA SYMBOL
+03D5; C; 03C6; # GREEK PHI SYMBOL
+03D6; C; 03C0; # GREEK PI SYMBOL
+03D8; C; 03D9; # GREEK LETTER ARCHAIC KOPPA
+03DA; C; 03DB; # GREEK LETTER STIGMA
+03DC; C; 03DD; # GREEK LETTER DIGAMMA
+03DE; C; 03DF; # GREEK LETTER KOPPA
+03E0; C; 03E1; # GREEK LETTER SAMPI
+03E2; C; 03E3; # COPTIC CAPITAL LETTER SHEI
+03E4; C; 03E5; # COPTIC CAPITAL LETTER FEI
+03E6; C; 03E7; # COPTIC CAPITAL LETTER KHEI
+03E8; C; 03E9; # COPTIC CAPITAL LETTER HORI
+03EA; C; 03EB; # COPTIC CAPITAL LETTER GANGIA
+03EC; C; 03ED; # COPTIC CAPITAL LETTER SHIMA
+03EE; C; 03EF; # COPTIC CAPITAL LETTER DEI
+03F0; C; 03BA; # GREEK KAPPA SYMBOL
+03F1; C; 03C1; # GREEK RHO SYMBOL
+03F4; C; 03B8; # GREEK CAPITAL THETA SYMBOL
+03F5; C; 03B5; # GREEK LUNATE EPSILON SYMBOL
+03F7; C; 03F8; # GREEK CAPITAL LETTER SHO
+03F9; C; 03F2; # GREEK CAPITAL LUNATE SIGMA SYMBOL
+03FA; C; 03FB; # GREEK CAPITAL LETTER SAN
+0400; C; 0450; # CYRILLIC CAPITAL LETTER IE WITH GRAVE
+0401; C; 0451; # CYRILLIC CAPITAL LETTER IO
+0402; C; 0452; # CYRILLIC CAPITAL LETTER DJE
+0403; C; 0453; # CYRILLIC CAPITAL LETTER GJE
+0404; C; 0454; # CYRILLIC CAPITAL LETTER UKRAINIAN IE
+0405; C; 0455; # CYRILLIC CAPITAL LETTER DZE
+0406; C; 0456; # CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
+0407; C; 0457; # CYRILLIC CAPITAL LETTER YI
+0408; C; 0458; # CYRILLIC CAPITAL LETTER JE
+0409; C; 0459; # CYRILLIC CAPITAL LETTER LJE
+040A; C; 045A; # CYRILLIC CAPITAL LETTER NJE
+040B; C; 045B; # CYRILLIC CAPITAL LETTER TSHE
+040C; C; 045C; # CYRILLIC CAPITAL LETTER KJE
+040D; C; 045D; # CYRILLIC CAPITAL LETTER I WITH GRAVE
+040E; C; 045E; # CYRILLIC CAPITAL LETTER SHORT U
+040F; C; 045F; # CYRILLIC CAPITAL LETTER DZHE
+0410; C; 0430; # CYRILLIC CAPITAL LETTER A
+0411; C; 0431; # CYRILLIC CAPITAL LETTER BE
+0412; C; 0432; # CYRILLIC CAPITAL LETTER VE
+0413; C; 0433; # CYRILLIC CAPITAL LETTER GHE
+0414; C; 0434; # CYRILLIC CAPITAL LETTER DE
+0415; C; 0435; # CYRILLIC CAPITAL LETTER IE
+0416; C; 0436; # CYRILLIC CAPITAL LETTER ZHE
+0417; C; 0437; # CYRILLIC CAPITAL LETTER ZE
+0418; C; 0438; # CYRILLIC CAPITAL LETTER I
+0419; C; 0439; # CYRILLIC CAPITAL LETTER SHORT I
+041A; C; 043A; # CYRILLIC CAPITAL LETTER KA
+041B; C; 043B; # CYRILLIC CAPITAL LETTER EL
+041C; C; 043C; # CYRILLIC CAPITAL LETTER EM
+041D; C; 043D; # CYRILLIC CAPITAL LETTER EN
+041E; C; 043E; # CYRILLIC CAPITAL LETTER O
+041F; C; 043F; # CYRILLIC CAPITAL LETTER PE
+0420; C; 0440; # CYRILLIC CAPITAL LETTER ER
+0421; C; 0441; # CYRILLIC CAPITAL LETTER ES
+0422; C; 0442; # CYRILLIC CAPITAL LETTER TE
+0423; C; 0443; # CYRILLIC CAPITAL LETTER U
+0424; C; 0444; # CYRILLIC CAPITAL LETTER EF
+0425; C; 0445; # CYRILLIC CAPITAL LETTER HA
+0426; C; 0446; # CYRILLIC CAPITAL LETTER TSE
+0427; C; 0447; # CYRILLIC CAPITAL LETTER CHE
+0428; C; 0448; # CYRILLIC CAPITAL LETTER SHA
+0429; C; 0449; # CYRILLIC CAPITAL LETTER SHCHA
+042A; C; 044A; # CYRILLIC CAPITAL LETTER HARD SIGN
+042B; C; 044B; # CYRILLIC CAPITAL LETTER YERU
+042C; C; 044C; # CYRILLIC CAPITAL LETTER SOFT SIGN
+042D; C; 044D; # CYRILLIC CAPITAL LETTER E
+042E; C; 044E; # CYRILLIC CAPITAL LETTER YU
+042F; C; 044F; # CYRILLIC CAPITAL LETTER YA
+0460; C; 0461; # CYRILLIC CAPITAL LETTER OMEGA
+0462; C; 0463; # CYRILLIC CAPITAL LETTER YAT
+0464; C; 0465; # CYRILLIC CAPITAL LETTER IOTIFIED E
+0466; C; 0467; # CYRILLIC CAPITAL LETTER LITTLE YUS
+0468; C; 0469; # CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS
+046A; C; 046B; # CYRILLIC CAPITAL LETTER BIG YUS
+046C; C; 046D; # CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS
+046E; C; 046F; # CYRILLIC CAPITAL LETTER KSI
+0470; C; 0471; # CYRILLIC CAPITAL LETTER PSI
+0472; C; 0473; # CYRILLIC CAPITAL LETTER FITA
+0474; C; 0475; # CYRILLIC CAPITAL LETTER IZHITSA
+0476; C; 0477; # CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT
+0478; C; 0479; # CYRILLIC CAPITAL LETTER UK
+047A; C; 047B; # CYRILLIC CAPITAL LETTER ROUND OMEGA
+047C; C; 047D; # CYRILLIC CAPITAL LETTER OMEGA WITH TITLO
+047E; C; 047F; # CYRILLIC CAPITAL LETTER OT
+0480; C; 0481; # CYRILLIC CAPITAL LETTER KOPPA
+048A; C; 048B; # CYRILLIC CAPITAL LETTER SHORT I WITH TAIL
+048C; C; 048D; # CYRILLIC CAPITAL LETTER SEMISOFT SIGN
+048E; C; 048F; # CYRILLIC CAPITAL LETTER ER WITH TICK
+0490; C; 0491; # CYRILLIC CAPITAL LETTER GHE WITH UPTURN
+0492; C; 0493; # CYRILLIC CAPITAL LETTER GHE WITH STROKE
+0494; C; 0495; # CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK
+0496; C; 0497; # CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER
+0498; C; 0499; # CYRILLIC CAPITAL LETTER ZE WITH DESCENDER
+049A; C; 049B; # CYRILLIC CAPITAL LETTER KA WITH DESCENDER
+049C; C; 049D; # CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE
+049E; C; 049F; # CYRILLIC CAPITAL LETTER KA WITH STROKE
+04A0; C; 04A1; # CYRILLIC CAPITAL LETTER BASHKIR KA
+04A2; C; 04A3; # CYRILLIC CAPITAL LETTER EN WITH DESCENDER
+04A4; C; 04A5; # CYRILLIC CAPITAL LIGATURE EN GHE
+04A6; C; 04A7; # CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK
+04A8; C; 04A9; # CYRILLIC CAPITAL LETTER ABKHASIAN HA
+04AA; C; 04AB; # CYRILLIC CAPITAL LETTER ES WITH DESCENDER
+04AC; C; 04AD; # CYRILLIC CAPITAL LETTER TE WITH DESCENDER
+04AE; C; 04AF; # CYRILLIC CAPITAL LETTER STRAIGHT U
+04B0; C; 04B1; # CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE
+04B2; C; 04B3; # CYRILLIC CAPITAL LETTER HA WITH DESCENDER
+04B4; C; 04B5; # CYRILLIC CAPITAL LIGATURE TE TSE
+04B6; C; 04B7; # CYRILLIC CAPITAL LETTER CHE WITH DESCENDER
+04B8; C; 04B9; # CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE
+04BA; C; 04BB; # CYRILLIC CAPITAL LETTER SHHA
+04BC; C; 04BD; # CYRILLIC CAPITAL LETTER ABKHASIAN CHE
+04BE; C; 04BF; # CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER
+04C1; C; 04C2; # CYRILLIC CAPITAL LETTER ZHE WITH BREVE
+04C3; C; 04C4; # CYRILLIC CAPITAL LETTER KA WITH HOOK
+04C5; C; 04C6; # CYRILLIC CAPITAL LETTER EL WITH TAIL
+04C7; C; 04C8; # CYRILLIC CAPITAL LETTER EN WITH HOOK
+04C9; C; 04CA; # CYRILLIC CAPITAL LETTER EN WITH TAIL
+04CB; C; 04CC; # CYRILLIC CAPITAL LETTER KHAKASSIAN CHE
+04CD; C; 04CE; # CYRILLIC CAPITAL LETTER EM WITH TAIL
+04D0; C; 04D1; # CYRILLIC CAPITAL LETTER A WITH BREVE
+04D2; C; 04D3; # CYRILLIC CAPITAL LETTER A WITH DIAERESIS
+04D4; C; 04D5; # CYRILLIC CAPITAL LIGATURE A IE
+04D6; C; 04D7; # CYRILLIC CAPITAL LETTER IE WITH BREVE
+04D8; C; 04D9; # CYRILLIC CAPITAL LETTER SCHWA
+04DA; C; 04DB; # CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS
+04DC; C; 04DD; # CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS
+04DE; C; 04DF; # CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS
+04E0; C; 04E1; # CYRILLIC CAPITAL LETTER ABKHASIAN DZE
+04E2; C; 04E3; # CYRILLIC CAPITAL LETTER I WITH MACRON
+04E4; C; 04E5; # CYRILLIC CAPITAL LETTER I WITH DIAERESIS
+04E6; C; 04E7; # CYRILLIC CAPITAL LETTER O WITH DIAERESIS
+04E8; C; 04E9; # CYRILLIC CAPITAL LETTER BARRED O
+04EA; C; 04EB; # CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS
+04EC; C; 04ED; # CYRILLIC CAPITAL LETTER E WITH DIAERESIS
+04EE; C; 04EF; # CYRILLIC CAPITAL LETTER U WITH MACRON
+04F0; C; 04F1; # CYRILLIC CAPITAL LETTER U WITH DIAERESIS
+04F2; C; 04F3; # CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE
+04F4; C; 04F5; # CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS
+04F6; C; 04F7; # CYRILLIC CAPITAL LETTER GHE WITH DESCENDER
+04F8; C; 04F9; # CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS
+0500; C; 0501; # CYRILLIC CAPITAL LETTER KOMI DE
+0502; C; 0503; # CYRILLIC CAPITAL LETTER KOMI DJE
+0504; C; 0505; # CYRILLIC CAPITAL LETTER KOMI ZJE
+0506; C; 0507; # CYRILLIC CAPITAL LETTER KOMI DZJE
+0508; C; 0509; # CYRILLIC CAPITAL LETTER KOMI LJE
+050A; C; 050B; # CYRILLIC CAPITAL LETTER KOMI NJE
+050C; C; 050D; # CYRILLIC CAPITAL LETTER KOMI SJE
+050E; C; 050F; # CYRILLIC CAPITAL LETTER KOMI TJE
+0531; C; 0561; # ARMENIAN CAPITAL LETTER AYB
+0532; C; 0562; # ARMENIAN CAPITAL LETTER BEN
+0533; C; 0563; # ARMENIAN CAPITAL LETTER GIM
+0534; C; 0564; # ARMENIAN CAPITAL LETTER DA
+0535; C; 0565; # ARMENIAN CAPITAL LETTER ECH
+0536; C; 0566; # ARMENIAN CAPITAL LETTER ZA
+0537; C; 0567; # ARMENIAN CAPITAL LETTER EH
+0538; C; 0568; # ARMENIAN CAPITAL LETTER ET
+0539; C; 0569; # ARMENIAN CAPITAL LETTER TO
+053A; C; 056A; # ARMENIAN CAPITAL LETTER ZHE
+053B; C; 056B; # ARMENIAN CAPITAL LETTER INI
+053C; C; 056C; # ARMENIAN CAPITAL LETTER LIWN
+053D; C; 056D; # ARMENIAN CAPITAL LETTER XEH
+053E; C; 056E; # ARMENIAN CAPITAL LETTER CA
+053F; C; 056F; # ARMENIAN CAPITAL LETTER KEN
+0540; C; 0570; # ARMENIAN CAPITAL LETTER HO
+0541; C; 0571; # ARMENIAN CAPITAL LETTER JA
+0542; C; 0572; # ARMENIAN CAPITAL LETTER GHAD
+0543; C; 0573; # ARMENIAN CAPITAL LETTER CHEH
+0544; C; 0574; # ARMENIAN CAPITAL LETTER MEN
+0545; C; 0575; # ARMENIAN CAPITAL LETTER YI
+0546; C; 0576; # ARMENIAN CAPITAL LETTER NOW
+0547; C; 0577; # ARMENIAN CAPITAL LETTER SHA
+0548; C; 0578; # ARMENIAN CAPITAL LETTER VO
+0549; C; 0579; # ARMENIAN CAPITAL LETTER CHA
+054A; C; 057A; # ARMENIAN CAPITAL LETTER PEH
+054B; C; 057B; # ARMENIAN CAPITAL LETTER JHEH
+054C; C; 057C; # ARMENIAN CAPITAL LETTER RA
+054D; C; 057D; # ARMENIAN CAPITAL LETTER SEH
+054E; C; 057E; # ARMENIAN CAPITAL LETTER VEW
+054F; C; 057F; # ARMENIAN CAPITAL LETTER TIWN
+0550; C; 0580; # ARMENIAN CAPITAL LETTER REH
+0551; C; 0581; # ARMENIAN CAPITAL LETTER CO
+0552; C; 0582; # ARMENIAN CAPITAL LETTER YIWN
+0553; C; 0583; # ARMENIAN CAPITAL LETTER PIWR
+0554; C; 0584; # ARMENIAN CAPITAL LETTER KEH
+0555; C; 0585; # ARMENIAN CAPITAL LETTER OH
+0556; C; 0586; # ARMENIAN CAPITAL LETTER FEH
+0587; F; 0565 0582; # ARMENIAN SMALL LIGATURE ECH YIWN
+10A0; C; 2D00; # GEORGIAN CAPITAL LETTER AN
+10A1; C; 2D01; # GEORGIAN CAPITAL LETTER BAN
+10A2; C; 2D02; # GEORGIAN CAPITAL LETTER GAN
+10A3; C; 2D03; # GEORGIAN CAPITAL LETTER DON
+10A4; C; 2D04; # GEORGIAN CAPITAL LETTER EN
+10A5; C; 2D05; # GEORGIAN CAPITAL LETTER VIN
+10A6; C; 2D06; # GEORGIAN CAPITAL LETTER ZEN
+10A7; C; 2D07; # GEORGIAN CAPITAL LETTER TAN
+10A8; C; 2D08; # GEORGIAN CAPITAL LETTER IN
+10A9; C; 2D09; # GEORGIAN CAPITAL LETTER KAN
+10AA; C; 2D0A; # GEORGIAN CAPITAL LETTER LAS
+10AB; C; 2D0B; # GEORGIAN CAPITAL LETTER MAN
+10AC; C; 2D0C; # GEORGIAN CAPITAL LETTER NAR
+10AD; C; 2D0D; # GEORGIAN CAPITAL LETTER ON
+10AE; C; 2D0E; # GEORGIAN CAPITAL LETTER PAR
+10AF; C; 2D0F; # GEORGIAN CAPITAL LETTER ZHAR
+10B0; C; 2D10; # GEORGIAN CAPITAL LETTER RAE
+10B1; C; 2D11; # GEORGIAN CAPITAL LETTER SAN
+10B2; C; 2D12; # GEORGIAN CAPITAL LETTER TAR
+10B3; C; 2D13; # GEORGIAN CAPITAL LETTER UN
+10B4; C; 2D14; # GEORGIAN CAPITAL LETTER PHAR
+10B5; C; 2D15; # GEORGIAN CAPITAL LETTER KHAR
+10B6; C; 2D16; # GEORGIAN CAPITAL LETTER GHAN
+10B7; C; 2D17; # GEORGIAN CAPITAL LETTER QAR
+10B8; C; 2D18; # GEORGIAN CAPITAL LETTER SHIN
+10B9; C; 2D19; # GEORGIAN CAPITAL LETTER CHIN
+10BA; C; 2D1A; # GEORGIAN CAPITAL LETTER CAN
+10BB; C; 2D1B; # GEORGIAN CAPITAL LETTER JIL
+10BC; C; 2D1C; # GEORGIAN CAPITAL LETTER CIL
+10BD; C; 2D1D; # GEORGIAN CAPITAL LETTER CHAR
+10BE; C; 2D1E; # GEORGIAN CAPITAL LETTER XAN
+10BF; C; 2D1F; # GEORGIAN CAPITAL LETTER JHAN
+10C0; C; 2D20; # GEORGIAN CAPITAL LETTER HAE
+10C1; C; 2D21; # GEORGIAN CAPITAL LETTER HE
+10C2; C; 2D22; # GEORGIAN CAPITAL LETTER HIE
+10C3; C; 2D23; # GEORGIAN CAPITAL LETTER WE
+10C4; C; 2D24; # GEORGIAN CAPITAL LETTER HAR
+10C5; C; 2D25; # GEORGIAN CAPITAL LETTER HOE
+1E00; C; 1E01; # LATIN CAPITAL LETTER A WITH RING BELOW
+1E02; C; 1E03; # LATIN CAPITAL LETTER B WITH DOT ABOVE
+1E04; C; 1E05; # LATIN CAPITAL LETTER B WITH DOT BELOW
+1E06; C; 1E07; # LATIN CAPITAL LETTER B WITH LINE BELOW
+1E08; C; 1E09; # LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE
+1E0A; C; 1E0B; # LATIN CAPITAL LETTER D WITH DOT ABOVE
+1E0C; C; 1E0D; # LATIN CAPITAL LETTER D WITH DOT BELOW
+1E0E; C; 1E0F; # LATIN CAPITAL LETTER D WITH LINE BELOW
+1E10; C; 1E11; # LATIN CAPITAL LETTER D WITH CEDILLA
+1E12; C; 1E13; # LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW
+1E14; C; 1E15; # LATIN CAPITAL LETTER E WITH MACRON AND GRAVE
+1E16; C; 1E17; # LATIN CAPITAL LETTER E WITH MACRON AND ACUTE
+1E18; C; 1E19; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW
+1E1A; C; 1E1B; # LATIN CAPITAL LETTER E WITH TILDE BELOW
+1E1C; C; 1E1D; # LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE
+1E1E; C; 1E1F; # LATIN CAPITAL LETTER F WITH DOT ABOVE
+1E20; C; 1E21; # LATIN CAPITAL LETTER G WITH MACRON
+1E22; C; 1E23; # LATIN CAPITAL LETTER H WITH DOT ABOVE
+1E24; C; 1E25; # LATIN CAPITAL LETTER H WITH DOT BELOW
+1E26; C; 1E27; # LATIN CAPITAL LETTER H WITH DIAERESIS
+1E28; C; 1E29; # LATIN CAPITAL LETTER H WITH CEDILLA
+1E2A; C; 1E2B; # LATIN CAPITAL LETTER H WITH BREVE BELOW
+1E2C; C; 1E2D; # LATIN CAPITAL LETTER I WITH TILDE BELOW
+1E2E; C; 1E2F; # LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE
+1E30; C; 1E31; # LATIN CAPITAL LETTER K WITH ACUTE
+1E32; C; 1E33; # LATIN CAPITAL LETTER K WITH DOT BELOW
+1E34; C; 1E35; # LATIN CAPITAL LETTER K WITH LINE BELOW
+1E36; C; 1E37; # LATIN CAPITAL LETTER L WITH DOT BELOW
+1E38; C; 1E39; # LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON
+1E3A; C; 1E3B; # LATIN CAPITAL LETTER L WITH LINE BELOW
+1E3C; C; 1E3D; # LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW
+1E3E; C; 1E3F; # LATIN CAPITAL LETTER M WITH ACUTE
+1E40; C; 1E41; # LATIN CAPITAL LETTER M WITH DOT ABOVE
+1E42; C; 1E43; # LATIN CAPITAL LETTER M WITH DOT BELOW
+1E44; C; 1E45; # LATIN CAPITAL LETTER N WITH DOT ABOVE
+1E46; C; 1E47; # LATIN CAPITAL LETTER N WITH DOT BELOW
+1E48; C; 1E49; # LATIN CAPITAL LETTER N WITH LINE BELOW
+1E4A; C; 1E4B; # LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW
+1E4C; C; 1E4D; # LATIN CAPITAL LETTER O WITH TILDE AND ACUTE
+1E4E; C; 1E4F; # LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS
+1E50; C; 1E51; # LATIN CAPITAL LETTER O WITH MACRON AND GRAVE
+1E52; C; 1E53; # LATIN CAPITAL LETTER O WITH MACRON AND ACUTE
+1E54; C; 1E55; # LATIN CAPITAL LETTER P WITH ACUTE
+1E56; C; 1E57; # LATIN CAPITAL LETTER P WITH DOT ABOVE
+1E58; C; 1E59; # LATIN CAPITAL LETTER R WITH DOT ABOVE
+1E5A; C; 1E5B; # LATIN CAPITAL LETTER R WITH DOT BELOW
+1E5C; C; 1E5D; # LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON
+1E5E; C; 1E5F; # LATIN CAPITAL LETTER R WITH LINE BELOW
+1E60; C; 1E61; # LATIN CAPITAL LETTER S WITH DOT ABOVE
+1E62; C; 1E63; # LATIN CAPITAL LETTER S WITH DOT BELOW
+1E64; C; 1E65; # LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE
+1E66; C; 1E67; # LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE
+1E68; C; 1E69; # LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE
+1E6A; C; 1E6B; # LATIN CAPITAL LETTER T WITH DOT ABOVE
+1E6C; C; 1E6D; # LATIN CAPITAL LETTER T WITH DOT BELOW
+1E6E; C; 1E6F; # LATIN CAPITAL LETTER T WITH LINE BELOW
+1E70; C; 1E71; # LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW
+1E72; C; 1E73; # LATIN CAPITAL LETTER U WITH DIAERESIS BELOW
+1E74; C; 1E75; # LATIN CAPITAL LETTER U WITH TILDE BELOW
+1E76; C; 1E77; # LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW
+1E78; C; 1E79; # LATIN CAPITAL LETTER U WITH TILDE AND ACUTE
+1E7A; C; 1E7B; # LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS
+1E7C; C; 1E7D; # LATIN CAPITAL LETTER V WITH TILDE
+1E7E; C; 1E7F; # LATIN CAPITAL LETTER V WITH DOT BELOW
+1E80; C; 1E81; # LATIN CAPITAL LETTER W WITH GRAVE
+1E82; C; 1E83; # LATIN CAPITAL LETTER W WITH ACUTE
+1E84; C; 1E85; # LATIN CAPITAL LETTER W WITH DIAERESIS
+1E86; C; 1E87; # LATIN CAPITAL LETTER W WITH DOT ABOVE
+1E88; C; 1E89; # LATIN CAPITAL LETTER W WITH DOT BELOW
+1E8A; C; 1E8B; # LATIN CAPITAL LETTER X WITH DOT ABOVE
+1E8C; C; 1E8D; # LATIN CAPITAL LETTER X WITH DIAERESIS
+1E8E; C; 1E8F; # LATIN CAPITAL LETTER Y WITH DOT ABOVE
+1E90; C; 1E91; # LATIN CAPITAL LETTER Z WITH CIRCUMFLEX
+1E92; C; 1E93; # LATIN CAPITAL LETTER Z WITH DOT BELOW
+1E94; C; 1E95; # LATIN CAPITAL LETTER Z WITH LINE BELOW
+1E96; F; 0068 0331; # LATIN SMALL LETTER H WITH LINE BELOW
+1E97; F; 0074 0308; # LATIN SMALL LETTER T WITH DIAERESIS
+1E98; F; 0077 030A; # LATIN SMALL LETTER W WITH RING ABOVE
+1E99; F; 0079 030A; # LATIN SMALL LETTER Y WITH RING ABOVE
+1E9A; F; 0061 02BE; # LATIN SMALL LETTER A WITH RIGHT HALF RING
+1E9B; C; 1E61; # LATIN SMALL LETTER LONG S WITH DOT ABOVE
+1EA0; C; 1EA1; # LATIN CAPITAL LETTER A WITH DOT BELOW
+1EA2; C; 1EA3; # LATIN CAPITAL LETTER A WITH HOOK ABOVE
+1EA4; C; 1EA5; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE
+1EA6; C; 1EA7; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE
+1EA8; C; 1EA9; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE
+1EAA; C; 1EAB; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE
+1EAC; C; 1EAD; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW
+1EAE; C; 1EAF; # LATIN CAPITAL LETTER A WITH BREVE AND ACUTE
+1EB0; C; 1EB1; # LATIN CAPITAL LETTER A WITH BREVE AND GRAVE
+1EB2; C; 1EB3; # LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE
+1EB4; C; 1EB5; # LATIN CAPITAL LETTER A WITH BREVE AND TILDE
+1EB6; C; 1EB7; # LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW
+1EB8; C; 1EB9; # LATIN CAPITAL LETTER E WITH DOT BELOW
+1EBA; C; 1EBB; # LATIN CAPITAL LETTER E WITH HOOK ABOVE
+1EBC; C; 1EBD; # LATIN CAPITAL LETTER E WITH TILDE
+1EBE; C; 1EBF; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE
+1EC0; C; 1EC1; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE
+1EC2; C; 1EC3; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE
+1EC4; C; 1EC5; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE
+1EC6; C; 1EC7; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW
+1EC8; C; 1EC9; # LATIN CAPITAL LETTER I WITH HOOK ABOVE
+1ECA; C; 1ECB; # LATIN CAPITAL LETTER I WITH DOT BELOW
+1ECC; C; 1ECD; # LATIN CAPITAL LETTER O WITH DOT BELOW
+1ECE; C; 1ECF; # LATIN CAPITAL LETTER O WITH HOOK ABOVE
+1ED0; C; 1ED1; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE
+1ED2; C; 1ED3; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE
+1ED4; C; 1ED5; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE
+1ED6; C; 1ED7; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE
+1ED8; C; 1ED9; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW
+1EDA; C; 1EDB; # LATIN CAPITAL LETTER O WITH HORN AND ACUTE
+1EDC; C; 1EDD; # LATIN CAPITAL LETTER O WITH HORN AND GRAVE
+1EDE; C; 1EDF; # LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE
+1EE0; C; 1EE1; # LATIN CAPITAL LETTER O WITH HORN AND TILDE
+1EE2; C; 1EE3; # LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW
+1EE4; C; 1EE5; # LATIN CAPITAL LETTER U WITH DOT BELOW
+1EE6; C; 1EE7; # LATIN CAPITAL LETTER U WITH HOOK ABOVE
+1EE8; C; 1EE9; # LATIN CAPITAL LETTER U WITH HORN AND ACUTE
+1EEA; C; 1EEB; # LATIN CAPITAL LETTER U WITH HORN AND GRAVE
+1EEC; C; 1EED; # LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE
+1EEE; C; 1EEF; # LATIN CAPITAL LETTER U WITH HORN AND TILDE
+1EF0; C; 1EF1; # LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW
+1EF2; C; 1EF3; # LATIN CAPITAL LETTER Y WITH GRAVE
+1EF4; C; 1EF5; # LATIN CAPITAL LETTER Y WITH DOT BELOW
+1EF6; C; 1EF7; # LATIN CAPITAL LETTER Y WITH HOOK ABOVE
+1EF8; C; 1EF9; # LATIN CAPITAL LETTER Y WITH TILDE
+1F08; C; 1F00; # GREEK CAPITAL LETTER ALPHA WITH PSILI
+1F09; C; 1F01; # GREEK CAPITAL LETTER ALPHA WITH DASIA
+1F0A; C; 1F02; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA
+1F0B; C; 1F03; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA
+1F0C; C; 1F04; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA
+1F0D; C; 1F05; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA
+1F0E; C; 1F06; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI
+1F0F; C; 1F07; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI
+1F18; C; 1F10; # GREEK CAPITAL LETTER EPSILON WITH PSILI
+1F19; C; 1F11; # GREEK CAPITAL LETTER EPSILON WITH DASIA
+1F1A; C; 1F12; # GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA
+1F1B; C; 1F13; # GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA
+1F1C; C; 1F14; # GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA
+1F1D; C; 1F15; # GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA
+1F28; C; 1F20; # GREEK CAPITAL LETTER ETA WITH PSILI
+1F29; C; 1F21; # GREEK CAPITAL LETTER ETA WITH DASIA
+1F2A; C; 1F22; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA
+1F2B; C; 1F23; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA
+1F2C; C; 1F24; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA
+1F2D; C; 1F25; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA
+1F2E; C; 1F26; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI
+1F2F; C; 1F27; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI
+1F38; C; 1F30; # GREEK CAPITAL LETTER IOTA WITH PSILI
+1F39; C; 1F31; # GREEK CAPITAL LETTER IOTA WITH DASIA
+1F3A; C; 1F32; # GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA
+1F3B; C; 1F33; # GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA
+1F3C; C; 1F34; # GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA
+1F3D; C; 1F35; # GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA
+1F3E; C; 1F36; # GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI
+1F3F; C; 1F37; # GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI
+1F48; C; 1F40; # GREEK CAPITAL LETTER OMICRON WITH PSILI
+1F49; C; 1F41; # GREEK CAPITAL LETTER OMICRON WITH DASIA
+1F4A; C; 1F42; # GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA
+1F4B; C; 1F43; # GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA
+1F4C; C; 1F44; # GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA
+1F4D; C; 1F45; # GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA
+1F50; F; 03C5 0313; # GREEK SMALL LETTER UPSILON WITH PSILI
+1F52; F; 03C5 0313 0300; # GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA
+1F54; F; 03C5 0313 0301; # GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA
+1F56; F; 03C5 0313 0342; # GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI
+1F59; C; 1F51; # GREEK CAPITAL LETTER UPSILON WITH DASIA
+1F5B; C; 1F53; # GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA
+1F5D; C; 1F55; # GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA
+1F5F; C; 1F57; # GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI
+1F68; C; 1F60; # GREEK CAPITAL LETTER OMEGA WITH PSILI
+1F69; C; 1F61; # GREEK CAPITAL LETTER OMEGA WITH DASIA
+1F6A; C; 1F62; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA
+1F6B; C; 1F63; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA
+1F6C; C; 1F64; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA
+1F6D; C; 1F65; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA
+1F6E; C; 1F66; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI
+1F6F; C; 1F67; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI
+1F80; F; 1F00 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI
+1F81; F; 1F01 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI
+1F82; F; 1F02 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI
+1F83; F; 1F03 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI
+1F84; F; 1F04 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI
+1F85; F; 1F05 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI
+1F86; F; 1F06 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
+1F87; F; 1F07 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
+1F88; F; 1F00 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI
+1F88; S; 1F80; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI
+1F89; F; 1F01 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI
+1F89; S; 1F81; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI
+1F8A; F; 1F02 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI
+1F8A; S; 1F82; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI
+1F8B; F; 1F03 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI
+1F8B; S; 1F83; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI
+1F8C; F; 1F04 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI
+1F8C; S; 1F84; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI
+1F8D; F; 1F05 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI
+1F8D; S; 1F85; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI
+1F8E; F; 1F06 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
+1F8E; S; 1F86; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
+1F8F; F; 1F07 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+1F8F; S; 1F87; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+1F90; F; 1F20 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI
+1F91; F; 1F21 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI
+1F92; F; 1F22 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI
+1F93; F; 1F23 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI
+1F94; F; 1F24 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI
+1F95; F; 1F25 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI
+1F96; F; 1F26 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
+1F97; F; 1F27 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
+1F98; F; 1F20 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI
+1F98; S; 1F90; # GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI
+1F99; F; 1F21 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI
+1F99; S; 1F91; # GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI
+1F9A; F; 1F22 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI
+1F9A; S; 1F92; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI
+1F9B; F; 1F23 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI
+1F9B; S; 1F93; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI
+1F9C; F; 1F24 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI
+1F9C; S; 1F94; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI
+1F9D; F; 1F25 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI
+1F9D; S; 1F95; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI
+1F9E; F; 1F26 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
+1F9E; S; 1F96; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
+1F9F; F; 1F27 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+1F9F; S; 1F97; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+1FA0; F; 1F60 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI
+1FA1; F; 1F61 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI
+1FA2; F; 1F62 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI
+1FA3; F; 1F63 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI
+1FA4; F; 1F64 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI
+1FA5; F; 1F65 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI
+1FA6; F; 1F66 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
+1FA7; F; 1F67 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
+1FA8; F; 1F60 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI
+1FA8; S; 1FA0; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI
+1FA9; F; 1F61 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI
+1FA9; S; 1FA1; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI
+1FAA; F; 1F62 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI
+1FAA; S; 1FA2; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI
+1FAB; F; 1F63 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI
+1FAB; S; 1FA3; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI
+1FAC; F; 1F64 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI
+1FAC; S; 1FA4; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI
+1FAD; F; 1F65 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI
+1FAD; S; 1FA5; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI
+1FAE; F; 1F66 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
+1FAE; S; 1FA6; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
+1FAF; F; 1F67 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+1FAF; S; 1FA7; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+1FB2; F; 1F70 03B9; # GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI
+1FB3; F; 03B1 03B9; # GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI
+1FB4; F; 03AC 03B9; # GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
+1FB6; F; 03B1 0342; # GREEK SMALL LETTER ALPHA WITH PERISPOMENI
+1FB7; F; 03B1 0342 03B9; # GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI
+1FB8; C; 1FB0; # GREEK CAPITAL LETTER ALPHA WITH VRACHY
+1FB9; C; 1FB1; # GREEK CAPITAL LETTER ALPHA WITH MACRON
+1FBA; C; 1F70; # GREEK CAPITAL LETTER ALPHA WITH VARIA
+1FBB; C; 1F71; # GREEK CAPITAL LETTER ALPHA WITH OXIA
+1FBC; F; 03B1 03B9; # GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
+1FBC; S; 1FB3; # GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
+1FBE; C; 03B9; # GREEK PROSGEGRAMMENI
+1FC2; F; 1F74 03B9; # GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI
+1FC3; F; 03B7 03B9; # GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI
+1FC4; F; 03AE 03B9; # GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
+1FC6; F; 03B7 0342; # GREEK SMALL LETTER ETA WITH PERISPOMENI
+1FC7; F; 03B7 0342 03B9; # GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI
+1FC8; C; 1F72; # GREEK CAPITAL LETTER EPSILON WITH VARIA
+1FC9; C; 1F73; # GREEK CAPITAL LETTER EPSILON WITH OXIA
+1FCA; C; 1F74; # GREEK CAPITAL LETTER ETA WITH VARIA
+1FCB; C; 1F75; # GREEK CAPITAL LETTER ETA WITH OXIA
+1FCC; F; 03B7 03B9; # GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
+1FCC; S; 1FC3; # GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
+1FD2; F; 03B9 0308 0300; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA
+1FD3; F; 03B9 0308 0301; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
+1FD6; F; 03B9 0342; # GREEK SMALL LETTER IOTA WITH PERISPOMENI
+1FD7; F; 03B9 0308 0342; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI
+1FD8; C; 1FD0; # GREEK CAPITAL LETTER IOTA WITH VRACHY
+1FD9; C; 1FD1; # GREEK CAPITAL LETTER IOTA WITH MACRON
+1FDA; C; 1F76; # GREEK CAPITAL LETTER IOTA WITH VARIA
+1FDB; C; 1F77; # GREEK CAPITAL LETTER IOTA WITH OXIA
+1FE2; F; 03C5 0308 0300; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA
+1FE3; F; 03C5 0308 0301; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA
+1FE4; F; 03C1 0313; # GREEK SMALL LETTER RHO WITH PSILI
+1FE6; F; 03C5 0342; # GREEK SMALL LETTER UPSILON WITH PERISPOMENI
+1FE7; F; 03C5 0308 0342; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI
+1FE8; C; 1FE0; # GREEK CAPITAL LETTER UPSILON WITH VRACHY
+1FE9; C; 1FE1; # GREEK CAPITAL LETTER UPSILON WITH MACRON
+1FEA; C; 1F7A; # GREEK CAPITAL LETTER UPSILON WITH VARIA
+1FEB; C; 1F7B; # GREEK CAPITAL LETTER UPSILON WITH OXIA
+1FEC; C; 1FE5; # GREEK CAPITAL LETTER RHO WITH DASIA
+1FF2; F; 1F7C 03B9; # GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI
+1FF3; F; 03C9 03B9; # GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI
+1FF4; F; 03CE 03B9; # GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
+1FF6; F; 03C9 0342; # GREEK SMALL LETTER OMEGA WITH PERISPOMENI
+1FF7; F; 03C9 0342 03B9; # GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI
+1FF8; C; 1F78; # GREEK CAPITAL LETTER OMICRON WITH VARIA
+1FF9; C; 1F79; # GREEK CAPITAL LETTER OMICRON WITH OXIA
+1FFA; C; 1F7C; # GREEK CAPITAL LETTER OMEGA WITH VARIA
+1FFB; C; 1F7D; # GREEK CAPITAL LETTER OMEGA WITH OXIA
+1FFC; F; 03C9 03B9; # GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
+1FFC; S; 1FF3; # GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
+2126; C; 03C9; # OHM SIGN
+212A; C; 006B; # KELVIN SIGN
+212B; C; 00E5; # ANGSTROM SIGN
+2160; C; 2170; # ROMAN NUMERAL ONE
+2161; C; 2171; # ROMAN NUMERAL TWO
+2162; C; 2172; # ROMAN NUMERAL THREE
+2163; C; 2173; # ROMAN NUMERAL FOUR
+2164; C; 2174; # ROMAN NUMERAL FIVE
+2165; C; 2175; # ROMAN NUMERAL SIX
+2166; C; 2176; # ROMAN NUMERAL SEVEN
+2167; C; 2177; # ROMAN NUMERAL EIGHT
+2168; C; 2178; # ROMAN NUMERAL NINE
+2169; C; 2179; # ROMAN NUMERAL TEN
+216A; C; 217A; # ROMAN NUMERAL ELEVEN
+216B; C; 217B; # ROMAN NUMERAL TWELVE
+216C; C; 217C; # ROMAN NUMERAL FIFTY
+216D; C; 217D; # ROMAN NUMERAL ONE HUNDRED
+216E; C; 217E; # ROMAN NUMERAL FIVE HUNDRED
+216F; C; 217F; # ROMAN NUMERAL ONE THOUSAND
+24B6; C; 24D0; # CIRCLED LATIN CAPITAL LETTER A
+24B7; C; 24D1; # CIRCLED LATIN CAPITAL LETTER B
+24B8; C; 24D2; # CIRCLED LATIN CAPITAL LETTER C
+24B9; C; 24D3; # CIRCLED LATIN CAPITAL LETTER D
+24BA; C; 24D4; # CIRCLED LATIN CAPITAL LETTER E
+24BB; C; 24D5; # CIRCLED LATIN CAPITAL LETTER F
+24BC; C; 24D6; # CIRCLED LATIN CAPITAL LETTER G
+24BD; C; 24D7; # CIRCLED LATIN CAPITAL LETTER H
+24BE; C; 24D8; # CIRCLED LATIN CAPITAL LETTER I
+24BF; C; 24D9; # CIRCLED LATIN CAPITAL LETTER J
+24C0; C; 24DA; # CIRCLED LATIN CAPITAL LETTER K
+24C1; C; 24DB; # CIRCLED LATIN CAPITAL LETTER L
+24C2; C; 24DC; # CIRCLED LATIN CAPITAL LETTER M
+24C3; C; 24DD; # CIRCLED LATIN CAPITAL LETTER N
+24C4; C; 24DE; # CIRCLED LATIN CAPITAL LETTER O
+24C5; C; 24DF; # CIRCLED LATIN CAPITAL LETTER P
+24C6; C; 24E0; # CIRCLED LATIN CAPITAL LETTER Q
+24C7; C; 24E1; # CIRCLED LATIN CAPITAL LETTER R
+24C8; C; 24E2; # CIRCLED LATIN CAPITAL LETTER S
+24C9; C; 24E3; # CIRCLED LATIN CAPITAL LETTER T
+24CA; C; 24E4; # CIRCLED LATIN CAPITAL LETTER U
+24CB; C; 24E5; # CIRCLED LATIN CAPITAL LETTER V
+24CC; C; 24E6; # CIRCLED LATIN CAPITAL LETTER W
+24CD; C; 24E7; # CIRCLED LATIN CAPITAL LETTER X
+24CE; C; 24E8; # CIRCLED LATIN CAPITAL LETTER Y
+24CF; C; 24E9; # CIRCLED LATIN CAPITAL LETTER Z
+2C00; C; 2C30; # GLAGOLITIC CAPITAL LETTER AZU
+2C01; C; 2C31; # GLAGOLITIC CAPITAL LETTER BUKY
+2C02; C; 2C32; # GLAGOLITIC CAPITAL LETTER VEDE
+2C03; C; 2C33; # GLAGOLITIC CAPITAL LETTER GLAGOLI
+2C04; C; 2C34; # GLAGOLITIC CAPITAL LETTER DOBRO
+2C05; C; 2C35; # GLAGOLITIC CAPITAL LETTER YESTU
+2C06; C; 2C36; # GLAGOLITIC CAPITAL LETTER ZHIVETE
+2C07; C; 2C37; # GLAGOLITIC CAPITAL LETTER DZELO
+2C08; C; 2C38; # GLAGOLITIC CAPITAL LETTER ZEMLJA
+2C09; C; 2C39; # GLAGOLITIC CAPITAL LETTER IZHE
+2C0A; C; 2C3A; # GLAGOLITIC CAPITAL LETTER INITIAL IZHE
+2C0B; C; 2C3B; # GLAGOLITIC CAPITAL LETTER I
+2C0C; C; 2C3C; # GLAGOLITIC CAPITAL LETTER DJERVI
+2C0D; C; 2C3D; # GLAGOLITIC CAPITAL LETTER KAKO
+2C0E; C; 2C3E; # GLAGOLITIC CAPITAL LETTER LJUDIJE
+2C0F; C; 2C3F; # GLAGOLITIC CAPITAL LETTER MYSLITE
+2C10; C; 2C40; # GLAGOLITIC CAPITAL LETTER NASHI
+2C11; C; 2C41; # GLAGOLITIC CAPITAL LETTER ONU
+2C12; C; 2C42; # GLAGOLITIC CAPITAL LETTER POKOJI
+2C13; C; 2C43; # GLAGOLITIC CAPITAL LETTER RITSI
+2C14; C; 2C44; # GLAGOLITIC CAPITAL LETTER SLOVO
+2C15; C; 2C45; # GLAGOLITIC CAPITAL LETTER TVRIDO
+2C16; C; 2C46; # GLAGOLITIC CAPITAL LETTER UKU
+2C17; C; 2C47; # GLAGOLITIC CAPITAL LETTER FRITU
+2C18; C; 2C48; # GLAGOLITIC CAPITAL LETTER HERU
+2C19; C; 2C49; # GLAGOLITIC CAPITAL LETTER OTU
+2C1A; C; 2C4A; # GLAGOLITIC CAPITAL LETTER PE
+2C1B; C; 2C4B; # GLAGOLITIC CAPITAL LETTER SHTA
+2C1C; C; 2C4C; # GLAGOLITIC CAPITAL LETTER TSI
+2C1D; C; 2C4D; # GLAGOLITIC CAPITAL LETTER CHRIVI
+2C1E; C; 2C4E; # GLAGOLITIC CAPITAL LETTER SHA
+2C1F; C; 2C4F; # GLAGOLITIC CAPITAL LETTER YERU
+2C20; C; 2C50; # GLAGOLITIC CAPITAL LETTER YERI
+2C21; C; 2C51; # GLAGOLITIC CAPITAL LETTER YATI
+2C22; C; 2C52; # GLAGOLITIC CAPITAL LETTER SPIDERY HA
+2C23; C; 2C53; # GLAGOLITIC CAPITAL LETTER YU
+2C24; C; 2C54; # GLAGOLITIC CAPITAL LETTER SMALL YUS
+2C25; C; 2C55; # GLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAIL
+2C26; C; 2C56; # GLAGOLITIC CAPITAL LETTER YO
+2C27; C; 2C57; # GLAGOLITIC CAPITAL LETTER IOTATED SMALL YUS
+2C28; C; 2C58; # GLAGOLITIC CAPITAL LETTER BIG YUS
+2C29; C; 2C59; # GLAGOLITIC CAPITAL LETTER IOTATED BIG YUS
+2C2A; C; 2C5A; # GLAGOLITIC CAPITAL LETTER FITA
+2C2B; C; 2C5B; # GLAGOLITIC CAPITAL LETTER IZHITSA
+2C2C; C; 2C5C; # GLAGOLITIC CAPITAL LETTER SHTAPIC
+2C2D; C; 2C5D; # GLAGOLITIC CAPITAL LETTER TROKUTASTI A
+2C2E; C; 2C5E; # GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE
+2C80; C; 2C81; # COPTIC CAPITAL LETTER ALFA
+2C82; C; 2C83; # COPTIC CAPITAL LETTER VIDA
+2C84; C; 2C85; # COPTIC CAPITAL LETTER GAMMA
+2C86; C; 2C87; # COPTIC CAPITAL LETTER DALDA
+2C88; C; 2C89; # COPTIC CAPITAL LETTER EIE
+2C8A; C; 2C8B; # COPTIC CAPITAL LETTER SOU
+2C8C; C; 2C8D; # COPTIC CAPITAL LETTER ZATA
+2C8E; C; 2C8F; # COPTIC CAPITAL LETTER HATE
+2C90; C; 2C91; # COPTIC CAPITAL LETTER THETHE
+2C92; C; 2C93; # COPTIC CAPITAL LETTER IAUDA
+2C94; C; 2C95; # COPTIC CAPITAL LETTER KAPA
+2C96; C; 2C97; # COPTIC CAPITAL LETTER LAULA
+2C98; C; 2C99; # COPTIC CAPITAL LETTER MI
+2C9A; C; 2C9B; # COPTIC CAPITAL LETTER NI
+2C9C; C; 2C9D; # COPTIC CAPITAL LETTER KSI
+2C9E; C; 2C9F; # COPTIC CAPITAL LETTER O
+2CA0; C; 2CA1; # COPTIC CAPITAL LETTER PI
+2CA2; C; 2CA3; # COPTIC CAPITAL LETTER RO
+2CA4; C; 2CA5; # COPTIC CAPITAL LETTER SIMA
+2CA6; C; 2CA7; # COPTIC CAPITAL LETTER TAU
+2CA8; C; 2CA9; # COPTIC CAPITAL LETTER UA
+2CAA; C; 2CAB; # COPTIC CAPITAL LETTER FI
+2CAC; C; 2CAD; # COPTIC CAPITAL LETTER KHI
+2CAE; C; 2CAF; # COPTIC CAPITAL LETTER PSI
+2CB0; C; 2CB1; # COPTIC CAPITAL LETTER OOU
+2CB2; C; 2CB3; # COPTIC CAPITAL LETTER DIALECT-P ALEF
+2CB4; C; 2CB5; # COPTIC CAPITAL LETTER OLD COPTIC AIN
+2CB6; C; 2CB7; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE
+2CB8; C; 2CB9; # COPTIC CAPITAL LETTER DIALECT-P KAPA
+2CBA; C; 2CBB; # COPTIC CAPITAL LETTER DIALECT-P NI
+2CBC; C; 2CBD; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI
+2CBE; C; 2CBF; # COPTIC CAPITAL LETTER OLD COPTIC OOU
+2CC0; C; 2CC1; # COPTIC CAPITAL LETTER SAMPI
+2CC2; C; 2CC3; # COPTIC CAPITAL LETTER CROSSED SHEI
+2CC4; C; 2CC5; # COPTIC CAPITAL LETTER OLD COPTIC SHEI
+2CC6; C; 2CC7; # COPTIC CAPITAL LETTER OLD COPTIC ESH
+2CC8; C; 2CC9; # COPTIC CAPITAL LETTER AKHMIMIC KHEI
+2CCA; C; 2CCB; # COPTIC CAPITAL LETTER DIALECT-P HORI
+2CCC; C; 2CCD; # COPTIC CAPITAL LETTER OLD COPTIC HORI
+2CCE; C; 2CCF; # COPTIC CAPITAL LETTER OLD COPTIC HA
+2CD0; C; 2CD1; # COPTIC CAPITAL LETTER L-SHAPED HA
+2CD2; C; 2CD3; # COPTIC CAPITAL LETTER OLD COPTIC HEI
+2CD4; C; 2CD5; # COPTIC CAPITAL LETTER OLD COPTIC HAT
+2CD6; C; 2CD7; # COPTIC CAPITAL LETTER OLD COPTIC GANGIA
+2CD8; C; 2CD9; # COPTIC CAPITAL LETTER OLD COPTIC DJA
+2CDA; C; 2CDB; # COPTIC CAPITAL LETTER OLD COPTIC SHIMA
+2CDC; C; 2CDD; # COPTIC CAPITAL LETTER OLD NUBIAN SHIMA
+2CDE; C; 2CDF; # COPTIC CAPITAL LETTER OLD NUBIAN NGI
+2CE0; C; 2CE1; # COPTIC CAPITAL LETTER OLD NUBIAN NYI
+2CE2; C; 2CE3; # COPTIC CAPITAL LETTER OLD NUBIAN WAU
+FB00; F; 0066 0066; # LATIN SMALL LIGATURE FF
+FB01; F; 0066 0069; # LATIN SMALL LIGATURE FI
+FB02; F; 0066 006C; # LATIN SMALL LIGATURE FL
+FB03; F; 0066 0066 0069; # LATIN SMALL LIGATURE FFI
+FB04; F; 0066 0066 006C; # LATIN SMALL LIGATURE FFL
+FB05; F; 0073 0074; # LATIN SMALL LIGATURE LONG S T
+FB06; F; 0073 0074; # LATIN SMALL LIGATURE ST
+FB13; F; 0574 0576; # ARMENIAN SMALL LIGATURE MEN NOW
+FB14; F; 0574 0565; # ARMENIAN SMALL LIGATURE MEN ECH
+FB15; F; 0574 056B; # ARMENIAN SMALL LIGATURE MEN INI
+FB16; F; 057E 0576; # ARMENIAN SMALL LIGATURE VEW NOW
+FB17; F; 0574 056D; # ARMENIAN SMALL LIGATURE MEN XEH
+FF21; C; FF41; # FULLWIDTH LATIN CAPITAL LETTER A
+FF22; C; FF42; # FULLWIDTH LATIN CAPITAL LETTER B
+FF23; C; FF43; # FULLWIDTH LATIN CAPITAL LETTER C
+FF24; C; FF44; # FULLWIDTH LATIN CAPITAL LETTER D
+FF25; C; FF45; # FULLWIDTH LATIN CAPITAL LETTER E
+FF26; C; FF46; # FULLWIDTH LATIN CAPITAL LETTER F
+FF27; C; FF47; # FULLWIDTH LATIN CAPITAL LETTER G
+FF28; C; FF48; # FULLWIDTH LATIN CAPITAL LETTER H
+FF29; C; FF49; # FULLWIDTH LATIN CAPITAL LETTER I
+FF2A; C; FF4A; # FULLWIDTH LATIN CAPITAL LETTER J
+FF2B; C; FF4B; # FULLWIDTH LATIN CAPITAL LETTER K
+FF2C; C; FF4C; # FULLWIDTH LATIN CAPITAL LETTER L
+FF2D; C; FF4D; # FULLWIDTH LATIN CAPITAL LETTER M
+FF2E; C; FF4E; # FULLWIDTH LATIN CAPITAL LETTER N
+FF2F; C; FF4F; # FULLWIDTH LATIN CAPITAL LETTER O
+FF30; C; FF50; # FULLWIDTH LATIN CAPITAL LETTER P
+FF31; C; FF51; # FULLWIDTH LATIN CAPITAL LETTER Q
+FF32; C; FF52; # FULLWIDTH LATIN CAPITAL LETTER R
+FF33; C; FF53; # FULLWIDTH LATIN CAPITAL LETTER S
+FF34; C; FF54; # FULLWIDTH LATIN CAPITAL LETTER T
+FF35; C; FF55; # FULLWIDTH LATIN CAPITAL LETTER U
+FF36; C; FF56; # FULLWIDTH LATIN CAPITAL LETTER V
+FF37; C; FF57; # FULLWIDTH LATIN CAPITAL LETTER W
+FF38; C; FF58; # FULLWIDTH LATIN CAPITAL LETTER X
+FF39; C; FF59; # FULLWIDTH LATIN CAPITAL LETTER Y
+FF3A; C; FF5A; # FULLWIDTH LATIN CAPITAL LETTER Z
+10400; C; 10428; # DESERET CAPITAL LETTER LONG I
+10401; C; 10429; # DESERET CAPITAL LETTER LONG E
+10402; C; 1042A; # DESERET CAPITAL LETTER LONG A
+10403; C; 1042B; # DESERET CAPITAL LETTER LONG AH
+10404; C; 1042C; # DESERET CAPITAL LETTER LONG O
+10405; C; 1042D; # DESERET CAPITAL LETTER LONG OO
+10406; C; 1042E; # DESERET CAPITAL LETTER SHORT I
+10407; C; 1042F; # DESERET CAPITAL LETTER SHORT E
+10408; C; 10430; # DESERET CAPITAL LETTER SHORT A
+10409; C; 10431; # DESERET CAPITAL LETTER SHORT AH
+1040A; C; 10432; # DESERET CAPITAL LETTER SHORT O
+1040B; C; 10433; # DESERET CAPITAL LETTER SHORT OO
+1040C; C; 10434; # DESERET CAPITAL LETTER AY
+1040D; C; 10435; # DESERET CAPITAL LETTER OW
+1040E; C; 10436; # DESERET CAPITAL LETTER WU
+1040F; C; 10437; # DESERET CAPITAL LETTER YEE
+10410; C; 10438; # DESERET CAPITAL LETTER H
+10411; C; 10439; # DESERET CAPITAL LETTER PEE
+10412; C; 1043A; # DESERET CAPITAL LETTER BEE
+10413; C; 1043B; # DESERET CAPITAL LETTER TEE
+10414; C; 1043C; # DESERET CAPITAL LETTER DEE
+10415; C; 1043D; # DESERET CAPITAL LETTER CHEE
+10416; C; 1043E; # DESERET CAPITAL LETTER JEE
+10417; C; 1043F; # DESERET CAPITAL LETTER KAY
+10418; C; 10440; # DESERET CAPITAL LETTER GAY
+10419; C; 10441; # DESERET CAPITAL LETTER EF
+1041A; C; 10442; # DESERET CAPITAL LETTER VEE
+1041B; C; 10443; # DESERET CAPITAL LETTER ETH
+1041C; C; 10444; # DESERET CAPITAL LETTER THEE
+1041D; C; 10445; # DESERET CAPITAL LETTER ES
+1041E; C; 10446; # DESERET CAPITAL LETTER ZEE
+1041F; C; 10447; # DESERET CAPITAL LETTER ESH
+10420; C; 10448; # DESERET CAPITAL LETTER ZHEE
+10421; C; 10449; # DESERET CAPITAL LETTER ER
+10422; C; 1044A; # DESERET CAPITAL LETTER EL
+10423; C; 1044B; # DESERET CAPITAL LETTER EM
+10424; C; 1044C; # DESERET CAPITAL LETTER EN
+10425; C; 1044D; # DESERET CAPITAL LETTER ENG
+10426; C; 1044E; # DESERET CAPITAL LETTER OI
+10427; C; 1044F; # DESERET CAPITAL LETTER EW

+ 159 - 0
libs/physfs-2.0.3/extras/globbing.c

@@ -0,0 +1,159 @@
+/** \file globbing.c */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "physfs.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 LICENSE.txt in the root of the source tree.
+ *
+ *  \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 */
+
+
+char **PHYSFSEXT_enumerateFilesWildcard(const char *dir, const char *wildcard,
+                                        int caseSensitive)
+{
+    char **rc = PHYSFS_enumerateFiles(dir);
+    char **i = rc;
+    char **j;
+
+    while (*i != NULL)
+    {
+        if (matchesPattern(*i, wildcard, caseSensitive))
+            i++;
+        else
+        {
+            /* FIXME: This counts on physfs's allocation method not changing! */
+            free(*i);
+            for (j = i; *j != NULL; j++)
+                j[0] = j[1];
+        } /* else */
+    } /* for */
+
+    return(rc);
+} /* 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);
+
+    PHYSFS_freeList(flist);
+    PHYSFS_deinit();
+
+    return(0);
+} /* main */
+#endif
+
+/* end of globbing.c ... */
+

+ 89 - 0
libs/physfs-2.0.3/extras/globbing.h

@@ -0,0 +1,89 @@
+#ifndef INCL_PHYSFSEXT_GLOBBING_H
+#define INCL_PHYSFSEXT_GLOBBING_H
+
+/** \file globbing.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_enumerateFilesPattern() when enumerating files. This is just
+ *  like PHYSFS_enumerateFiles(), but it returns a subset that matches your
+ *  wildcard pattern. You must call PHYSFS_freeList() on the results, just
+ *  like you would with PHYSFS_enumerateFiles().
+ *
+ * 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 char **PHYSFS_enumerateFilesWildcard(const char *dir, const char *wildcard, int caseSensitive)
+ * \brief Get a file listing of a search path's directory.
+ *
+ * Matching directories are interpolated. That is, if "C:\mydir" is in the
+ *  search path and contains a directory "savegames" that contains "x.sav",
+ *  "y.Sav", and "z.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 PHYSFS_freeList() with the return value from this
+ *  function when you are done with it.
+ *
+ *    \param dir directory in platform-independent notation to enumerate.
+ *   \return Null-terminated array of null-terminated strings.
+ */
+__EXPORT__ char **PHYSFSEXT_enumerateFilesWildcard(const char *dir,
+                                                   const char *wildcard,
+                                                   int caseSensitive);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* include-once blocker. */
+
+/* end of globbing.h ... */
+

+ 219 - 0
libs/physfs-2.0.3/extras/ignorecase.c

@@ -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 ... */
+

+ 87 - 0
libs/physfs-2.0.3/extras/ignorecase.h

@@ -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
libs/physfs-2.0.3/extras/makecasefoldhashtable.pl

@@ -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 ...
+

+ 103 - 0
libs/physfs-2.0.3/extras/physfs_rb/installer.rb

@@ -0,0 +1,103 @@
+# $Id: installer.rb,v 1.3 2003/07/21 03:46:50 icculus Exp $
+
+require 'rbconfig'
+require 'find'
+require 'ftools'
+
+include Config
+
+module Slimb
+  class Installer
+    def initialize target_dir = "", &user_skip 
+      @user_skip = user_skip or proc {|f| false}
+      
+      @version = CONFIG["MAJOR"] + "." + CONFIG["MINOR"]
+      @libdir = File.join(CONFIG["libdir"], "ruby", @version)
+      @sitedir = CONFIG["sitedir"] || File.join(@libdir, "site_ruby")
+      @dest = File.join @sitedir, target_dir
+
+      File::makedirs @dest
+      File::chmod 0755, @dest, true
+    end
+
+    def skip? file
+      @user_skip[file] or
+	file[0] == ?. or file[-1] == ?~ or file[-1] == ?#
+    end
+    
+    def install_dir dir 
+      File::makedirs(File.join(@dest, dir))
+      File::chmod(0755, File.join(@dest, dir), true)
+      Dir.foreach(dir) {|file|
+	next if skip? file
+	
+	if File.ftype(File.join(dir, file)) == "directory"
+	  install_dir File.join(dir, file)
+	else
+	  install_file File.join(dir, file)
+	end
+      }
+    end
+
+    def install_file file
+      if file =~ /\.so$/
+	install_so file
+      else
+	File::install file, File.join(@dest, file), 0644, true
+      end
+    end
+
+    def install_so file
+      File::install file, File.join(CONFIG["sitearchdir"], file), 0644, true
+    end
+
+    def uninstall_so file
+      file = File.join(CONFIG["sitearchdir"], file)
+      File::safe_unlink file
+    end
+
+    def install something
+      case something
+      when Array
+	something.each {|x|
+	  install x if x.is_a? String
+	}
+      when String
+	if File.ftype(something) == "directory"
+	  install_dir something
+	else
+	  install_file something
+	end
+      end
+    end
+
+    def uninstall what = "*"
+      case what
+      when Array
+	files = what.map {|x| File.join(@dest, x)}
+      when String
+	files = Dir[File.join(@dest, what)]
+      end
+      
+      files.each {|x|
+	# FIXME: recursive uninstall is a must
+	next if FileTest.directory? x
+	File::safe_unlink x
+      }
+    end
+
+    def run files, argv
+      if !argv.grep(/--uninstall/).empty?
+	uninstall files
+      else
+	install files
+      end	
+    end
+  end
+end
+
+# self-installation 
+if $0 == __FILE__
+  $stderr.puts "Installing slimb installer..."
+  Slimb::Installer.new("slimb").install File.basename(__FILE__)
+end

+ 9 - 0
libs/physfs-2.0.3/extras/physfs_rb/physfs/extconf.rb

@@ -0,0 +1,9 @@
+require 'mkmf'
+
+$CFLAGS += `sdl-config --cflags`.chomp
+$LDFLAGS += `sdl-config --libs`.chomp
+
+have_library "physfs", "PHYSFS_init"
+have_library "SDL", "SDL_AllocRW"
+
+create_makefile "physfs_so"

+ 7 - 0
libs/physfs-2.0.3/extras/physfs_rb/physfs/install.rb

@@ -0,0 +1,7 @@
+#!/usr/local/bin/ruby
+
+if __FILE__ == $0
+  require 'slimb/installer'
+  files = ["physfs.rb", "physfs_so.so"]
+  installer = Slimb::Installer.new.run files, ARGV
+end

+ 9 - 0
libs/physfs-2.0.3/extras/physfs_rb/physfs/make_install_test.sh

@@ -0,0 +1,9 @@
+#!/bin/sh
+ruby extconf.rb
+make
+cd ..
+ruby installer.rb
+cd physfs
+ruby install.rb
+cd test
+ruby test_physfs.rb

+ 121 - 0
libs/physfs-2.0.3/extras/physfs_rb/physfs/physfs.rb

@@ -0,0 +1,121 @@
+#
+# PhysicsFS - ruby interface
+#
+# Author: Ed Sinjiashvili ([email protected])
+# License: LGPL
+#
+
+require 'physfs_so'
+
+module PhysicsFS
+
+  class Version
+    def initialize major, minor, patch
+      @major = major
+      @minor = minor
+      @patch = patch
+    end
+
+    attr_reader :major, :minor, :patch
+
+    def to_s
+      "#@major.#@minor.#@patch"
+    end
+  end
+
+  class ArchiveInfo
+    def initialize ext, desc, author, url
+      @extension = ext
+      @description = desc
+      @author = author
+      @url = url
+    end
+
+    attr_reader :extension, :description
+    attr_reader :author, :url
+
+    def to_s
+      " * #@extension: #@description\n    Written by #@author.\n    #@url\n"
+    end
+  end
+
+  #
+  # convenience methods
+  #
+  class << self  
+
+    def init argv0 = $0
+      init_internal argv0
+    end
+
+    def append_search_path str
+      add_to_search_path str, 1
+      self
+    end
+
+    def prepend_search_path str
+      add_to_search_path str, 0
+      self
+    end
+
+    alias_method :<<,      :append_search_path
+    alias_method :push,    :append_search_path
+    alias_method :unshift, :prepend_search_path
+
+    def ls path = ""
+      enumerate path
+    end
+  end
+
+  #
+  # File - PhysicsFS abstract file - can be drawn from various sources
+  # 
+  class File
+    def write_str str
+      write str, 1, str.length
+    end
+    
+    def cat
+      prev_pos = tell
+      seek 0
+      r = read length, 1
+      seek prev_pos
+      r
+    end
+    
+    alias_method :size, :length
+  end
+
+  #
+  # RWops - general stdio like operations on file-like creatures
+  #
+  class RWops
+    SEEK_SET = 0
+    SEEK_CUR = 1
+    SEEK_END = 2
+
+    # tell current position of RWopted entity
+    def tell
+      seek 0, SEEK_CUR
+    end
+
+    # length of RWops abstracted entity
+    def length
+      cur = tell
+      r = seek 0, SEEK_END
+      seek cur, SEEK_SET
+      r
+    end
+
+    alias_method :size, :length
+
+    #
+    # create rwops from PhysicsFS file object
+    # 
+    def self.from_physfs file
+      file.to_rwops
+    end
+  end
+end
+
+# physfs.rb ends here #

+ 192 - 0
libs/physfs-2.0.3/extras/physfs_rb/physfs/physfsrwops.c

@@ -0,0 +1,192 @@
+/*
+ * 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.
+ *
+ * Unless otherwise stated, the rest of PhysicsFS falls under the GNU Lesser
+ *  General Public License: http://www.gnu.org/licenses/lgpl.txt
+ *
+ * SDL falls under the LGPL, too. You can get SDL at http://www.libsdl.org/
+ *
+ *  This file was written by Ryan C. Gordon. ([email protected]).
+ */
+
+#include <stdio.h>  /* used for SEEK_SET, SEEK_CUR, SEEK_END ... */
+#include "physfsrwops.h"
+
+static int physfsrwops_seek(SDL_RWops *rw, int offset, int whence)
+{
+    PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
+    int pos = 0;
+
+    if (whence == SEEK_SET)
+    {
+        pos = offset;
+    } /* if */
+
+    else if (whence == SEEK_CUR)
+    {
+        PHYSFS_sint64 current = PHYSFS_tell(handle);
+        if (current == -1)
+        {
+            SDL_SetError("Can't find position in file: %s",
+                          PHYSFS_getLastError());
+            return(-1);
+        } /* if */
+
+        pos = (int) current;
+        if ( ((PHYSFS_sint64) pos) != current )
+        {
+            SDL_SetError("Can't fit current file position in an int!");
+            return(-1);
+        } /* if */
+
+        if (offset == 0)  /* this is a "tell" call. We're done. */
+            return(pos);
+
+        pos += offset;
+    } /* else if */
+
+    else if (whence == SEEK_END)
+    {
+        PHYSFS_sint64 len = PHYSFS_fileLength(handle);
+        if (len == -1)
+        {
+            SDL_SetError("Can't find end of file: %s", PHYSFS_getLastError());
+            return(-1);
+        } /* if */
+
+        pos = (int) len;
+        if ( ((PHYSFS_sint64) pos) != len )
+        {
+            SDL_SetError("Can't fit end-of-file position in an int!");
+            return(-1);
+        } /* if */
+
+        pos += 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 */
+
+    return(pos);
+} /* physfsrwops_seek */
+
+
+static int physfsrwops_read(SDL_RWops *rw, void *ptr, int size, int maxnum)
+{
+    PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
+    PHYSFS_sint64 rc = PHYSFS_read(handle, ptr, size, maxnum);
+    if (rc != maxnum)
+    {
+        if (!PHYSFS_eof(handle)) /* not EOF? Must be an error. */
+            SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+    } /* if */
+
+    return((int) rc);
+} /* physfsrwops_read */
+
+
+static int physfsrwops_write(SDL_RWops *rw, const void *ptr, int size, int num)
+{
+    PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
+    PHYSFS_sint64 rc = PHYSFS_write(handle, ptr, size, num);
+    if (rc != num)
+        SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+
+    return((int) rc);
+} /* 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 ... */
+

+ 87 - 0
libs/physfs-2.0.3/extras/physfs_rb/physfs/physfsrwops.h

@@ -0,0 +1,87 @@
+/*
+ * 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.
+ *
+ * Unless otherwise stated, the rest of PhysicsFS falls under the GNU Lesser
+ *  General Public License: http://www.gnu.org/licenses/lgpl.txt
+ *
+ * SDL falls under the LGPL, too. You can get SDL at http://www.libsdl.org/
+ *
+ *  This file was written by Ryan C. Gordon. ([email protected]).
+ */
+
+#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().
+ */
+__EXPORT__ 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().
+ */
+__EXPORT__ 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().
+ */
+__EXPORT__ 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().
+ */
+__EXPORT__ SDL_RWops *PHYSFSRWOPS_makeRWops(PHYSFS_file *handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* include-once blocker */
+
+/* end of physfsrwops.h ... */
+

+ 462 - 0
libs/physfs-2.0.3/extras/physfs_rb/physfs/rb_physfs.c

@@ -0,0 +1,462 @@
+/*
+ * PhysicsFS - ruby interface
+ * 
+ * Author::  Ed Sinjiashvili ([email protected])
+ * License:: LGPL
+ */
+
+#include "physfs.h"
+#include "ruby.h"
+
+#include "rb_physfs.h" 
+#include "rb_physfs_file.h"
+
+VALUE modulePhysfs;
+
+/*
+ * PhysicsFS::init str
+ *
+ * initialize PhysicsFS
+ */
+VALUE physfs_init (VALUE self, VALUE str)
+{
+    int result = PHYSFS_init (STR2CSTR(str));
+
+    if (result)
+	return Qtrue;
+
+    return Qfalse;
+}
+
+/*
+ * PhysicsFS::deinit
+ */
+VALUE physfs_deinit (VALUE self)
+{
+    if (PHYSFS_deinit ())
+	return Qtrue;
+
+    return Qfalse;
+}
+
+/*
+ * PhysicsFS::version
+ * 
+ * return PhysicsFS::Version object
+ */
+VALUE physfs_version (VALUE self)
+{
+    char evalStr[200];
+    PHYSFS_Version ver;
+
+    PHYSFS_getLinkedVersion (&ver);
+
+    sprintf (evalStr, "PhysicsFS::Version.new %d, %d, %d", 
+	     ver.major, ver.minor, ver.patch);
+    return rb_eval_string (evalStr);
+}
+
+/*
+ * PhysicsFS::supported_archives
+ *
+ * return Array of PhysicsFS::ArchiveInfo objects
+ */
+VALUE physfs_supported_archives (VALUE self)
+{
+    const PHYSFS_ArchiveInfo **info = PHYSFS_supportedArchiveTypes();
+    VALUE klass = rb_const_get (modulePhysfs, rb_intern ("ArchiveInfo"));
+    VALUE ary = rb_ary_new ();
+    VALUE params[4];
+
+    while ( *info != 0 ) 
+    {
+        params[0] = rb_str_new2 ((*info)->extension);
+        params[1] = rb_str_new2 ((*info)->description);
+        params[2] = rb_str_new2 ((*info)->author);
+        params[3] = rb_str_new2 ((*info)->url);
+
+        rb_ary_push (ary, rb_class_new_instance (4, params, klass));
+        info++;
+    }
+
+    return ary;
+}
+
+/*
+ * PhysicsFS::last_error
+ *
+ * return string representation of last PhysicsFS error
+ */
+VALUE physfs_last_error (VALUE self)
+{
+    const char *last_error = PHYSFS_getLastError ();
+
+    if (last_error == 0)
+	last_error = "";
+
+    return rb_str_new2 (last_error);
+}
+
+/*
+ * PhysicsFS::dir_separator
+ *
+ * return platform directory separator
+ */
+VALUE physfs_dir_separator (VALUE self)
+{
+    return rb_str_new2 (PHYSFS_getDirSeparator ());
+}
+
+/*
+ * PhysicsFS::permit_symlinks boolValue
+ *
+ * turn symlinks support on/off
+ */
+VALUE physfs_permit_symlinks (VALUE self, VALUE allow)
+{
+    int p = 1;
+    
+    if (allow == Qfalse || allow == Qnil)
+        p = 0;
+
+    PHYSFS_permitSymbolicLinks (p);
+    return Qtrue;
+}
+
+/*
+ * PhysicsFS::cdrom_dirs
+ *
+ * return Array of strings containing available CDs 
+ */
+VALUE physfs_cdrom_dirs (VALUE self)
+{
+    char **cds = PHYSFS_getCdRomDirs();
+    char **i;
+    VALUE ary = rb_ary_new ();
+
+    for (i = cds; *i != 0; i++)
+        rb_ary_push (ary, rb_str_new2 (*i));
+
+    PHYSFS_freeList (cds);
+    return ary;
+}
+
+/*
+ * PhysicsFS::base_dir
+ *
+ * return base directory
+ */
+VALUE physfs_base_dir (VALUE self)
+{
+    const char *base_dir = PHYSFS_getBaseDir ();
+    if (base_dir == 0)
+        base_dir = "";
+
+    return rb_str_new2 (base_dir);
+}
+
+/*
+ * PhysicsFS::user_dir
+ *
+ * return user directory
+ */
+VALUE physfs_user_dir (VALUE self)
+{
+    const char *user_dir = PHYSFS_getBaseDir ();
+    if (user_dir == 0)
+        user_dir = "";
+
+    return rb_str_new2 (user_dir);
+}
+   
+/*
+ * PhysicsFS::write_dir 
+ *
+ * return write directory
+ */
+VALUE physfs_write_dir (VALUE self)
+{
+    const char *write_dir = PHYSFS_getWriteDir ();
+    if (write_dir == 0)
+        return Qnil;
+
+    return rb_str_new2 (write_dir);
+}
+
+/*
+ * PhysicsFS::write_dir= str
+ *
+ * set write directory to *str*
+ */
+VALUE physfs_set_write_dir (VALUE self, VALUE str)
+{
+    int result = PHYSFS_setWriteDir (STR2CSTR(str));
+
+    if (result)
+        return Qtrue;
+    return Qfalse;
+}
+
+/*
+ * PhysicsFS::add_to_search_path str, append
+ *
+ * if append > 0 - append str to search path, otherwise prepend it
+ */
+VALUE physfs_add_search_path (VALUE self, VALUE str, VALUE append)
+{
+    int result = PHYSFS_addToSearchPath (STR2CSTR(str), FIX2INT(append));
+    if (result)
+        return Qtrue;
+    return Qfalse;
+}
+
+/*
+ * PhysicsFS::remove_from_search_path str
+ *
+ * removes str from search path
+ */
+VALUE physfs_remove_search_path (VALUE self, VALUE str)
+{
+    int result = PHYSFS_removeFromSearchPath (STR2CSTR(str));
+    if (result)
+        return Qtrue;
+    return Qfalse;
+}
+
+/*
+ * PhysicsFS::search_path
+ *
+ * return current search_path - as array of strings
+ */
+VALUE physfs_search_path (VALUE self)
+{
+    char **path = PHYSFS_getSearchPath ();
+    char **i;
+    VALUE ary = rb_ary_new ();
+
+    for (i = path ; *i != 0; i++)
+        rb_ary_push (ary, rb_str_new2 (*i));
+
+    PHYSFS_freeList (path);
+    return ary;
+}
+
+// 
+VALUE physfs_setSaneConfig(VALUE self, VALUE org, VALUE app, VALUE ext,
+                           VALUE includeCdroms, VALUE archivesFirst)
+{
+    int res = PHYSFS_setSaneConfig (STR2CSTR(org), STR2CSTR(app), STR2CSTR(ext),
+                                   RTEST(includeCdroms), RTEST(archivesFirst));
+    if (res)
+        return Qtrue;
+
+    return Qfalse;
+}
+
+/*
+ * PhysicsFS::mkdir newdir
+ *
+ * create new directory 
+ */ 
+VALUE physfs_mkdir (VALUE self, VALUE newdir)
+{
+    int result = PHYSFS_mkdir (STR2CSTR(newdir));
+    if (result)
+        return Qtrue;
+    return Qfalse;
+}
+
+/*
+ * PhysicsFS::delete name
+ *
+ * delete file with name
+ */
+VALUE physfs_delete (VALUE self, VALUE name)
+{
+    int result = PHYSFS_delete (STR2CSTR(name));
+    if (result)
+        return Qtrue;
+    return Qfalse;
+}
+
+/*
+ * PhysicsFS::real_dir name
+ *
+ * return real directory (in search path) of a name
+ */
+VALUE physfs_real_dir (VALUE self, VALUE name)
+{
+    const char *path = PHYSFS_getRealDir (STR2CSTR(name));
+    if (path == 0)
+        return Qnil;
+
+    return rb_str_new2 (path);
+}
+
+/*
+ * PhysicsFS::enumerate dir
+ *
+ * list a dir from a search path
+ */
+VALUE physfs_enumerate (VALUE self, VALUE dir)
+{
+    char **files = PHYSFS_enumerateFiles (STR2CSTR(dir));
+    char **i;
+    VALUE ary = rb_ary_new ();
+
+    for (i = files; *i != 0; i++)
+        rb_ary_push (ary, rb_str_new2 (*i));
+
+    PHYSFS_freeList (files);
+    return ary;
+}
+
+/*
+ * PhysicsFS::exists? name
+ *
+ * does a file with name exist?
+ */
+VALUE physfs_exists (VALUE self, VALUE name)
+{
+    int result = PHYSFS_exists (STR2CSTR(name));
+    if (result)
+        return Qtrue;
+    return Qfalse;
+}
+
+/*
+ * PhysicsFS::is_directory? name
+ *
+ * return true if name is directory
+ */
+VALUE physfs_is_directory (VALUE self, VALUE name)
+{
+    int result = PHYSFS_isDirectory (STR2CSTR(name));
+    if (result)
+        return Qtrue;
+    return Qfalse;
+}
+
+/*
+ * PhysicsFS::is_symlink? name
+ *
+ * return true if name is symlink
+ */
+VALUE physfs_is_symlink (VALUE self, VALUE name)
+{
+    int result = PHYSFS_isSymbolicLink (STR2CSTR(name));
+    if (result)
+        return Qtrue;
+    return Qfalse;
+}
+
+/*
+ * PhysicsFS::last_mod_time name
+ *
+ * return last modification time of a file
+ */
+VALUE physfs_last_mod_time (VALUE self, VALUE name)
+{
+    int result = PHYSFS_getLastModTime (STR2CSTR(name));
+    
+    return INT2FIX(result);
+}
+
+/*
+ * PhysicsFS::open_read name
+ *
+ * return +PhysicsFS::File+ ready for reading
+ */
+VALUE physfs_open_read (VALUE self, VALUE name)
+{
+    PHYSFS_File *file = PHYSFS_openRead (STR2CSTR(name));
+    return physfs_file_new (file);
+}
+
+/*
+ * PhysicsFS::open_write name
+ *
+ * return PhysicsFS::File ready for writing
+ */
+VALUE physfs_open_write (VALUE self, VALUE name)
+{
+    PHYSFS_File *file = PHYSFS_openWrite (STR2CSTR(name));
+    return physfs_file_new (file);
+}
+
+/*
+ * PhysicsFS::open_append name
+ *
+ * return PhysicsFS::File ready for appending
+ */
+VALUE physfs_open_append (VALUE self, VALUE name)
+{
+    PHYSFS_File *file = PHYSFS_openAppend (STR2CSTR(name));
+    return physfs_file_new (file);
+}
+
+void Init_physfs_so (void)
+{
+    modulePhysfs = rb_define_module ("PhysicsFS");
+
+    rb_define_singleton_method (modulePhysfs, "init_internal", physfs_init, 1);
+    rb_define_singleton_method (modulePhysfs, "deinit", physfs_deinit, 0);
+    rb_define_singleton_method (modulePhysfs, "version", physfs_version, 0);
+    rb_define_singleton_method (modulePhysfs, "supported_archives",
+				physfs_supported_archives, 0);
+    rb_define_singleton_method (modulePhysfs, "last_error", 
+				physfs_last_error, 0);
+    rb_define_singleton_method (modulePhysfs, "dir_separator",
+				physfs_dir_separator, 0);
+    rb_define_singleton_method (modulePhysfs, "permit_symlinks",
+                                physfs_permit_symlinks, 1);
+    rb_define_singleton_method (modulePhysfs, "cdrom_dirs", 
+                                physfs_cdrom_dirs, 0);
+    rb_define_singleton_method (modulePhysfs, "base_dir", physfs_base_dir, 0);
+    rb_define_singleton_method (modulePhysfs, "user_dir", physfs_user_dir, 0);
+
+    rb_define_singleton_method (modulePhysfs, "write_dir", physfs_write_dir, 0);
+    rb_define_singleton_method (modulePhysfs, "write_dir=", 
+                                physfs_set_write_dir, 1);
+
+    rb_define_singleton_method (modulePhysfs, "add_to_search_path",
+                                physfs_add_search_path, 2);
+    rb_define_singleton_method (modulePhysfs, "remove_from_search_path",
+                                physfs_remove_search_path, 1);
+    rb_define_singleton_method (modulePhysfs, "search_path",
+                                physfs_search_path, 0);
+
+    rb_define_singleton_method (modulePhysfs, "set_sane_config",
+                                physfs_setSaneConfig, 5);
+
+    rb_define_singleton_method (modulePhysfs, "mkdir", physfs_mkdir, 1);
+    rb_define_singleton_method (modulePhysfs, "delete", physfs_delete, 1);
+    rb_define_singleton_method (modulePhysfs, "real_dir",
+                                physfs_real_dir, 1);
+    rb_define_singleton_method (modulePhysfs, "enumerate", physfs_enumerate, 1);
+    rb_define_singleton_method (modulePhysfs, "exists?", physfs_exists, 1);
+    rb_define_singleton_method (modulePhysfs, "is_directory?", 
+                                physfs_is_directory, 1);
+    rb_define_singleton_method (modulePhysfs, "is_symlink?", 
+                                physfs_is_symlink, 1);
+    rb_define_singleton_method (modulePhysfs, "last_mod_time",
+                                physfs_last_mod_time, 1);
+
+    rb_define_singleton_method (modulePhysfs, "open_read", 
+                                physfs_open_read, 1);
+    rb_define_singleton_method (modulePhysfs, "open_write", 
+                                physfs_open_write, 1);
+    rb_define_singleton_method (modulePhysfs, "open_append", 
+                                physfs_open_append, 1);
+
+    init_physfs_file ();
+    init_sdl_rwops ();
+}
+
+/*
+// Local Variables:
+// mode: C
+// c-indentation-style: "stroustrup"
+// indent-tabs-mode: nil
+// End:
+*/

+ 13 - 0
libs/physfs-2.0.3/extras/physfs_rb/physfs/rb_physfs.h

@@ -0,0 +1,13 @@
+/*
+ * PhysicsFS - ruby interface
+ * 
+ * Author::  Ed Sinjiashvili ([email protected])
+ * License:: LGPL
+ */
+
+#ifndef __RB__PHYSFS__H__
+#define __RB__PHYSFS__H__
+
+extern VALUE modulePhysfs;
+
+#endif

+ 226 - 0
libs/physfs-2.0.3/extras/physfs_rb/physfs/rb_physfs_file.c

@@ -0,0 +1,226 @@
+/*
+ * PhysicsFS File abstraction - ruby interface
+ * 
+ * Author::  Ed Sinjiashvili ([email protected])
+ * License:: LGPL
+ */
+
+#include "physfs.h"
+#include "ruby.h"
+
+#include "rb_physfs.h"
+#include "rb_physfs_file.h"
+#include "physfsrwops.h"
+
+VALUE classPhysfsFile;
+
+/*
+ * construct new PhysicsFS::File object
+ */
+VALUE physfs_file_new (PHYSFS_File *file)
+{
+    if (file == 0)
+        return Qnil;
+
+    return Data_Wrap_Struct (classPhysfsFile, 0, 0, file);
+}
+
+/*
+ * PhysicsFS::File#close 
+ *
+ * Close the file. It's illegal to use the object after its closure.
+ */
+VALUE physfs_file_close (VALUE self)
+{
+    int result;
+    PHYSFS_File *file;
+    Data_Get_Struct (self, PHYSFS_File, file);
+
+    if (file == 0)
+	return Qfalse;
+
+    result = PHYSFS_close (file);
+    DATA_PTR(self) = 0;
+
+    if (result)
+        return Qtrue;
+    return Qfalse;
+}
+
+/*
+ * PhysicsFS::File#read obj_size, num_objects
+ *
+ * Read *objCount* objects which are *objSize* each.
+ * return String instance containing raw data or nil if failure.
+ * #length of string will reflect real number of objects read.
+ */
+VALUE physfs_file_read (VALUE self, VALUE objSize, VALUE objCount)
+{
+    int objRead;
+    void *buffer;
+    VALUE result;
+    PHYSFS_File *file;
+
+    Data_Get_Struct (self, PHYSFS_File, file);
+    if (file == 0)
+	return Qnil; //wasted file - no read possible
+
+    buffer  = malloc (FIX2UINT(objSize) * FIX2UINT(objCount));
+    if (buffer == 0)
+	return Qnil;
+
+    objRead = PHYSFS_read (file, buffer, FIX2UINT(objSize), FIX2UINT(objCount));
+    if (objRead == -1)
+    {
+        free (buffer);
+        return Qnil;
+    }
+
+    result = rb_str_new (buffer, objRead * FIX2UINT(objSize));
+    free (buffer);
+    return result;
+}
+
+/*
+ * PhysicsFS::File#write buffer, obj_size, num_objects
+ *
+ * return nil on failure or number of objects written.
+ */
+VALUE physfs_file_write (VALUE self, VALUE buf, VALUE objSize, VALUE objCount)
+{
+    int result;
+    PHYSFS_File *file;
+
+    Data_Get_Struct (self, PHYSFS_File, file);
+    if (file == 0)
+	return Qnil;
+
+    result = PHYSFS_write (file, STR2CSTR(buf), 
+                           FIX2UINT(objSize), FIX2UINT(objCount));
+    if (result == -1)
+        return Qnil;
+
+    return INT2FIX(result);
+}
+
+/*
+ * PhysicsFS::File#eof? 
+ */
+VALUE physfs_file_eof (VALUE self)
+{
+    int result;
+    PHYSFS_File *file;
+
+    Data_Get_Struct (self, PHYSFS_File, file);
+    if (file == 0)
+	return Qnil;
+
+    result = PHYSFS_eof (file);
+
+    if (result)
+        return Qtrue;
+
+    return Qfalse;
+}
+
+/*
+ * PhysicsFS::File#tell
+ *
+ * tells current position in file
+ */
+VALUE physfs_file_tell (VALUE self)
+{
+    int result;
+    PHYSFS_File *file;
+
+    Data_Get_Struct (self, PHYSFS_File, file);
+    if (file == 0)
+	return Qnil;
+
+    result = PHYSFS_tell (file);
+
+    if (result == -1)
+        return Qnil;
+
+    return INT2FIX(result);
+}    
+
+/*
+ * PhysicsFS::File#seek pos
+ *
+ * seek to pos in file
+ */
+VALUE physfs_file_seek (VALUE self, VALUE pos)
+{
+    int result;
+    PHYSFS_File *file;
+
+    Data_Get_Struct (self, PHYSFS_File, file);
+    if (file == 0)
+	return Qnil;
+
+    result = PHYSFS_seek (file, FIX2LONG(pos));
+
+    if (result)
+        return Qtrue;
+
+    return Qfalse;    
+}
+
+/*
+ * PhysicsFS::File#length 
+ */
+VALUE physfs_file_length (VALUE self)
+{
+    int result;
+    PHYSFS_File *file;
+
+    Data_Get_Struct (self, PHYSFS_File, file);
+    if (file == 0)
+	return Qnil;
+
+    result = PHYSFS_fileLength (file);
+
+    if (result == -1)
+        return Qnil;
+
+    return INT2FIX(result);
+}
+
+/*
+ * PhysicsFS::File#to_rwops
+ *
+ * File object is converted to RWops object. 
+ * File object becomes unusable after that - every operation
+ * should be done through new-born RWops object. 
+ */
+VALUE physfs_file_to_rwops (VALUE self)
+{
+    PHYSFS_File *file;
+    SDL_RWops   *rwops;
+
+    Data_Get_Struct (self, PHYSFS_File, file);
+    if (file == 0)
+	return Qnil;
+
+    rwops = PHYSFSRWOPS_makeRWops (file);
+    if (rwops == 0)
+	return Qnil;
+
+    DATA_PTR(self) = 0; // oh, gosh, we've sacrificed ourselves!
+    return sdl_rwops_new (rwops);
+}
+
+void init_physfs_file (void)
+{
+    classPhysfsFile = rb_define_class_under (modulePhysfs, "File", rb_cObject);
+
+    rb_define_method (classPhysfsFile, "close",    physfs_file_close,    0);
+    rb_define_method (classPhysfsFile, "eof?",     physfs_file_eof,      0);
+    rb_define_method (classPhysfsFile, "tell",     physfs_file_tell,     0);
+    rb_define_method (classPhysfsFile, "seek",     physfs_file_seek,     1);
+    rb_define_method (classPhysfsFile, "length",   physfs_file_length,   0);
+    rb_define_method (classPhysfsFile, "read",     physfs_file_read,     2);
+    rb_define_method (classPhysfsFile, "write",    physfs_file_write,    3);
+    rb_define_method (classPhysfsFile, "to_rwops", physfs_file_to_rwops, 0);
+}

+ 24 - 0
libs/physfs-2.0.3/extras/physfs_rb/physfs/rb_physfs_file.h

@@ -0,0 +1,24 @@
+/*
+ * PhysicsFS File abstraction - ruby interface
+ * 
+ * Author::  Ed Sinjiashvili ([email protected])
+ * License:: LGPL
+ */
+
+#ifndef __RB__PHYSFS__FILE__H__
+#define __RB__PHYSFS__FILE__H__
+
+extern VALUE classPhysfsFile;
+
+VALUE physfs_file_new    (PHYSFS_file *file);
+VALUE physfs_file_close  (VALUE self);
+VALUE physfs_file_read   (VALUE self, VALUE objSize, VALUE objCount);
+VALUE physfs_file_write  (VALUE self, VALUE buf, VALUE objSize, VALUE objCount);
+VALUE physfs_file_eof    (VALUE self);
+VALUE physfs_file_tell   (VALUE self);
+VALUE physfs_file_seek   (VALUE self, VALUE pos);
+VALUE physfs_file_length (VALUE self);
+
+void init_physfs_file (void);
+
+#endif

+ 162 - 0
libs/physfs-2.0.3/extras/physfs_rb/physfs/rb_sdl_rwops.c

@@ -0,0 +1,162 @@
+/*
+ * SDL_RWops - ruby interface
+ *
+ * Author::	Ed Sinjiashvili ([email protected])
+ * License::	LGPL
+ */
+
+#include "SDL_rwops.h"
+#include "ruby.h"
+
+#include "rb_physfs.h"
+#include "rb_sdl_rwops.h"
+
+VALUE classRWops;
+
+/*
+ * RWops constructor
+ */
+VALUE sdl_rwops_new (SDL_RWops *ops)
+{
+    VALUE result; 
+
+    if (ops == 0)
+	return Qnil;
+
+    result = Data_Wrap_Struct (classRWops, 0, SDL_FreeRW, ops);
+    return result;
+}
+
+/*
+ * PhysicsFS::RWops::from_file name, mode
+ *
+ * create RWops object from file
+ */
+VALUE sdl_rwops_from_file (VALUE self, VALUE name, VALUE mode)
+{
+    SDL_RWops *ops = SDL_RWFromFile(STR2CSTR(name), STR2CSTR(mode));
+    return sdl_rwops_new (ops);
+}
+
+/*
+ * PhysicsFS::RWops::from_memory string
+ *
+ * create RWops object from memory
+ */
+VALUE sdl_rwops_from_mem (VALUE self, VALUE str)
+{
+    int	  len	   = RSTRING(str)->len;
+    void *mem	   = STR2CSTR(str);
+    SDL_RWops *ops = SDL_RWFromMem(mem, len);
+
+    return sdl_rwops_new (ops);
+}
+
+/*
+ * PhysicsFS::RWops#seek offset, whence
+ *
+ * position RWops object 
+ */
+VALUE sdl_rwops_seek (VALUE self, VALUE offset, VALUE whence)
+{
+    int result;
+    SDL_RWops *ops;
+    
+    Data_Get_Struct (self, SDL_RWops, ops);
+    if (ops == 0)
+	return Qnil;
+
+    result = SDL_RWseek(ops, FIX2INT(offset), FIX2INT(whence));
+    return INT2FIX(result);
+}
+
+/*
+ * PhysicsFS::RWops#close
+ *
+ * close RWops. No use of the object is possible after that.
+ */
+VALUE sdl_rwops_close (VALUE self)
+{
+    int result;
+    SDL_RWops *ops;
+    
+    Data_Get_Struct (self, SDL_RWops, ops);
+    if (ops == 0)
+	return Qnil;
+    
+    result = SDL_RWclose (ops);
+    DATA_PTR(self) = 0;
+
+    return INT2FIX(result);
+}
+
+/*
+ * PhysicsFS::RWops#read
+ *
+ * read from RWops object objCount objSize'd entities.
+ * return string containing raw data or nil
+ */
+VALUE sdl_rwops_read (VALUE self, VALUE objSize, VALUE objCount)
+{
+    int objRead;
+    void *buffer;
+    VALUE result;
+    SDL_RWops *ops;
+
+    Data_Get_Struct (self, SDL_RWops, ops);
+    if (ops == 0)
+	return Qnil;
+
+    buffer = malloc (FIX2UINT(objSize) * FIX2UINT(objCount));
+    if (buffer == 0)
+	return Qnil;
+
+    objRead = SDL_RWread (ops, buffer, FIX2UINT(objSize), FIX2UINT(objCount));
+    if (objRead == -1)
+    {
+	free (buffer);
+	return Qnil;
+    }
+
+    result = rb_str_new (buffer, objRead * FIX2UINT(objSize));
+    free (buffer);
+    return result;
+}
+
+/*
+ * PhysicsFS::RWops#write buffer, size, n
+ *
+ * write raw string containing n objects size length each.
+ * return number of objects written or nil
+ */
+VALUE sdl_rwops_write (VALUE self, VALUE buffer, VALUE size, VALUE n)
+{
+    int result;
+    SDL_RWops *ops;
+
+    Data_Get_Struct (self, SDL_RWops, ops);
+    if (ops == 0)
+	return Qnil;
+
+    result = SDL_RWwrite (ops, STR2CSTR(buffer), FIX2INT(size), FIX2INT(n));
+	
+    if (result == -1)
+	return Qnil;
+
+    return INT2FIX(result);
+}
+
+void init_sdl_rwops (void)
+{
+    classRWops = rb_define_class_under (modulePhysfs, "RWops", rb_cObject);
+    
+    rb_define_method (classRWops, "seek",  sdl_rwops_seek,  2);
+    rb_define_method (classRWops, "read",  sdl_rwops_read,  2);
+    rb_define_method (classRWops, "write", sdl_rwops_write, 3);
+    rb_define_method (classRWops, "close", sdl_rwops_close, 0);
+    
+    rb_define_singleton_method (classRWops, "from_file", 
+				sdl_rwops_from_file, 2);
+    rb_define_singleton_method (classRWops, "from_memory", 
+				sdl_rwops_from_mem, 1);
+}

+ 16 - 0
libs/physfs-2.0.3/extras/physfs_rb/physfs/rb_sdl_rwops.h

@@ -0,0 +1,16 @@
+/*
+ * SDL_RWops - ruby interface
+ *
+ * Author::	Ed Sinjiashvili ([email protected])
+ * License::	LGPL
+ */
+
+#ifndef __RB__SDL__RWOPS__H__
+#define __RB__SDL__RWOPS__H__
+
+extern VALUE classRWops;
+
+VALUE sdl_rwops_new (SDL_RWops *ops);
+void init_sdl_rwops (void);
+
+#endif

+ 358 - 0
libs/physfs-2.0.3/extras/physfs_rb/physfs/test/test_physfs.rb

@@ -0,0 +1,358 @@
+#
+# PhysicsFS test program - mimics real physfs_test
+#
+require 'readline'
+require 'physfs'
+
+def die msg
+  puts "#{msg} - reason: #{PhysicsFS.last_error}"
+end
+
+#
+# parse line to command and args
+# 
+def parse line
+  return false if line.nil?
+  
+  if line.strip =~ /^(.*?) (?: (?:\s+(.*)) | $)/x
+    run $1, $2
+  else
+    false
+  end
+end
+
+#
+# parse command args
+# 
+def parse_args args
+  args.strip!
+
+  dquoted  = /^ " (.*?) "/x
+  squoted  = /^ ' (.*?) '/x
+  unquoted = /^([^\s\'\"]+)/
+  
+  regexps = [dquoted, squoted, unquoted]
+  
+  result = []
+  while args != ""
+    regexps.each do |r|
+      if args =~ r
+	result << $1
+	args.sub! r, ""
+	args.sub!(/\s+/, "")
+	break
+      end
+    end
+  end
+  result
+end
+
+def usage cmd, prefix = "usage: "
+  print prefix
+  args = Commands::HELP[cmd]
+  if args
+    print cmd
+    args.scan(/\w+/).each {|x|
+      print " <#{x}>"
+    }
+    puts
+  else
+    puts %|#{cmd} (no arguments)|
+  end
+end
+  
+# commands go below
+module Commands
+  HELP = {
+    "init"           => "argv0",
+    "addarchive"     => "archiveLocation append",
+    "removearchive"  => "archiveLocation",
+    "enumerate"      => "dirToEnumerate",
+    "ls"             => "dirToEnumerate",
+    "setwritedir"    => "newWriteDir",
+    "permitsymlinks" => "1or0",
+    "setsaneconfig"  => "org appName arcExt includeCdRoms archivesFirst",
+    "mkdir"	     => "dirToMk",
+    "delete"         => "dirToDelete",
+    "getrealdir"     => "fileToFind",
+    "exists"         => "fileToCheck",
+    "isdir"          => "fileToCheck",
+    "issymlink"      => "fileToCheck",
+    "cat"            => "fileToCat",
+    "filelength"     => "fileToCheck",
+    "append"         => "fileToAppend",
+    "write"          => "fileToCreateOrTrash",
+    "getlastmodtime" => "fileToExamine"
+  }
+
+  def quit_cmd
+    exit
+  end
+
+  alias q_cmd quit_cmd
+
+  def help_cmd
+    commands = ::Commands.instance_methods.grep(/_cmd$/).sort
+    puts "Commands:"
+    commands.each do |c|
+      usage c.sub("_cmd", ""), "  - "
+    end
+
+    true
+  end
+
+  def e val
+    if val
+      puts "Successful."
+    else
+      puts "Failure. reason: #{PhysicsFS.last_error}"
+    end
+    true
+  end
+
+  def init_cmd arg
+    e PhysicsFS.init(arg)
+  end
+
+  def deinit_cmd
+    e PhysicsFS.deinit
+  end
+
+  def addarchive_cmd archive, append
+    e PhysicsFS.add_to_search_path(archive, append)
+  end
+
+  def removearchive_cmd archive
+    e PhysicsFS.remove_from_search_path archive
+  end
+
+  def enumerate_cmd path
+    entries = PhysicsFS.enumerate(path)
+    entries.each {|x|
+      puts x
+    }
+    true
+  end
+
+  alias ls_cmd enumerate_cmd
+
+  def getlasterror_cmd
+    puts "Last error is [#{PhysicsFS.last_error}]"
+    true
+  end
+
+  def getdirsep_cmd
+    puts "Directory separator is [#{PhysicsFS.dir_separator}]"
+    true
+  end
+
+  def getcdromdirs_cmd
+    dirs = PhysicsFS.cdrom_dirs
+    dirs.each {|x|
+      puts x
+    }
+    puts " total [#{dirs.length}] drives."
+    true
+  end
+
+  def getsearchpath_cmd
+    spath = PhysicsFS.search_path
+    spath.each {|x|
+      puts x
+    }
+    puts "total [#{spath.length}] directories."
+    true
+  end
+
+  def getbasedir_cmd
+    dir = PhysicsFS.base_dir
+    puts dir if dir
+    true
+  end
+
+  def getuserdir_cmd
+    puts PhysicsFS.user_dir
+    true
+  end
+
+  def getwritedir_cmd
+    dir = PhysicsFS.write_dir
+    if dir
+      puts "Write directory is [#{dir}]."
+    else
+      puts "No write directory defined."
+    end
+    true
+  end
+
+  def setwritedir_cmd dir
+    e(PhysicsFS.write_dir = dir)
+  end
+
+  def permitsymlinks_cmd val
+    if val.to_i == 1
+      PhysicsFS.permit_symlinks true
+      puts "Symlinks are now permitted"
+    else
+      PhysicsFS.permit_symlinks false
+      puts "Symlinks are now forbidden"
+    end
+    true
+  end
+
+  def setsaneconfig_cmd org, appname, ext, includeCdroms, archivesFirst
+    includeCdroms = includeCdroms.to_i == 1
+    archiveFirst = archivesFirst == 1
+    e PhysicsFS.set_sane_config(org, appname, ext, includeCdroms, archivesFirst)
+  end
+
+  def mkdir_cmd dir
+    e PhysicsFS.mkdir(dir)
+  end
+
+  def delete_cmd dir
+    e PhysicsFS.delete(dir)
+  end
+
+  def getrealdir_cmd file
+    dir = PhysicsFS.real_dir file
+    if dir
+      puts "Found at [#{dir}]"
+    else
+      puts "Not found."
+    end
+    true
+  end
+
+  def exists_cmd file
+    if PhysicsFS.exists? file
+      puts "File exists"
+    else
+      puts "File does not exist"
+    end
+    true
+  end
+
+  def isdir_cmd file
+    if PhysicsFS.is_directory? file
+      puts "File is a directory"
+    else
+      puts "File is NOT a directory"
+    end
+    true
+  end
+
+  def issymlink_cmd file
+    if PhysicsFS.is_symlink? file
+      puts "File is a symlink"
+    else
+      puts "File is NOT a symlink"
+    end
+    true
+  end
+
+  def cat_cmd filename
+    file = PhysicsFS.open_read filename
+    if file.nil?
+      puts "failed to open. reason: #{PhysicsFS.last_error}"
+      return true
+    end
+
+    puts file.cat
+    true
+  end
+
+  def filelength_cmd filename
+    file = PhysicsFS.open_read filename
+    if file.nil?
+      puts "failed to open. reason: #{PhysicsFS.last_error}"
+      return true
+    end
+
+    puts file.length
+    file.close
+    true
+  end
+
+  WRITE_STR = "Rubyfied PhysicsFS works just fine.\n\n"
+  
+  def append_cmd filename
+    file = PhysicsFS.open_append filename
+    if file.nil?
+      puts "failed to open. reason: #{PhysicsFS.last_error}"
+      return true
+    end
+
+    file.write WRITE_STR, 1, WRITE_STR.length
+    file.close
+    true
+  end
+
+  def write_cmd filename
+    file = PhysicsFS.open_write filename
+    if file.nil?
+      puts "failed to open. reason: #{PhysicsFS.last_error}"
+      return true
+    end
+
+    file.write_str WRITE_STR
+    file.close
+    true
+  end
+
+  def getlastmodtime_cmd filename
+    t = PhysicsFS.last_mod_time filename
+    if t == -1
+      puts "failed to determin. reason: #{PhysicsFS.last_error}"
+    else
+      puts "Last modified: #{Time.at(t)}"
+    end
+    true
+  end
+end
+
+include Commands
+
+def run command, args
+  if args
+    args = parse_args args
+  else
+    args = []
+  end
+
+  begin
+    cmd = method "#{command}_cmd"
+    if args.length == cmd.arity
+      return cmd.call *args
+    else
+      usage command
+      true
+    end
+  rescue NameError
+    puts 'Unknown command. Enter "help" for instructions.'
+    true
+  end
+end
+
+if __FILE__ == $0
+  
+  PhysicsFS.init($0) or die "PhysicsFS init failed"
+  
+  puts "PhysicsFS version: #{PhysicsFS.version}"
+  puts
+
+  puts "Supported archives: "
+  puts PhysicsFS.supported_archives
+  puts
+
+  puts 'Enter commands. Enter "help" for instructions.'
+
+  loop {
+    line = Readline::readline "physfs_rb> ", true
+    break unless parse line
+  }
+end
+
+
+
+

+ 291 - 0
libs/physfs-2.0.3/extras/physfshttpd.c

@@ -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. ([email protected]).
+ */
+
+#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 ... */
+

+ 193 - 0
libs/physfs-2.0.3/extras/physfsrwops.c

@@ -0,0 +1,193 @@
+/*
+ * 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. ([email protected]).
+ */
+
+#include <stdio.h>  /* used for SEEK_SET, SEEK_CUR, SEEK_END ... */
+#include "physfsrwops.h"
+
+static int physfsrwops_seek(SDL_RWops *rw, int offset, int whence)
+{
+    PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
+    int pos = 0;
+
+    if (whence == SEEK_SET)
+    {
+        pos = offset;
+    } /* if */
+
+    else if (whence == SEEK_CUR)
+    {
+        PHYSFS_sint64 current = PHYSFS_tell(handle);
+        if (current == -1)
+        {
+            SDL_SetError("Can't find position in file: %s",
+                          PHYSFS_getLastError());
+            return(-1);
+        } /* if */
+
+        pos = (int) current;
+        if ( ((PHYSFS_sint64) pos) != current )
+        {
+            SDL_SetError("Can't fit current file position in an int!");
+            return(-1);
+        } /* if */
+
+        if (offset == 0)  /* this is a "tell" call. We're done. */
+            return(pos);
+
+        pos += offset;
+    } /* else if */
+
+    else if (whence == SEEK_END)
+    {
+        PHYSFS_sint64 len = PHYSFS_fileLength(handle);
+        if (len == -1)
+        {
+            SDL_SetError("Can't find end of file: %s", PHYSFS_getLastError());
+            return(-1);
+        } /* if */
+
+        pos = (int) len;
+        if ( ((PHYSFS_sint64) pos) != len )
+        {
+            SDL_SetError("Can't fit end-of-file position in an int!");
+            return(-1);
+        } /* if */
+
+        pos += 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 */
+
+    return(pos);
+} /* physfsrwops_seek */
+
+
+static int physfsrwops_read(SDL_RWops *rw, void *ptr, int size, int maxnum)
+{
+    PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
+    PHYSFS_sint64 rc = PHYSFS_read(handle, ptr, size, maxnum);
+    if (rc != maxnum)
+    {
+        if (!PHYSFS_eof(handle)) /* not EOF? Must be an error. */
+            SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+    } /* if */
+
+    return((int) rc);
+} /* physfsrwops_read */
+
+
+static int physfsrwops_write(SDL_RWops *rw, const void *ptr, int size, int num)
+{
+    PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
+    PHYSFS_sint64 rc = PHYSFS_write(handle, ptr, size, num);
+    if (rc != num)
+        SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+
+    return((int) rc);
+} /* 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 ... */
+

+ 88 - 0
libs/physfs-2.0.3/extras/physfsrwops.h

@@ -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. ([email protected]).
+ */
+
+#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().
+ */
+__EXPORT__ 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().
+ */
+__EXPORT__ 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().
+ */
+__EXPORT__ 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().
+ */
+__EXPORT__ SDL_RWops *PHYSFSRWOPS_makeRWops(PHYSFS_File *handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* include-once blocker */
+
+/* end of physfsrwops.h ... */
+

+ 181 - 0
libs/physfs-2.0.3/extras/physfsunpack.c

@@ -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 ... */
+

+ 66 - 0
libs/physfs-2.0.3/extras/selfextract.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. ([email protected]).
+ */
+
+/*
+ * 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 */
+

+ 237 - 0
libs/physfs-2.0.3/lzma/7zC.txt

@@ -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

+ 471 - 0
libs/physfs-2.0.3/lzma/7zFormat.txt

@@ -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

+ 32 - 0
libs/physfs-2.0.3/lzma/C/7zCrc.c

@@ -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;
+}

+ 21 - 0
libs/physfs-2.0.3/lzma/C/7zCrc.h

@@ -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

+ 40 - 0
libs/physfs-2.0.3/lzma/C/7zCrcT8.c

@@ -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;
+}

+ 119 - 0
libs/physfs-2.0.3/lzma/C/Alloc.c

@@ -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

+ 29 - 0
libs/physfs-2.0.3/lzma/C/Alloc.h

@@ -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

+ 70 - 0
libs/physfs-2.0.3/lzma/C/Archive/7z/7zAlloc.c

@@ -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);
+}

+ 20 - 0
libs/physfs-2.0.3/lzma/C/Archive/7z/7zAlloc.h

@@ -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

+ 29 - 0
libs/physfs-2.0.3/lzma/C/Archive/7z/7zBuffer.c

@@ -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;
+}

+ 19 - 0
libs/physfs-2.0.3/lzma/C/Archive/7z/7zBuffer.h

@@ -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

+ 345 - 0
libs/physfs-2.0.3/lzma/C/Archive/7z/7zDecode.c

@@ -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;
+}

+ 20 - 0
libs/physfs-2.0.3/lzma/C/Archive/7z/7zDecode.h

@@ -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

+ 119 - 0
libs/physfs-2.0.3/lzma/C/Archive/7z/7zExtract.c

@@ -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;
+}

+ 40 - 0
libs/physfs-2.0.3/lzma/C/Archive/7z/7zExtract.h

@@ -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

+ 5 - 0
libs/physfs-2.0.3/lzma/C/Archive/7z/7zHeader.c

@@ -0,0 +1,5 @@
+/*  7zHeader.c */
+
+#include "7zHeader.h"
+
+Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};

+ 55 - 0
libs/physfs-2.0.3/lzma/C/Archive/7z/7zHeader.h

@@ -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

+ 1314 - 0
libs/physfs-2.0.3/lzma/C/Archive/7z/7zIn.c

@@ -0,0 +1,1314 @@
+/* 7zIn.c */
+
+#include "7zIn.h"
+#include "7zDecode.h"
+#include "../../7zCrc.h"
+
+#define RINOM(x) { if((x) == 0) return SZE_OUTOFMEMORY; }
+
+void SzArDbExInit(CArchiveDatabaseEx *db)
+{
+  SzArchiveDatabaseInit(&db->Database);
+  db->FolderStartPackStreamIndex = 0;
+  db->PackStreamStartPositions = 0;
+  db->FolderStartFileIndex = 0;
+  db->FileIndexToFolderIndexMap = 0;
+}
+
+void SzArDbExFree(CArchiveDatabaseEx *db, void (*freeFunc)(void *))
+{
+  freeFunc(db->FolderStartPackStreamIndex);
+  freeFunc(db->PackStreamStartPositions);
+  freeFunc(db->FolderStartFileIndex);
+  freeFunc(db->FileIndexToFolderIndexMap);
+  SzArchiveDatabaseFree(&db->Database, freeFunc);
+  SzArDbExInit(db);
+}
+
+/*
+CFileSize GetFolderPackStreamSize(int folderIndex, int streamIndex) const 
+{
+  return PackSizes[FolderStartPackStreamIndex[folderIndex] + streamIndex];
+}
+
+CFileSize GetFilePackSize(int fileIndex) const
+{
+  int folderIndex = FileIndexToFolderIndexMap[fileIndex];
+  if (folderIndex >= 0)
+  {
+    const CFolder &folderInfo = Folders[folderIndex];
+    if (FolderStartFileIndex[folderIndex] == fileIndex)
+    return GetFolderFullPackSize(folderIndex);
+  }
+  return 0;
+}
+*/
+
+#define MY_ALLOC(T, p, size, allocFunc) { if ((size) == 0) p = 0; else \
+  if ((p = (T *)allocFunc((size) * sizeof(T))) == 0) return SZE_OUTOFMEMORY; }
+
+SZ_RESULT SzArDbExFill(CArchiveDatabaseEx *db, void * (*allocFunc)(size_t size))
+{
+  UInt32 startPos = 0;
+  CFileSize startPosSize = 0;
+  UInt32 i;
+  UInt32 folderIndex = 0;
+  UInt32 indexInFolder = 0;
+  MY_ALLOC(UInt32, db->FolderStartPackStreamIndex, db->Database.NumFolders, allocFunc);
+  for(i = 0; i < db->Database.NumFolders; i++)
+  {
+    db->FolderStartPackStreamIndex[i] = startPos;
+    startPos += db->Database.Folders[i].NumPackStreams;
+  }
+
+  MY_ALLOC(CFileSize, db->PackStreamStartPositions, db->Database.NumPackStreams, allocFunc);
+
+  for(i = 0; i < db->Database.NumPackStreams; i++)
+  {
+    db->PackStreamStartPositions[i] = startPosSize;
+    startPosSize += db->Database.PackSizes[i];
+  }
+
+  MY_ALLOC(UInt32, db->FolderStartFileIndex, db->Database.NumFolders, allocFunc);
+  MY_ALLOC(UInt32, db->FileIndexToFolderIndexMap, db->Database.NumFiles, allocFunc);
+
+  for (i = 0; i < db->Database.NumFiles; i++)
+  {
+    CFileItem *file = db->Database.Files + i;
+    int emptyStream = !file->HasStream;
+    if (emptyStream && indexInFolder == 0)
+    {
+      db->FileIndexToFolderIndexMap[i] = (UInt32)-1;
+      continue;
+    }
+    if (indexInFolder == 0)
+    {
+      /*
+      v3.13 incorrectly worked with empty folders
+      v4.07: Loop for skipping empty folders
+      */
+      for (;;)
+      {
+        if (folderIndex >= db->Database.NumFolders)
+          return SZE_ARCHIVE_ERROR;
+        db->FolderStartFileIndex[folderIndex] = i;
+        if (db->Database.Folders[folderIndex].NumUnPackStreams != 0)
+          break;
+        folderIndex++;
+      }
+    }
+    db->FileIndexToFolderIndexMap[i] = folderIndex;
+    if (emptyStream)
+      continue;
+    indexInFolder++;
+    if (indexInFolder >= db->Database.Folders[folderIndex].NumUnPackStreams)
+    {
+      folderIndex++;
+      indexInFolder = 0;
+    }
+  }
+  return SZ_OK;
+}
+
+
+CFileSize SzArDbGetFolderStreamPos(CArchiveDatabaseEx *db, UInt32 folderIndex, UInt32 indexInFolder)
+{
+  return db->ArchiveInfo.DataStartPosition + 
+    db->PackStreamStartPositions[db->FolderStartPackStreamIndex[folderIndex] + indexInFolder];
+}
+
+int SzArDbGetFolderFullPackSize(CArchiveDatabaseEx *db, UInt32 folderIndex, CFileSize *resSize)
+{
+  UInt32 packStreamIndex = db->FolderStartPackStreamIndex[folderIndex];
+  CFolder *folder = db->Database.Folders + folderIndex;
+  CFileSize size = 0;
+  UInt32 i;
+  for (i = 0; i < folder->NumPackStreams; i++)
+  {
+    CFileSize t = size + db->Database.PackSizes[packStreamIndex + i];
+    if (t < size)
+      return SZE_FAIL;
+    size = t;
+  }
+  *resSize = size;
+  return SZ_OK;
+}
+
+
+/*
+SZ_RESULT SzReadTime(const CObjectVector<CSzByteBuffer> &dataVector,
+    CObjectVector<CFileItem> &files, UInt64 type)
+{
+  CBoolVector boolVector;
+  RINOK(ReadBoolVector2(files.Size(), boolVector))
+
+  CStreamSwitch streamSwitch;
+  RINOK(streamSwitch.Set(this, &dataVector));
+
+  for(int i = 0; i < files.Size(); i++)
+  {
+    CFileItem &file = files[i];
+    CArchiveFileTime fileTime;
+    bool defined = boolVector[i];
+    if (defined)
+    {
+      UInt32 low, high;
+      RINOK(SzReadUInt32(low));
+      RINOK(SzReadUInt32(high));
+      fileTime.dwLowDateTime = low;
+      fileTime.dwHighDateTime = high;
+    }
+    switch(type)
+    {
+      case k7zIdCreationTime:
+        file.IsCreationTimeDefined = defined;
+        if (defined)
+          file.CreationTime = fileTime;
+        break;
+      case k7zIdLastWriteTime:
+        file.IsLastWriteTimeDefined = defined;
+        if (defined)
+          file.LastWriteTime = fileTime;
+        break;
+      case k7zIdLastAccessTime:
+        file.IsLastAccessTimeDefined = defined;
+        if (defined)
+          file.LastAccessTime = fileTime;
+        break;
+    }
+  }
+  return SZ_OK;
+}
+*/
+
+SZ_RESULT SafeReadDirect(ISzInStream *inStream, Byte *data, size_t size)
+{
+  #ifdef _LZMA_IN_CB
+  while (size > 0)
+  {
+    void *inBufferSpec;
+    size_t processedSize;
+    const Byte *inBuffer;
+    RINOK(inStream->Read(inStream, (void **)&inBufferSpec, size, &processedSize));
+    inBuffer = (const Byte *)inBufferSpec;
+    if (processedSize == 0 || processedSize > size)
+      return SZE_FAIL;
+    size -= processedSize;
+    do
+    {
+      *data++ = *inBuffer++;
+    }
+    while (--processedSize != 0);
+  }
+  #else
+  size_t processedSize;
+  RINOK(inStream->Read(inStream, data, size, &processedSize));
+  if (processedSize != size)
+    return SZE_FAIL;
+  #endif
+  return SZ_OK;
+}
+
+SZ_RESULT SafeReadDirectByte(ISzInStream *inStream, Byte *data)
+{
+  return SafeReadDirect(inStream, data, 1);
+}
+
+SZ_RESULT SafeReadDirectUInt32(ISzInStream *inStream, UInt32 *value, UInt32 *crc)
+{
+  int i;
+  *value = 0;
+  for (i = 0; i < 4; i++)
+  {
+    Byte b;
+    RINOK(SafeReadDirectByte(inStream, &b));
+    *value |= ((UInt32)b << (8 * i));
+    *crc = CRC_UPDATE_BYTE(*crc, b);
+  }
+  return SZ_OK;
+}
+
+SZ_RESULT SafeReadDirectUInt64(ISzInStream *inStream, UInt64 *value, UInt32 *crc)
+{
+  int i;
+  *value = 0;
+  for (i = 0; i < 8; i++)
+  {
+    Byte b;
+    RINOK(SafeReadDirectByte(inStream, &b));
+    *value |= ((UInt64)b << (8 * i));
+    *crc = CRC_UPDATE_BYTE(*crc, b);
+  }
+  return SZ_OK;
+}
+
+int TestSignatureCandidate(Byte *testBytes)
+{
+  size_t i;
+  for (i = 0; i < k7zSignatureSize; i++)
+    if (testBytes[i] != k7zSignature[i])
+      return 0;
+  return 1;
+}
+
+typedef struct _CSzState
+{
+  Byte *Data;
+  size_t Size;
+}CSzData;
+
+SZ_RESULT SzReadByte(CSzData *sd, Byte *b)
+{
+  if (sd->Size == 0)
+    return SZE_ARCHIVE_ERROR;
+  sd->Size--;
+  *b = *sd->Data++;
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadBytes(CSzData *sd, Byte *data, size_t size)
+{
+  size_t i;
+  for (i = 0; i < size; i++)
+  {
+    RINOK(SzReadByte(sd, data + i));
+  }
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadUInt32(CSzData *sd, UInt32 *value)
+{
+  int i;
+  *value = 0;
+  for (i = 0; i < 4; i++)
+  {
+    Byte b;
+    RINOK(SzReadByte(sd, &b));
+    *value |= ((UInt32)(b) << (8 * i));
+  }
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadNumber(CSzData *sd, UInt64 *value)
+{
+  Byte firstByte;
+  Byte mask = 0x80;
+  int i;
+  RINOK(SzReadByte(sd, &firstByte));
+  *value = 0;
+  for (i = 0; i < 8; i++)
+  {
+    Byte b;
+    if ((firstByte & mask) == 0)
+    {
+      UInt64 highPart = firstByte & (mask - 1);
+      *value += (highPart << (8 * i));
+      return SZ_OK;
+    }
+    RINOK(SzReadByte(sd, &b));
+    *value |= ((UInt64)b << (8 * i));
+    mask >>= 1;
+  }
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadSize(CSzData *sd, CFileSize *value)
+{
+  UInt64 value64;
+  RINOK(SzReadNumber(sd, &value64));
+  *value = (CFileSize)value64;
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadNumber32(CSzData *sd, UInt32 *value)
+{
+  UInt64 value64;
+  RINOK(SzReadNumber(sd, &value64));
+  if (value64 >= 0x80000000)
+    return SZE_NOTIMPL;
+  if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 2)))
+    return SZE_NOTIMPL;
+  *value = (UInt32)value64;
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadID(CSzData *sd, UInt64 *value) 
+{ 
+  return SzReadNumber(sd, value); 
+}
+
+SZ_RESULT SzSkeepDataSize(CSzData *sd, UInt64 size)
+{
+  if (size > sd->Size)
+    return SZE_ARCHIVE_ERROR;
+  sd->Size -= (size_t)size;
+  sd->Data += (size_t)size;
+  return SZ_OK;
+}
+
+SZ_RESULT SzSkeepData(CSzData *sd)
+{
+  UInt64 size;
+  RINOK(SzReadNumber(sd, &size));
+  return SzSkeepDataSize(sd, size);
+}
+
+SZ_RESULT SzReadArchiveProperties(CSzData *sd)
+{
+  for (;;)
+  {
+    UInt64 type;
+    RINOK(SzReadID(sd, &type));
+    if (type == k7zIdEnd)
+      break;
+    SzSkeepData(sd);
+  }
+  return SZ_OK;
+}
+
+SZ_RESULT SzWaitAttribute(CSzData *sd, UInt64 attribute)
+{
+  for (;;)
+  {
+    UInt64 type;
+    RINOK(SzReadID(sd, &type));
+    if (type == attribute)
+      return SZ_OK;
+    if (type == k7zIdEnd)
+      return SZE_ARCHIVE_ERROR;
+    RINOK(SzSkeepData(sd));
+  }
+}
+
+SZ_RESULT SzReadBoolVector(CSzData *sd, size_t numItems, Byte **v, void * (*allocFunc)(size_t size))
+{
+  Byte b = 0;
+  Byte mask = 0;
+  size_t i;
+  MY_ALLOC(Byte, *v, numItems, allocFunc);
+  for (i = 0; i < numItems; i++)
+  {
+    if (mask == 0)
+    {
+      RINOK(SzReadByte(sd, &b));
+      mask = 0x80;
+    }
+    (*v)[i] = (Byte)(((b & mask) != 0) ? 1 : 0);
+    mask >>= 1;
+  }
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadBoolVector2(CSzData *sd, size_t numItems, Byte **v, void * (*allocFunc)(size_t size))
+{
+  Byte allAreDefined;
+  size_t i;
+  RINOK(SzReadByte(sd, &allAreDefined));
+  if (allAreDefined == 0)
+    return SzReadBoolVector(sd, numItems, v, allocFunc);
+  MY_ALLOC(Byte, *v, numItems, allocFunc);
+  for(i = 0; i < numItems; i++)
+    (*v)[i] = 1;
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadHashDigests(
+    CSzData *sd, 
+    size_t numItems,
+    Byte **digestsDefined, 
+    UInt32 **digests, 
+    void * (*allocFunc)(size_t size))
+{
+  size_t i;
+  RINOK(SzReadBoolVector2(sd, numItems, digestsDefined, allocFunc));
+  MY_ALLOC(UInt32, *digests, numItems, allocFunc);
+  for(i = 0; i < numItems; i++)
+    if ((*digestsDefined)[i])
+    {
+      RINOK(SzReadUInt32(sd, (*digests) + i));
+    }
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadPackInfo(
+    CSzData *sd, 
+    CFileSize *dataOffset,
+    UInt32 *numPackStreams,
+    CFileSize **packSizes,
+    Byte **packCRCsDefined,
+    UInt32 **packCRCs,
+    void * (*allocFunc)(size_t size))
+{
+  UInt32 i;
+  RINOK(SzReadSize(sd, dataOffset));
+  RINOK(SzReadNumber32(sd, numPackStreams));
+
+  RINOK(SzWaitAttribute(sd, k7zIdSize));
+
+  MY_ALLOC(CFileSize, *packSizes, (size_t)*numPackStreams, allocFunc);
+
+  for(i = 0; i < *numPackStreams; i++)
+  {
+    RINOK(SzReadSize(sd, (*packSizes) + i));
+  }
+
+  for (;;)
+  {
+    UInt64 type;
+    RINOK(SzReadID(sd, &type));
+    if (type == k7zIdEnd)
+      break;
+    if (type == k7zIdCRC)
+    {
+      RINOK(SzReadHashDigests(sd, (size_t)*numPackStreams, packCRCsDefined, packCRCs, allocFunc)); 
+      continue;
+    }
+    RINOK(SzSkeepData(sd));
+  }
+  if (*packCRCsDefined == 0)
+  {
+    MY_ALLOC(Byte, *packCRCsDefined, (size_t)*numPackStreams, allocFunc);
+    MY_ALLOC(UInt32, *packCRCs, (size_t)*numPackStreams, allocFunc);
+    for(i = 0; i < *numPackStreams; i++)
+    {
+      (*packCRCsDefined)[i] = 0;
+      (*packCRCs)[i] = 0;
+    }
+  }
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadSwitch(CSzData *sd)
+{
+  Byte external;
+  RINOK(SzReadByte(sd, &external));
+  return (external == 0) ? SZ_OK: SZE_ARCHIVE_ERROR;
+}
+
+SZ_RESULT SzGetNextFolderItem(CSzData *sd, CFolder *folder, void * (*allocFunc)(size_t size))
+{
+  UInt32 numCoders;
+  UInt32 numBindPairs;
+  UInt32 numPackedStreams;
+  UInt32 i;
+  UInt32 numInStreams = 0;
+  UInt32 numOutStreams = 0;
+  RINOK(SzReadNumber32(sd, &numCoders));
+  folder->NumCoders = numCoders;
+
+  MY_ALLOC(CCoderInfo, folder->Coders, (size_t)numCoders, allocFunc);
+
+  for (i = 0; i < numCoders; i++)
+    SzCoderInfoInit(folder->Coders + i);
+
+  for (i = 0; i < numCoders; i++)
+  {
+    Byte mainByte;
+    CCoderInfo *coder = folder->Coders + i;
+    {
+      unsigned idSize, j;
+      Byte longID[15];
+      RINOK(SzReadByte(sd, &mainByte));
+      idSize = (unsigned)(mainByte & 0xF);
+      RINOK(SzReadBytes(sd, longID, idSize));
+      if (idSize > sizeof(coder->MethodID))
+        return SZE_NOTIMPL;
+      coder->MethodID = 0;
+      for (j = 0; j < idSize; j++)
+        coder->MethodID |= (CMethodID)longID[idSize - 1 - j] << (8 * j);
+
+      if ((mainByte & 0x10) != 0)
+      {
+        RINOK(SzReadNumber32(sd, &coder->NumInStreams));
+        RINOK(SzReadNumber32(sd, &coder->NumOutStreams));
+      }
+      else
+      {
+        coder->NumInStreams = 1;
+        coder->NumOutStreams = 1;
+      }
+      if ((mainByte & 0x20) != 0)
+      {
+        UInt64 propertiesSize = 0;
+        RINOK(SzReadNumber(sd, &propertiesSize));
+        if (!SzByteBufferCreate(&coder->Properties, (size_t)propertiesSize, allocFunc))
+          return SZE_OUTOFMEMORY;
+        RINOK(SzReadBytes(sd, coder->Properties.Items, (size_t)propertiesSize));
+      }
+    }
+    while ((mainByte & 0x80) != 0)
+    {
+      RINOK(SzReadByte(sd, &mainByte));
+      RINOK(SzSkeepDataSize(sd, (mainByte & 0xF)));
+      if ((mainByte & 0x10) != 0)
+      {
+        UInt32 n;
+        RINOK(SzReadNumber32(sd, &n));
+        RINOK(SzReadNumber32(sd, &n));
+      }
+      if ((mainByte & 0x20) != 0)
+      {
+        UInt64 propertiesSize = 0;
+        RINOK(SzReadNumber(sd, &propertiesSize));
+        RINOK(SzSkeepDataSize(sd, propertiesSize));
+      }
+    }
+    numInStreams += (UInt32)coder->NumInStreams;
+    numOutStreams += (UInt32)coder->NumOutStreams;
+  }
+
+  numBindPairs = numOutStreams - 1;
+  folder->NumBindPairs = numBindPairs;
+
+
+  MY_ALLOC(CBindPair, folder->BindPairs, (size_t)numBindPairs, allocFunc);
+
+  for (i = 0; i < numBindPairs; i++)
+  {
+    CBindPair *bindPair = folder->BindPairs + i;;
+    RINOK(SzReadNumber32(sd, &bindPair->InIndex));
+    RINOK(SzReadNumber32(sd, &bindPair->OutIndex)); 
+  }
+
+  numPackedStreams = numInStreams - (UInt32)numBindPairs;
+
+  folder->NumPackStreams = numPackedStreams;
+  MY_ALLOC(UInt32, folder->PackStreams, (size_t)numPackedStreams, allocFunc);
+
+  if (numPackedStreams == 1)
+  {
+    UInt32 j;
+    UInt32 pi = 0;
+    for (j = 0; j < numInStreams; j++)
+      if (SzFolderFindBindPairForInStream(folder, j) < 0)
+      {
+        folder->PackStreams[pi++] = j;
+        break;
+      }
+  }
+  else
+    for(i = 0; i < numPackedStreams; i++)
+    {
+      RINOK(SzReadNumber32(sd, folder->PackStreams + i));
+    }
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadUnPackInfo(
+    CSzData *sd, 
+    UInt32 *numFolders,
+    CFolder **folders,  /* for allocFunc */
+    void * (*allocFunc)(size_t size),
+    ISzAlloc *allocTemp)
+{
+  UInt32 i;
+  RINOK(SzWaitAttribute(sd, k7zIdFolder));
+  RINOK(SzReadNumber32(sd, numFolders));
+  {
+    RINOK(SzReadSwitch(sd));
+
+    MY_ALLOC(CFolder, *folders, (size_t)*numFolders, allocFunc);
+
+    for(i = 0; i < *numFolders; i++)
+      SzFolderInit((*folders) + i);
+
+    for(i = 0; i < *numFolders; i++)
+    {
+      RINOK(SzGetNextFolderItem(sd, (*folders) + i, allocFunc));
+    }
+  }
+
+  RINOK(SzWaitAttribute(sd, k7zIdCodersUnPackSize));
+
+  for(i = 0; i < *numFolders; i++)
+  {
+    UInt32 j;
+    CFolder *folder = (*folders) + i;
+    UInt32 numOutStreams = SzFolderGetNumOutStreams(folder);
+
+    MY_ALLOC(CFileSize, folder->UnPackSizes, (size_t)numOutStreams, allocFunc);
+
+    for(j = 0; j < numOutStreams; j++)
+    {
+      RINOK(SzReadSize(sd, folder->UnPackSizes + j));
+    }
+  }
+
+  for (;;)
+  {
+    UInt64 type;
+    RINOK(SzReadID(sd, &type));
+    if (type == k7zIdEnd)
+      return SZ_OK;
+    if (type == k7zIdCRC)
+    {
+      SZ_RESULT res;
+      Byte *crcsDefined = 0;
+      UInt32 *crcs = 0;
+      res = SzReadHashDigests(sd, *numFolders, &crcsDefined, &crcs, allocTemp->Alloc); 
+      if (res == SZ_OK)
+      {
+        for(i = 0; i < *numFolders; i++)
+        {
+          CFolder *folder = (*folders) + i;
+          folder->UnPackCRCDefined = crcsDefined[i];
+          folder->UnPackCRC = crcs[i];
+        }
+      }
+      allocTemp->Free(crcs);
+      allocTemp->Free(crcsDefined);
+      RINOK(res);
+      continue;
+    }
+    RINOK(SzSkeepData(sd));
+  }
+}
+
+SZ_RESULT SzReadSubStreamsInfo(
+    CSzData *sd, 
+    UInt32 numFolders,
+    CFolder *folders,
+    UInt32 *numUnPackStreams,
+    CFileSize **unPackSizes,
+    Byte **digestsDefined,
+    UInt32 **digests,
+    ISzAlloc *allocTemp)
+{
+  UInt64 type = 0;
+  UInt32 i;
+  UInt32 si = 0;
+  UInt32 numDigests = 0;
+
+  for(i = 0; i < numFolders; i++)
+    folders[i].NumUnPackStreams = 1;
+  *numUnPackStreams = numFolders;
+
+  for (;;)
+  {
+    RINOK(SzReadID(sd, &type));
+    if (type == k7zIdNumUnPackStream)
+    {
+      *numUnPackStreams = 0;
+      for(i = 0; i < numFolders; i++)
+      {
+        UInt32 numStreams;
+        RINOK(SzReadNumber32(sd, &numStreams));
+        folders[i].NumUnPackStreams = numStreams;
+        *numUnPackStreams += numStreams;
+      }
+      continue;
+    }
+    if (type == k7zIdCRC || type == k7zIdSize)
+      break;
+    if (type == k7zIdEnd)
+      break;
+    RINOK(SzSkeepData(sd));
+  }
+
+  if (*numUnPackStreams == 0)
+  {
+    *unPackSizes = 0;
+    *digestsDefined = 0;
+    *digests = 0;
+  }
+  else
+  {
+    *unPackSizes = (CFileSize *)allocTemp->Alloc((size_t)*numUnPackStreams * sizeof(CFileSize));
+    RINOM(*unPackSizes);
+    *digestsDefined = (Byte *)allocTemp->Alloc((size_t)*numUnPackStreams * sizeof(Byte));
+    RINOM(*digestsDefined);
+    *digests = (UInt32 *)allocTemp->Alloc((size_t)*numUnPackStreams * sizeof(UInt32));
+    RINOM(*digests);
+  }
+
+  for(i = 0; i < numFolders; i++)
+  {
+    /*
+    v3.13 incorrectly worked with empty folders
+    v4.07: we check that folder is empty
+    */
+    CFileSize sum = 0;
+    UInt32 j;
+    UInt32 numSubstreams = folders[i].NumUnPackStreams;
+    if (numSubstreams == 0)
+      continue;
+    if (type == k7zIdSize)
+    for (j = 1; j < numSubstreams; j++)
+    {
+      CFileSize size;
+      RINOK(SzReadSize(sd, &size));
+      (*unPackSizes)[si++] = size;
+      sum += size;
+    }
+    (*unPackSizes)[si++] = SzFolderGetUnPackSize(folders + i) - sum;
+  }
+  if (type == k7zIdSize)
+  {
+    RINOK(SzReadID(sd, &type));
+  }
+
+  for(i = 0; i < *numUnPackStreams; i++)
+  {
+    (*digestsDefined)[i] = 0;
+    (*digests)[i] = 0;
+  }
+
+
+  for(i = 0; i < numFolders; i++)
+  {
+    UInt32 numSubstreams = folders[i].NumUnPackStreams;
+    if (numSubstreams != 1 || !folders[i].UnPackCRCDefined)
+      numDigests += numSubstreams;
+  }
+
+ 
+  si = 0;
+  for (;;)
+  {
+    if (type == k7zIdCRC)
+    {
+      int digestIndex = 0;
+      Byte *digestsDefined2 = 0; 
+      UInt32 *digests2 = 0;
+      SZ_RESULT res = SzReadHashDigests(sd, numDigests, &digestsDefined2, &digests2, allocTemp->Alloc);
+      if (res == SZ_OK)
+      {
+        for (i = 0; i < numFolders; i++)
+        {
+          CFolder *folder = folders + i;
+          UInt32 numSubstreams = folder->NumUnPackStreams;
+          if (numSubstreams == 1 && folder->UnPackCRCDefined)
+          {
+            (*digestsDefined)[si] = 1;
+            (*digests)[si] = folder->UnPackCRC;
+            si++;
+          }
+          else
+          {
+            UInt32 j;
+            for (j = 0; j < numSubstreams; j++, digestIndex++)
+            {
+              (*digestsDefined)[si] = digestsDefined2[digestIndex];
+              (*digests)[si] = digests2[digestIndex];
+              si++;
+            }
+          }
+        }
+      }
+      allocTemp->Free(digestsDefined2);
+      allocTemp->Free(digests2);
+      RINOK(res);
+    }
+    else if (type == k7zIdEnd)
+      return SZ_OK;
+    else
+    {
+      RINOK(SzSkeepData(sd));
+    }
+    RINOK(SzReadID(sd, &type));
+  }
+}
+
+
+SZ_RESULT SzReadStreamsInfo(
+    CSzData *sd, 
+    CFileSize *dataOffset,
+    CArchiveDatabase *db,
+    UInt32 *numUnPackStreams,
+    CFileSize **unPackSizes, /* allocTemp */
+    Byte **digestsDefined,   /* allocTemp */
+    UInt32 **digests,        /* allocTemp */
+    void * (*allocFunc)(size_t size),
+    ISzAlloc *allocTemp)
+{
+  for (;;)
+  {
+    UInt64 type;
+    RINOK(SzReadID(sd, &type));
+    if ((UInt64)(int)type != type)
+      return SZE_FAIL;
+    switch((int)type)
+    {
+      case k7zIdEnd:
+        return SZ_OK;
+      case k7zIdPackInfo:
+      {
+        RINOK(SzReadPackInfo(sd, dataOffset, &db->NumPackStreams, 
+            &db->PackSizes, &db->PackCRCsDefined, &db->PackCRCs, allocFunc));
+        break;
+      }
+      case k7zIdUnPackInfo:
+      {
+        RINOK(SzReadUnPackInfo(sd, &db->NumFolders, &db->Folders, allocFunc, allocTemp));
+        break;
+      }
+      case k7zIdSubStreamsInfo:
+      {
+        RINOK(SzReadSubStreamsInfo(sd, db->NumFolders, db->Folders, 
+            numUnPackStreams, unPackSizes, digestsDefined, digests, allocTemp));
+        break;
+      }
+      default:
+        return SZE_FAIL;
+    }
+  }
+}
+
+Byte kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+SZ_RESULT SzReadFileNames(CSzData *sd, UInt32 numFiles, CFileItem *files, 
+    void * (*allocFunc)(size_t size))
+{
+  UInt32 i;
+  for(i = 0; i < numFiles; i++)
+  {
+    UInt32 len = 0;
+    UInt32 pos = 0;
+    CFileItem *file = files + i;
+    while(pos + 2 <= sd->Size)
+    {
+      int numAdds;
+      UInt32 value = (UInt32)(sd->Data[pos] | (((UInt32)sd->Data[pos + 1]) << 8));
+      pos += 2;
+      len++;
+      if (value == 0)
+        break;
+      if (value < 0x80)
+        continue;
+      if (value >= 0xD800 && value < 0xE000)
+      {
+        UInt32 c2;
+        if (value >= 0xDC00)
+          return SZE_ARCHIVE_ERROR;
+        if (pos + 2 > sd->Size)
+          return SZE_ARCHIVE_ERROR;
+        c2 = (UInt32)(sd->Data[pos] | (((UInt32)sd->Data[pos + 1]) << 8));
+        pos += 2;
+        if (c2 < 0xDC00 || c2 >= 0xE000)
+          return SZE_ARCHIVE_ERROR;
+        value = ((value - 0xD800) << 10) | (c2 - 0xDC00);
+      }
+      for (numAdds = 1; numAdds < 5; numAdds++)
+        if (value < (((UInt32)1) << (numAdds * 5 + 6)))
+          break;
+      len += numAdds;
+    }
+
+    MY_ALLOC(char, file->Name, (size_t)len, allocFunc);
+
+    len = 0;
+    while(2 <= sd->Size)
+    {
+      int numAdds;
+      UInt32 value = (UInt32)(sd->Data[0] | (((UInt32)sd->Data[1]) << 8));
+      SzSkeepDataSize(sd, 2);
+      if (value < 0x80)
+      {
+        file->Name[len++] = (char)value;
+        if (value == 0)
+          break;
+        continue;
+      }
+      if (value >= 0xD800 && value < 0xE000)
+      {
+        UInt32 c2 = (UInt32)(sd->Data[0] | (((UInt32)sd->Data[1]) << 8));
+        SzSkeepDataSize(sd, 2);
+        value = ((value - 0xD800) << 10) | (c2 - 0xDC00);
+      }
+      for (numAdds = 1; numAdds < 5; numAdds++)
+        if (value < (((UInt32)1) << (numAdds * 5 + 6)))
+          break;
+      file->Name[len++] = (char)(kUtf8Limits[numAdds - 1] + (value >> (6 * numAdds)));
+      do
+      {
+        numAdds--;
+        file->Name[len++] = (char)(0x80 + ((value >> (6 * numAdds)) & 0x3F));
+      }
+      while(numAdds > 0);
+
+      len += numAdds;
+    }
+  }
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadHeader2(
+    CSzData *sd, 
+    CArchiveDatabaseEx *db,   /* allocMain */
+    CFileSize **unPackSizes,  /* allocTemp */
+    Byte **digestsDefined,    /* allocTemp */
+    UInt32 **digests,         /* allocTemp */
+    Byte **emptyStreamVector, /* allocTemp */
+    Byte **emptyFileVector,   /* allocTemp */
+    Byte **lwtVector,         /* allocTemp */
+    ISzAlloc *allocMain, 
+    ISzAlloc *allocTemp)
+{
+  UInt64 type;
+  UInt32 numUnPackStreams = 0;
+  UInt32 numFiles = 0;
+  CFileItem *files = 0;
+  UInt32 numEmptyStreams = 0;
+  UInt32 i;
+
+  RINOK(SzReadID(sd, &type));
+
+  if (type == k7zIdArchiveProperties)
+  {
+    RINOK(SzReadArchiveProperties(sd));
+    RINOK(SzReadID(sd, &type));
+  }
+ 
+ 
+  if (type == k7zIdMainStreamsInfo)
+  {
+    RINOK(SzReadStreamsInfo(sd,
+        &db->ArchiveInfo.DataStartPosition,
+        &db->Database, 
+        &numUnPackStreams,
+        unPackSizes,
+        digestsDefined,
+        digests, allocMain->Alloc, allocTemp));
+    db->ArchiveInfo.DataStartPosition += db->ArchiveInfo.StartPositionAfterHeader;
+    RINOK(SzReadID(sd, &type));
+  }
+
+  if (type == k7zIdEnd)
+    return SZ_OK;
+  if (type != k7zIdFilesInfo)
+    return SZE_ARCHIVE_ERROR;
+  
+  RINOK(SzReadNumber32(sd, &numFiles));
+  db->Database.NumFiles = numFiles;
+
+  MY_ALLOC(CFileItem, files, (size_t)numFiles, allocMain->Alloc);
+
+  db->Database.Files = files;
+  for(i = 0; i < numFiles; i++)
+    SzFileInit(files + i);
+
+  for (;;)
+  {
+    UInt64 type;
+    UInt64 size;
+    RINOK(SzReadID(sd, &type));
+    if (type == k7zIdEnd)
+      break;
+    RINOK(SzReadNumber(sd, &size));
+
+    if ((UInt64)(int)type != type)
+    {
+      RINOK(SzSkeepDataSize(sd, size));
+    }
+    else
+    switch((int)type)
+    {
+      case k7zIdName:
+      {
+        RINOK(SzReadSwitch(sd));
+        RINOK(SzReadFileNames(sd, numFiles, files, allocMain->Alloc))
+        break;
+      }
+      case k7zIdEmptyStream:
+      {
+        RINOK(SzReadBoolVector(sd, numFiles, emptyStreamVector, allocTemp->Alloc));
+        numEmptyStreams = 0;
+        for (i = 0; i < numFiles; i++)
+          if ((*emptyStreamVector)[i])
+            numEmptyStreams++;
+        break;
+      }
+      case k7zIdEmptyFile:
+      {
+        RINOK(SzReadBoolVector(sd, numEmptyStreams, emptyFileVector, allocTemp->Alloc));
+        break;
+      }
+      case k7zIdLastWriteTime:
+      {
+        RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp->Alloc));
+        RINOK(SzReadSwitch(sd));
+        for (i = 0; i < numFiles; i++)
+        {
+          CFileItem *f = &files[i];
+          Byte defined = (*lwtVector)[i];
+          f->IsLastWriteTimeDefined = defined;
+          f->LastWriteTime.Low = f->LastWriteTime.High = 0;
+          if (defined)
+          {
+            RINOK(SzReadUInt32(sd, &f->LastWriteTime.Low));
+            RINOK(SzReadUInt32(sd, &f->LastWriteTime.High));
+          }
+        }
+        break;
+      }
+      default:
+      {
+        RINOK(SzSkeepDataSize(sd, size));
+      }
+    }
+  }
+
+  {
+    UInt32 emptyFileIndex = 0;
+    UInt32 sizeIndex = 0;
+    for(i = 0; i < numFiles; i++)
+    {
+      CFileItem *file = files + i;
+      file->IsAnti = 0;
+      if (*emptyStreamVector == 0)
+        file->HasStream = 1;
+      else
+        file->HasStream = (Byte)((*emptyStreamVector)[i] ? 0 : 1);
+      if(file->HasStream)
+      {
+        file->IsDirectory = 0;
+        file->Size = (*unPackSizes)[sizeIndex];
+        file->FileCRC = (*digests)[sizeIndex];
+        file->IsFileCRCDefined = (Byte)(*digestsDefined)[sizeIndex];
+        sizeIndex++;
+      }
+      else
+      {
+        if (*emptyFileVector == 0)
+          file->IsDirectory = 1;
+        else
+          file->IsDirectory = (Byte)((*emptyFileVector)[emptyFileIndex] ? 0 : 1);
+        emptyFileIndex++;
+        file->Size = 0;
+        file->IsFileCRCDefined = 0;
+      }
+    }
+  }
+  return SzArDbExFill(db, allocMain->Alloc);
+}
+
+SZ_RESULT SzReadHeader(
+    CSzData *sd, 
+    CArchiveDatabaseEx *db, 
+    ISzAlloc *allocMain, 
+    ISzAlloc *allocTemp)
+{
+  CFileSize *unPackSizes = 0;
+  Byte *digestsDefined = 0;
+  UInt32 *digests = 0;
+  Byte *emptyStreamVector = 0;
+  Byte *emptyFileVector = 0;
+  Byte *lwtVector = 0;
+  SZ_RESULT res = SzReadHeader2(sd, db, 
+      &unPackSizes, &digestsDefined, &digests,
+      &emptyStreamVector, &emptyFileVector, &lwtVector, 
+      allocMain, allocTemp);
+  allocTemp->Free(unPackSizes);
+  allocTemp->Free(digestsDefined);
+  allocTemp->Free(digests);
+  allocTemp->Free(emptyStreamVector);
+  allocTemp->Free(emptyFileVector);
+  allocTemp->Free(lwtVector);
+  return res;
+} 
+
+SZ_RESULT SzReadAndDecodePackedStreams2(
+    ISzInStream *inStream, 
+    CSzData *sd,
+    CSzByteBuffer *outBuffer,
+    CFileSize baseOffset, 
+    CArchiveDatabase *db,
+    CFileSize **unPackSizes,
+    Byte **digestsDefined,
+    UInt32 **digests,
+    #ifndef _LZMA_IN_CB
+    Byte **inBuffer,
+    #endif
+    ISzAlloc *allocTemp)
+{
+
+  UInt32 numUnPackStreams = 0;
+  CFileSize dataStartPos;
+  CFolder *folder;
+  #ifndef _LZMA_IN_CB
+  CFileSize packSize = 0;
+  UInt32 i = 0;
+  #endif
+  CFileSize unPackSize;
+  SZ_RESULT res;
+
+  RINOK(SzReadStreamsInfo(sd, &dataStartPos, db,
+      &numUnPackStreams,  unPackSizes, digestsDefined, digests, 
+      allocTemp->Alloc, allocTemp));
+  
+  dataStartPos += baseOffset;
+  if (db->NumFolders != 1)
+    return SZE_ARCHIVE_ERROR;
+
+  folder = db->Folders;
+  unPackSize = SzFolderGetUnPackSize(folder);
+  
+  RINOK(inStream->Seek(inStream, dataStartPos));
+
+  #ifndef _LZMA_IN_CB
+  for (i = 0; i < db->NumPackStreams; i++)
+    packSize += db->PackSizes[i];
+
+  MY_ALLOC(Byte, *inBuffer, (size_t)packSize, allocTemp->Alloc);
+
+  RINOK(SafeReadDirect(inStream, *inBuffer, (size_t)packSize));
+  #endif
+
+  if (!SzByteBufferCreate(outBuffer, (size_t)unPackSize, allocTemp->Alloc))
+    return SZE_OUTOFMEMORY;
+  
+  res = SzDecode(db->PackSizes, folder, 
+          #ifdef _LZMA_IN_CB
+          inStream, dataStartPos, 
+          #else
+          *inBuffer, 
+          #endif
+          outBuffer->Items, (size_t)unPackSize, allocTemp);
+  RINOK(res)
+  if (folder->UnPackCRCDefined)
+    if (CrcCalc(outBuffer->Items, (size_t)unPackSize) != folder->UnPackCRC)
+      return SZE_FAIL;
+  return SZ_OK;
+}
+
+SZ_RESULT SzReadAndDecodePackedStreams(
+    ISzInStream *inStream, 
+    CSzData *sd,
+    CSzByteBuffer *outBuffer,
+    CFileSize baseOffset, 
+    ISzAlloc *allocTemp)
+{
+  CArchiveDatabase db;
+  CFileSize *unPackSizes = 0;
+  Byte *digestsDefined = 0;
+  UInt32 *digests = 0;
+  #ifndef _LZMA_IN_CB
+  Byte *inBuffer = 0;
+  #endif
+  SZ_RESULT res;
+  SzArchiveDatabaseInit(&db);
+  res = SzReadAndDecodePackedStreams2(inStream, sd, outBuffer, baseOffset, 
+    &db, &unPackSizes, &digestsDefined, &digests, 
+    #ifndef _LZMA_IN_CB
+    &inBuffer,
+    #endif
+    allocTemp);
+  SzArchiveDatabaseFree(&db, allocTemp->Free);
+  allocTemp->Free(unPackSizes);
+  allocTemp->Free(digestsDefined);
+  allocTemp->Free(digests);
+  #ifndef _LZMA_IN_CB
+  allocTemp->Free(inBuffer);
+  #endif
+  return res;
+}
+
+SZ_RESULT SzArchiveOpen2(
+    ISzInStream *inStream, 
+    CArchiveDatabaseEx *db,
+    ISzAlloc *allocMain, 
+    ISzAlloc *allocTemp)
+{
+  Byte signature[k7zSignatureSize];
+  Byte version;
+  UInt32 crcFromArchive;
+  UInt64 nextHeaderOffset;
+  UInt64 nextHeaderSize;
+  UInt32 nextHeaderCRC;
+  UInt32 crc = 0;
+  CFileSize pos = 0;
+  CSzByteBuffer buffer;
+  CSzData sd;
+  SZ_RESULT res;
+
+  RINOK(SafeReadDirect(inStream, signature, k7zSignatureSize));
+
+  if (!TestSignatureCandidate(signature))
+    return SZE_ARCHIVE_ERROR;
+
+  /*
+  db.Clear();
+  db.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition;
+  */
+  RINOK(SafeReadDirectByte(inStream, &version));
+  if (version != k7zMajorVersion)
+    return SZE_ARCHIVE_ERROR;
+  RINOK(SafeReadDirectByte(inStream, &version));
+
+  RINOK(SafeReadDirectUInt32(inStream, &crcFromArchive, &crc));
+
+  crc = CRC_INIT_VAL;
+  RINOK(SafeReadDirectUInt64(inStream, &nextHeaderOffset, &crc));
+  RINOK(SafeReadDirectUInt64(inStream, &nextHeaderSize, &crc));
+  RINOK(SafeReadDirectUInt32(inStream, &nextHeaderCRC, &crc));
+
+  pos = k7zStartHeaderSize;
+  db->ArchiveInfo.StartPositionAfterHeader = pos;
+  
+  if (CRC_GET_DIGEST(crc) != crcFromArchive)
+    return SZE_ARCHIVE_ERROR;
+
+  if (nextHeaderSize == 0)
+    return SZ_OK;
+
+  RINOK(inStream->Seek(inStream, (CFileSize)(pos + nextHeaderOffset)));
+
+  if (!SzByteBufferCreate(&buffer, (size_t)nextHeaderSize, allocTemp->Alloc))
+    return SZE_OUTOFMEMORY;
+
+  res = SafeReadDirect(inStream, buffer.Items, (size_t)nextHeaderSize);
+  if (res == SZ_OK)
+  {
+    res = SZE_ARCHIVE_ERROR;
+    if (CrcCalc(buffer.Items, (UInt32)nextHeaderSize) == nextHeaderCRC)
+    {
+      for (;;)
+      {
+        UInt64 type;
+        sd.Data = buffer.Items;
+        sd.Size = buffer.Capacity;
+        res = SzReadID(&sd, &type);
+        if (res != SZ_OK)
+          break;
+        if (type == k7zIdHeader)
+        {
+          res = SzReadHeader(&sd, db, allocMain, allocTemp);
+          break;
+        }
+        if (type != k7zIdEncodedHeader)
+        {
+          res = SZE_ARCHIVE_ERROR;
+          break;
+        }
+        {
+          CSzByteBuffer outBuffer;
+          res = SzReadAndDecodePackedStreams(inStream, &sd, &outBuffer, 
+              db->ArchiveInfo.StartPositionAfterHeader, 
+              allocTemp);
+          if (res != SZ_OK)
+          {
+            SzByteBufferFree(&outBuffer, allocTemp->Free);
+            break;
+          }
+          SzByteBufferFree(&buffer, allocTemp->Free);
+          buffer.Items = outBuffer.Items;
+          buffer.Capacity = outBuffer.Capacity;
+        }
+      }
+    }
+  }
+  SzByteBufferFree(&buffer, allocTemp->Free);
+  return res;
+}
+
+SZ_RESULT SzArchiveOpen(
+    ISzInStream *inStream, 
+    CArchiveDatabaseEx *db,
+    ISzAlloc *allocMain, 
+    ISzAlloc *allocTemp)
+{
+  SZ_RESULT res = SzArchiveOpen2(inStream, db, allocMain, allocTemp);
+  if (res != SZ_OK)
+    SzArDbExFree(db, allocMain->Free);
+  return res;
+}

+ 55 - 0
libs/physfs-2.0.3/lzma/C/Archive/7z/7zIn.h

@@ -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

+ 134 - 0
libs/physfs-2.0.3/lzma/C/Archive/7z/7zItem.c

@@ -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);
+}

+ 95 - 0
libs/physfs-2.0.3/lzma/C/Archive/7z/7zItem.h

@@ -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

+ 428 - 0
libs/physfs-2.0.3/lzma/C/Archive/7z/7zMain.c

@@ -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;
+}

+ 10 - 0
libs/physfs-2.0.3/lzma/C/Archive/7z/7zMethodID.c

@@ -0,0 +1,10 @@
+/* 7zMethodID.c */
+
+#include "7zMethodID.h"
+
+/*
+int AreMethodsEqual(CMethodID *a1, CMethodID *a2)
+{
+  return (*a1 == *a2) ? 1 : 0;
+}
+*/

+ 10 - 0
libs/physfs-2.0.3/lzma/C/Archive/7z/7zMethodID.h

@@ -0,0 +1,10 @@
+/* 7zMethodID.h */
+
+#ifndef __7Z_METHOD_ID_H
+#define __7Z_METHOD_ID_H
+
+#include "../../Types.h"
+
+typedef UInt64 CMethodID;
+
+#endif

+ 211 - 0
libs/physfs-2.0.3/lzma/C/Archive/7z/7z_C.dsp

@@ -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

+ 29 - 0
libs/physfs-2.0.3/lzma/C/Archive/7z/7z_C.dsw

@@ -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>
+{{{
+}}}
+
+###############################################################################
+

+ 74 - 0
libs/physfs-2.0.3/lzma/C/Archive/7z/makefile

@@ -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)

+ 55 - 0
libs/physfs-2.0.3/lzma/C/Archive/7z/makefile.gcc

@@ -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)
+

+ 26 - 0
libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchARM.c

@@ -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;
+}

+ 10 - 0
libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchARM.h

@@ -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

+ 35 - 0
libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchARMThumb.c

@@ -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;
+}

+ 10 - 0
libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchARMThumb.h

@@ -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

+ 66 - 0
libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchIA64.c

@@ -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;
+}

+ 10 - 0
libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchIA64.h

@@ -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

+ 36 - 0
libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchPPC.c

@@ -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;
+}

+ 10 - 0
libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchPPC.h

@@ -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

+ 36 - 0
libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchSPARC.c

@@ -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;
+}

+ 10 - 0
libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchSPARC.h

@@ -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

+ 51 - 0
libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchTypes.h

@@ -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

+ 84 - 0
libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchX86.c

@@ -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;
+}

+ 12 - 0
libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchX86.h

@@ -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

+ 135 - 0
libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchX86_2.c

@@ -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;
+}

+ 28 - 0
libs/physfs-2.0.3/lzma/C/Compress/Branch/BranchX86_2.h

@@ -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

Some files were not shown because too many files changed in this diff