Initial integration, lots of broken stuff
authorTim Goya <tuxdev103@gmail.com>
Sun, 16 Dec 2007 22:17:36 +0000 (22:17 +0000)
committerTim Goya <tuxdev103@gmail.com>
Sun, 16 Dec 2007 22:17:36 +0000 (22:17 +0000)
SVN-Revision: 5199

214 files changed:
src/addon_manager.cpp
src/gameconfig.cpp
src/gameconfig.hpp
src/lisp/parser.cpp
src/main.cpp
src/physfs/physfs_sdl.cpp
src/physfs/physfs_stream.cpp
src/physfs/physfs_stream.hpp
src/sector.cpp
src/tinygettext/tinygettext.cpp
src/title.cpp
src/unison/CMakeLists.txt [new file with mode: 0644]
src/unison/Doxyfile [new file with mode: 0644]
src/unison/LICENSE_1_0.txt [new file with mode: 0644]
src/unison/include/unison/vfs/FileSystem.hpp [new file with mode: 0644]
src/unison/include/unison/vfs/sdl/Utils.hpp [new file with mode: 0644]
src/unison/include/unison/vfs/stream.hpp [new file with mode: 0644]
src/unison/include/unison/video/Blittable.hpp [new file with mode: 0644]
src/unison/include/unison/video/Blitters.hpp [new file with mode: 0644]
src/unison/include/unison/video/Color.hpp [new file with mode: 0644]
src/unison/include/unison/video/Coord.hpp [new file with mode: 0644]
src/unison/include/unison/video/DisplayList.hpp [new file with mode: 0644]
src/unison/include/unison/video/Rect.hpp [new file with mode: 0644]
src/unison/include/unison/video/RenderOptions.hpp [new file with mode: 0644]
src/unison/include/unison/video/Renderers.hpp [new file with mode: 0644]
src/unison/include/unison/video/Surface.hpp [new file with mode: 0644]
src/unison/include/unison/video/Texture.hpp [new file with mode: 0644]
src/unison/include/unison/video/Window.hpp [new file with mode: 0644]
src/unison/include/unison/video/backend/Renderer.hpp [new file with mode: 0644]
src/unison/include/unison/video/backend/Texture.hpp [new file with mode: 0644]
src/unison/include/unison/video/backend/Window.hpp [new file with mode: 0644]
src/unison/include/unison/video/sdl/Blitters.hpp [new file with mode: 0644]
src/unison/physfs-1.1.1/CHANGELOG.txt [new file with mode: 0644]
src/unison/physfs-1.1.1/CMakeLists.txt [new file with mode: 0644]
src/unison/physfs-1.1.1/CREDITS.txt [new file with mode: 0644]
src/unison/physfs-1.1.1/Doxyfile [new file with mode: 0644]
src/unison/physfs-1.1.1/INSTALL.txt [new file with mode: 0644]
src/unison/physfs-1.1.1/LICENSE.txt [new file with mode: 0644]
src/unison/physfs-1.1.1/TODO.txt [new file with mode: 0644]
src/unison/physfs-1.1.1/archivers/dir.c [new file with mode: 0644]
src/unison/physfs-1.1.1/archivers/grp.c [new file with mode: 0644]
src/unison/physfs-1.1.1/archivers/hog.c [new file with mode: 0644]
src/unison/physfs-1.1.1/archivers/lzma.c [new file with mode: 0644]
src/unison/physfs-1.1.1/archivers/mvl.c [new file with mode: 0644]
src/unison/physfs-1.1.1/archivers/qpak.c [new file with mode: 0644]
src/unison/physfs-1.1.1/archivers/wad.c [new file with mode: 0644]
src/unison/physfs-1.1.1/archivers/zip.c [new file with mode: 0644]
src/unison/physfs-1.1.1/extras/PhysFS.NET/AssemblyInfo.cs [new file with mode: 0755]
src/unison/physfs-1.1.1/extras/PhysFS.NET/PhysFS.NET.csproj [new file with mode: 0755]
src/unison/physfs-1.1.1/extras/PhysFS.NET/PhysFS.NET.sln [new file with mode: 0755]
src/unison/physfs-1.1.1/extras/PhysFS.NET/PhysFS.cs [new file with mode: 0755]
src/unison/physfs-1.1.1/extras/PhysFS.NET/PhysFSFileStream.cs [new file with mode: 0755]
src/unison/physfs-1.1.1/extras/PhysFS.NET/PhysFS_DLL.cs [new file with mode: 0755]
src/unison/physfs-1.1.1/extras/PhysFS.NET/README.txt [new file with mode: 0755]
src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/App.ico [new file with mode: 0755]
src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/AssemblyInfo.cs [new file with mode: 0755]
src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/TestApp.csproj [new file with mode: 0755]
src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/TestApp.sln [new file with mode: 0755]
src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/TestAppForm.cs [new file with mode: 0755]
src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/TestAppForm.resx [new file with mode: 0755]
src/unison/physfs-1.1.1/extras/abs-file.h [new file with mode: 0644]
src/unison/physfs-1.1.1/extras/casefolding.txt [new file with mode: 0644]
src/unison/physfs-1.1.1/extras/globbing.c [new file with mode: 0644]
src/unison/physfs-1.1.1/extras/globbing.h [new file with mode: 0644]
src/unison/physfs-1.1.1/extras/ignorecase.c [new file with mode: 0644]
src/unison/physfs-1.1.1/extras/ignorecase.h [new file with mode: 0644]
src/unison/physfs-1.1.1/extras/makecasefoldhashtable.pl [new file with mode: 0755]
src/unison/physfs-1.1.1/extras/makedist.sh [new file with mode: 0755]
src/unison/physfs-1.1.1/extras/physfs_rb/installer.rb [new file with mode: 0644]
src/unison/physfs-1.1.1/extras/physfs_rb/physfs/extconf.rb [new file with mode: 0644]
src/unison/physfs-1.1.1/extras/physfs_rb/physfs/install.rb [new file with mode: 0644]
src/unison/physfs-1.1.1/extras/physfs_rb/physfs/make_install_test.sh [new file with mode: 0755]
src/unison/physfs-1.1.1/extras/physfs_rb/physfs/physfs.rb [new file with mode: 0644]
src/unison/physfs-1.1.1/extras/physfs_rb/physfs/physfsrwops.c [new file with mode: 0644]
src/unison/physfs-1.1.1/extras/physfs_rb/physfs/physfsrwops.h [new file with mode: 0644]
src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_physfs.c [new file with mode: 0644]
src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_physfs.h [new file with mode: 0644]
src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_physfs_file.c [new file with mode: 0644]
src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_physfs_file.h [new file with mode: 0644]
src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_sdl_rwops.c [new file with mode: 0644]
src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_sdl_rwops.h [new file with mode: 0644]
src/unison/physfs-1.1.1/extras/physfs_rb/physfs/test/test_physfs.rb [new file with mode: 0644]
src/unison/physfs-1.1.1/extras/physfshttpd.c [new file with mode: 0644]
src/unison/physfs-1.1.1/extras/physfsrwops.c [new file with mode: 0644]
src/unison/physfs-1.1.1/extras/physfsrwops.h [new file with mode: 0644]
src/unison/physfs-1.1.1/extras/physfsunpack.c [new file with mode: 0644]
src/unison/physfs-1.1.1/extras/selfextract.c [new file with mode: 0644]
src/unison/physfs-1.1.1/lzma/7zAlloc.h [new file with mode: 0644]
src/unison/physfs-1.1.1/lzma/7zBuffer.c [new file with mode: 0644]
src/unison/physfs-1.1.1/lzma/7zBuffer.h [new file with mode: 0644]
src/unison/physfs-1.1.1/lzma/7zCrc.c [new file with mode: 0644]
src/unison/physfs-1.1.1/lzma/7zCrc.h [new file with mode: 0644]
src/unison/physfs-1.1.1/lzma/7zDecode.c [new file with mode: 0644]
src/unison/physfs-1.1.1/lzma/7zDecode.h [new file with mode: 0644]
src/unison/physfs-1.1.1/lzma/7zExtract.c [new file with mode: 0644]
src/unison/physfs-1.1.1/lzma/7zExtract.h [new file with mode: 0644]
src/unison/physfs-1.1.1/lzma/7zHeader.c [new file with mode: 0644]
src/unison/physfs-1.1.1/lzma/7zHeader.h [new file with mode: 0644]
src/unison/physfs-1.1.1/lzma/7zIn.c [new file with mode: 0644]
src/unison/physfs-1.1.1/lzma/7zIn.h [new file with mode: 0644]
src/unison/physfs-1.1.1/lzma/7zItem.c [new file with mode: 0644]
src/unison/physfs-1.1.1/lzma/7zItem.h [new file with mode: 0644]
src/unison/physfs-1.1.1/lzma/7zMethodID.c [new file with mode: 0644]
src/unison/physfs-1.1.1/lzma/7zMethodID.h [new file with mode: 0644]
src/unison/physfs-1.1.1/lzma/7zTypes.h [new file with mode: 0644]
src/unison/physfs-1.1.1/lzma/LZMA-LICENSE.txt [new file with mode: 0644]
src/unison/physfs-1.1.1/lzma/LzmaDecode.c [new file with mode: 0644]
src/unison/physfs-1.1.1/lzma/LzmaDecode.h [new file with mode: 0644]
src/unison/physfs-1.1.1/lzma/LzmaStateDecode.c [new file with mode: 0644]
src/unison/physfs-1.1.1/lzma/LzmaStateDecode.h [new file with mode: 0644]
src/unison/physfs-1.1.1/lzma/LzmaTypes.h [new file with mode: 0644]
src/unison/physfs-1.1.1/makeos2.cmd [new file with mode: 0644]
src/unison/physfs-1.1.1/physfs-1.1.1/CMakeFiles/CMakeError.log [new file with mode: 0644]
src/unison/physfs-1.1.1/physfs-1.1.1/CMakeFiles/CMakeTmp/src.c [new file with mode: 0644]
src/unison/physfs-1.1.1/physfs.c [new file with mode: 0644]
src/unison/physfs-1.1.1/physfs.h [new file with mode: 0644]
src/unison/physfs-1.1.1/physfs.spec.in [new file with mode: 0644]
src/unison/physfs-1.1.1/physfs_byteorder.c [new file with mode: 0644]
src/unison/physfs-1.1.1/physfs_casefolding.h [new file with mode: 0644]
src/unison/physfs-1.1.1/physfs_internal.h [new file with mode: 0644]
src/unison/physfs-1.1.1/physfs_platforms.h [new file with mode: 0644]
src/unison/physfs-1.1.1/physfs_unicode.c [new file with mode: 0644]
src/unison/physfs-1.1.1/platform/beos.cpp [new file with mode: 0644]
src/unison/physfs-1.1.1/platform/macosx.c [new file with mode: 0644]
src/unison/physfs-1.1.1/platform/os2.c [new file with mode: 0644]
src/unison/physfs-1.1.1/platform/pocketpc.c [new file with mode: 0644]
src/unison/physfs-1.1.1/platform/posix.c [new file with mode: 0644]
src/unison/physfs-1.1.1/platform/unix.c [new file with mode: 0644]
src/unison/physfs-1.1.1/platform/windows.c [new file with mode: 0644]
src/unison/physfs-1.1.1/test/test_physfs.c [new file with mode: 0644]
src/unison/physfs-1.1.1/test/wxtest_physfs.cpp [new file with mode: 0644]
src/unison/physfs-1.1.1/zlib123/adler32.c [new file with mode: 0644]
src/unison/physfs-1.1.1/zlib123/compress.c [new file with mode: 0644]
src/unison/physfs-1.1.1/zlib123/crc32.c [new file with mode: 0644]
src/unison/physfs-1.1.1/zlib123/crc32.h [new file with mode: 0644]
src/unison/physfs-1.1.1/zlib123/deflate.c [new file with mode: 0644]
src/unison/physfs-1.1.1/zlib123/deflate.h [new file with mode: 0644]
src/unison/physfs-1.1.1/zlib123/gzio.c [new file with mode: 0644]
src/unison/physfs-1.1.1/zlib123/infback.c [new file with mode: 0644]
src/unison/physfs-1.1.1/zlib123/inffast.c [new file with mode: 0644]
src/unison/physfs-1.1.1/zlib123/inffast.h [new file with mode: 0644]
src/unison/physfs-1.1.1/zlib123/inffixed.h [new file with mode: 0644]
src/unison/physfs-1.1.1/zlib123/inflate.c [new file with mode: 0644]
src/unison/physfs-1.1.1/zlib123/inflate.h [new file with mode: 0644]
src/unison/physfs-1.1.1/zlib123/inftrees.c [new file with mode: 0644]
src/unison/physfs-1.1.1/zlib123/inftrees.h [new file with mode: 0644]
src/unison/physfs-1.1.1/zlib123/trees.c [new file with mode: 0644]
src/unison/physfs-1.1.1/zlib123/trees.h [new file with mode: 0644]
src/unison/physfs-1.1.1/zlib123/uncompr.c [new file with mode: 0644]
src/unison/physfs-1.1.1/zlib123/zconf.h [new file with mode: 0644]
src/unison/physfs-1.1.1/zlib123/zlib.h [new file with mode: 0644]
src/unison/physfs-1.1.1/zlib123/zutil.c [new file with mode: 0644]
src/unison/physfs-1.1.1/zlib123/zutil.h [new file with mode: 0644]
src/unison/src/vfs/FileSystem.cpp [new file with mode: 0644]
src/unison/src/vfs/sdl/Utils.cpp [new file with mode: 0644]
src/unison/src/vfs/stream.cpp [new file with mode: 0644]
src/unison/src/video/Blittable.cpp [new file with mode: 0644]
src/unison/src/video/Blitters.cpp [new file with mode: 0644]
src/unison/src/video/Color.cpp [new file with mode: 0644]
src/unison/src/video/Renderers.cpp [new file with mode: 0644]
src/unison/src/video/Surface.cpp [new file with mode: 0644]
src/unison/src/video/Texture.cpp [new file with mode: 0644]
src/unison/src/video/Window.cpp [new file with mode: 0644]
src/unison/src/video/auto/Renderer.cpp [new file with mode: 0644]
src/unison/src/video/auto/Renderer.hpp [new file with mode: 0644]
src/unison/src/video/backend/Texture.cpp [new file with mode: 0644]
src/unison/src/video/opengl/Renderer.cpp [new file with mode: 0644]
src/unison/src/video/opengl/Renderer.hpp [new file with mode: 0644]
src/unison/src/video/opengl/SDL_gl.c [new file with mode: 0644]
src/unison/src/video/opengl/SDL_gl.h [new file with mode: 0644]
src/unison/src/video/opengl/SDL_glfuncs.h [new file with mode: 0644]
src/unison/src/video/opengl/Texture.cpp [new file with mode: 0644]
src/unison/src/video/opengl/Texture.hpp [new file with mode: 0644]
src/unison/src/video/opengl/Window.cpp [new file with mode: 0644]
src/unison/src/video/opengl/Window.hpp [new file with mode: 0644]
src/unison/src/video/sdl/Blitters.cpp [new file with mode: 0644]
src/unison/src/video/sdl/Renderer.cpp [new file with mode: 0644]
src/unison/src/video/sdl/Renderer.hpp [new file with mode: 0644]
src/unison/src/video/sdl/Texture.cpp [new file with mode: 0644]
src/unison/src/video/sdl/Texture.hpp [new file with mode: 0644]
src/unison/src/video/sdl/Window.cpp [new file with mode: 0644]
src/unison/src/video/sdl/Window.hpp [new file with mode: 0644]
src/video/color.hpp
src/video/drawing_context.cpp
src/video/drawing_context.hpp
src/video/drawing_request.hpp
src/video/font.cpp
src/video/font.hpp
src/video/gl_lightmap.cpp [deleted file]
src/video/gl_lightmap.hpp [deleted file]
src/video/gl_renderer.cpp [deleted file]
src/video/gl_renderer.hpp [deleted file]
src/video/gl_surface_data.hpp [deleted file]
src/video/gl_texture.cpp [deleted file]
src/video/gl_texture.hpp [deleted file]
src/video/glutil.hpp
src/video/lightmap.hpp [deleted file]
src/video/renderer.hpp [deleted file]
src/video/sdl_lightmap.cpp [deleted file]
src/video/sdl_lightmap.hpp [deleted file]
src/video/sdl_renderer.cpp [deleted file]
src/video/sdl_renderer.hpp [deleted file]
src/video/sdl_surface_data.hpp [deleted file]
src/video/sdl_texture.cpp [deleted file]
src/video/sdl_texture.hpp [deleted file]
src/video/surface.hpp
src/video/texture.hpp [deleted file]
src/video/texture_manager.cpp [deleted file]
src/video/texture_manager.hpp [deleted file]
src/video/video_systems.cpp [deleted file]
src/video/video_systems.hpp [deleted file]
src/world.cpp
src/worldmap/level.cpp
src/worldmap/worldmap.cpp

index 79e3537..c60a395 100644 (file)
 #include <sstream>
 #include <stdexcept>
 #include <list>
-#include <physfs.h>
+//#include <physfs.h>
+#include <unison/vfs/FileSystem.hpp>
+#include <unison/vfs/sdl/Utils.hpp>
 #include <sys/stat.h>
 #include <stdio.h>
+#include "SDL.h"
 #include "addon_manager.hpp"
 #include "config.h"
 #include "log.hpp"
@@ -50,12 +53,20 @@ namespace {
     return size * nmemb;
   }
 
-  size_t my_curl_physfs_write(void *ptr, size_t size, size_t nmemb, void *f_p)
+  /*size_t my_curl_physfs_write(void *ptr, size_t size, size_t nmemb, void *f_p)
   {
     PHYSFS_file* f = static_cast<PHYSFS_file*>(f_p);
     PHYSFS_sint64 written = PHYSFS_write(f, ptr, size, nmemb);
     log_debug << "read " << size * nmemb << " bytes of data..." << std::endl;
     return size * written;
+  }*/
+
+  size_t my_curl_sdl_write(void *ptr, size_t size, size_t nmemb, void *f_p)
+  {
+    SDL_RWops* f = static_cast<SDL_RWops*>(f_p);
+    int written = SDL_RWwrite(f, ptr, size, nmemb);
+    log_debug << "wrote " << size * nmemb << " bytes of data..." << std::endl;
+    return size * written;
   }
 
 }
@@ -87,16 +98,15 @@ AddonManager::get_installed_addons() const
 {
   std::vector<Addon> addons;
 
-  // iterate over complete search path (i.e. directories and archives)
-  char **i = PHYSFS_getSearchPath();
-  if (!i) throw std::runtime_error("Could not query physfs search path");
-  for (; *i != NULL; i++) {
-
+  Unison::VFS::FileSystem &fs = Unison::VFS::FileSystem::get();
+  std::vector<std::string> search_path = fs.get_search_path();
+  for(std::vector<std::string>::iterator iter = search_path.begin();iter != search_path.end();++iter)
+  {
     // get filename of potential archive
-    std::string fileName = *i;
+    std::string fileName = *iter;
 
     // make sure it's in the writeDir
-    static const std::string writeDir = PHYSFS_getWriteDir();
+    static const std::string writeDir = fs.get_write_dir();
     if (fileName.compare(0, writeDir.length(), writeDir) != 0) continue;
 
     // make sure it looks like an archive
@@ -113,7 +123,7 @@ AddonManager::get_installed_addons() const
     Addon addon;
 
     // extract nice title as fallback for when the Add-on has no addoninfo file
-    static const char* dirSep = PHYSFS_getDirSeparator();
+    static std::string dirSep = fs.get_dir_sep();
     std::string::size_type n = fileName.rfind(dirSep) + 1;
     if (n == std::string::npos) n = 0;
     addon.title = fileName.substr(n, fileName.length() - n - archiveExt.length());
@@ -123,7 +133,7 @@ AddonManager::get_installed_addons() const
     // read an accompaining .nfo file, if it exists
     static const std::string infoExt = ".nfo";
     std::string infoFileName = fileName.substr(n, fileName.length() - n - archiveExt.length()) + infoExt;
-    if (PHYSFS_exists(infoFileName.c_str())) {
+    if (fs.exists(infoFileName)) {
       addon.parse(infoFileName);
       if (addon.file != shortFileName) {
         log_warning << "Add-on \"" << addon.title << "\", contained in file \"" << shortFileName << "\" is accompained by an addoninfo file that specifies \"" << addon.file << "\" as the Add-on's file name. Skipping." << std::endl;
@@ -220,6 +230,8 @@ AddonManager::install(const Addon& addon)
     throw std::runtime_error("Add-on has unsafe file name (\""+addon.file+"\")");
   }
 
+  Unison::VFS::FileSystem &fs = Unison::VFS::FileSystem::get();
+
 #ifdef HAVE_LIBCURL
 
   char error_buffer[CURL_ERROR_SIZE+1];
@@ -227,7 +239,8 @@ AddonManager::install(const Addon& addon)
   char* url = (char*)malloc(addon.http_url.length() + 1);
   strncpy(url, addon.http_url.c_str(), addon.http_url.length() + 1);
 
-  PHYSFS_file* f = PHYSFS_openWrite(addon.file.c_str());
+  //PHYSFS_file* f = PHYSFS_openWrite(addon.file.c_str());
+  SDL_RWops *f = Unison::VFS::SDL::Utils::open_physfs_in(addon.file);
 
   log_debug << "Downloading \"" << url << "\"" << std::endl;
 
@@ -235,7 +248,7 @@ AddonManager::install(const Addon& addon)
   curl_handle = curl_easy_init();
   curl_easy_setopt(curl_handle, CURLOPT_URL, url);
   curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "SuperTux/" PACKAGE_VERSION " libcURL");
-  curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, my_curl_physfs_write);
+  curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, my_curl_sdl_write);
   curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, f);
   curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, error_buffer);
   curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1);
@@ -244,12 +257,14 @@ AddonManager::install(const Addon& addon)
   CURLcode result = curl_easy_perform(curl_handle);
   curl_easy_cleanup(curl_handle);
 
-  PHYSFS_close(f);
+  //PHYSFS_close(f);
+  SDL_RWclose(f);
 
   free(url);
 
   if (result != CURLE_OK) {
-    PHYSFS_delete(addon.file.c_str());
+    //PHYSFS_delete(addon.file.c_str());
+    fs.rm(addon.file);
     std::string why = error_buffer[0] ? error_buffer : "unhandled error";
     throw std::runtime_error("Downloading Add-on failed: " + why);
   }
@@ -260,11 +275,14 @@ AddonManager::install(const Addon& addon)
   std::string infoFileName = addon.file.substr(0, addon.file.length()-archiveExt.length()) + infoExt;
   addon.write(infoFileName);
 
-  static const std::string writeDir = PHYSFS_getWriteDir();
-  static const std::string dirSep = PHYSFS_getDirSeparator();
+  //static const std::string writeDir = PHYSFS_getWriteDir();
+  //static const std::string dirSep = PHYSFS_getDirSeparator();
+  static const std::string writeDir = fs.get_write_dir();
+  static const std::string dirSep = fs.get_dir_sep();
   std::string fullFilename = writeDir + dirSep + addon.file;
   log_debug << "Finished downloading \"" << fullFilename << "\"" << std::endl;
-  PHYSFS_addToSearchPath(fullFilename.c_str(), 1);
+  fs.mount(fullFilename, "/", true);
+  //PHYSFS_addToSearchPath(fullFilename.c_str(), 1);
 #else
   (void) addon;
 #endif
@@ -280,16 +298,18 @@ AddonManager::remove(const Addon& addon)
   }
 
   log_debug << "deleting file \"" << addon.file << "\"" << std::endl;
-  PHYSFS_removeFromSearchPath(addon.file.c_str());
-  PHYSFS_delete(addon.file.c_str());
+
+  Unison::VFS::FileSystem &fs = Unison::VFS::FileSystem::get();
+  fs.umount(addon.file);
+  fs.rm(addon.file);
 
   // remove an accompaining .nfo file
   static const std::string archiveExt = ".zip";
   static const std::string infoExt = ".nfo";
   std::string infoFileName = addon.file.substr(0, addon.file.length()-archiveExt.length()) + infoExt;
-  if (PHYSFS_exists(infoFileName.c_str())) {
+  if (fs.exists(infoFileName)) {
     log_debug << "deleting file \"" << infoFileName << "\"" << std::endl;
-    PHYSFS_delete(infoFileName.c_str());
+    fs.rm(infoFileName);
   }
 }
 
index 060eed0..4972804 100644 (file)
@@ -36,7 +36,8 @@ Config* config = 0;
 Config::Config()
 {
   use_fullscreen = true;
-  video = AUTO_VIDEO;
+  //video = AUTO_VIDEO;
+  video = "auto";
   try_vsync = true;
   show_fps = false;
   sound_enabled = true;
@@ -74,9 +75,10 @@ Config::load()
   const lisp::Lisp* config_video_lisp = config_lisp->get_lisp("video");
   if(config_video_lisp) {
     config_video_lisp->get("fullscreen", use_fullscreen);
-    std::string video_string;
-    config_video_lisp->get("video", video_string);
-    video = get_video_system(video_string);
+    //std::string video_string;
+    //config_video_lisp->get("video", video_string);
+    //video = get_video_system(video_string);
+    config_video_lisp->get("video", video);
     config_video_lisp->get("vsync", try_vsync);
     config_video_lisp->get("width", screenwidth);
     config_video_lisp->get("height", screenheight);
@@ -108,7 +110,8 @@ Config::save()
 
   writer.start_list("video");
   writer.write_bool("fullscreen", use_fullscreen);
-  writer.write_string("video", get_video_string(video));
+  //writer.write_string("video", get_video_string(video));
+  writer.write_string("video", video);
   writer.write_bool("vsync", try_vsync);
   writer.write_int("width", screenwidth);
   writer.write_int("height", screenheight);
index ac45730..2c39f93 100644 (file)
@@ -23,7 +23,7 @@
 
 #include <string>
 
-#include "video/video_systems.hpp"
+//#include "video/video_systems.hpp"
 
 class Config
 {
@@ -43,7 +43,7 @@ public:
   float aspect_ratio;
 
   bool use_fullscreen;
-  VideoSystem video;
+  std::string video;
   bool try_vsync;
   bool show_fps;
   bool sound_enabled;
index a558adc..c59535f 100644 (file)
@@ -66,8 +66,9 @@ static std::string dirname(const std::string& filename)
 const Lisp*
 Parser::parse(const std::string& filename)
 {
-  IFileStreambuf ins(filename);
-  std::istream in(&ins);
+  Unison::VFS::istream in(filename);
+  //IFileStreambuf ins(filename);
+  //std::istream in(&ins);
 
   if(!in.good()) {
     std::stringstream msg;
index cca8615..1e10203 100644 (file)
@@ -30,9 +30,9 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
-#include <physfs.h>
+//#include <physfs.h>
 #include <SDL.h>
-#include <SDL_image.h>
+//#include <SDL_image.h>
 
 #ifdef MACOSX
 namespace supertux_apple {
@@ -40,12 +40,15 @@ namespace supertux_apple {
 }
 #endif
 
+#include <unison/video/Window.hpp>
+#include <unison/vfs/FileSystem.hpp>
+
 #include "gameconfig.hpp"
 #include "resources.hpp"
 #include "gettext.hpp"
 #include "audio/sound_manager.hpp"
 #include "video/surface.hpp"
-#include "video/texture_manager.hpp"
+//#include "video/texture_manager.hpp"
 #include "video/drawing_context.hpp"
 #include "video/glutil.hpp"
 #include "control/joystickkeyboardcontroller.hpp"
@@ -92,6 +95,118 @@ static void init_tinygettext()
 
 static void init_physfs(const char* argv0)
 {
+  Unison::VFS::FileSystem &fs = Unison::VFS::FileSystem::get();
+  std::string application = "supertux2";
+  std::string userdir = fs.get_user_dir();
+  std::string dirsep = fs.get_dir_sep();
+  std::string writedir = userdir + "." + application;
+  fs.set_write_dir(writedir);
+  fs.mount(writedir, "/", true);
+
+  // Search for archives and add them to the search path
+  const char* archiveExt = ".zip";
+  std::vector<std::string> rc = fs.ls("/");
+  for(std::vector<std::string>::iterator iter = rc.begin(); iter != rc.end(); ++iter)
+  {
+    std::string ext = iter->substr(iter->length() - 4);
+    if(strcasecmp(ext.c_str(), archiveExt) == 0)
+    {
+      std::string dir = fs.get_real_dir(*iter);
+      fs.mount(dir + fs.get_dir_sep() + *iter, "/", true);
+    }
+  }
+
+  // when started from source dir...
+  std::string dir = fs.get_base_dir();
+  dir += "/data";
+  std::string testfname = dir;
+  testfname += "/credits.txt";
+  bool sourcedir = false;
+  FILE* f = fopen(testfname.c_str(), "r");
+  if(f) {
+    fclose(f);
+    fs.mount(dir, "/", true);
+    sourcedir = true;
+    /*if(!PHYSFS_addToSearchPath(dir.c_str(), 1)) {
+      log_warning << "Couldn't add '" << dir << "' to physfs searchpath: " << PHYSFS_getLastError() << std::endl;
+    } else {
+      sourcedir = true;
+    }*/
+  }
+
+#ifdef MACOSX
+  // when started from Application file on Mac OS X...
+  char path[PATH_MAX];
+  CFBundleRef mainBundle = CFBundleGetMainBundle();
+  assert(mainBundle != 0);
+  CFURLRef mainBundleURL = CFBundleCopyBundleURL(mainBundle);
+  assert(mainBundleURL != 0);
+  CFStringRef pathStr = CFUrlCopyFileSystemPath(mainBundleURL, kCFURLPOSIXPathStyle);
+  assert(pathStr != 0);
+  CFStringGetCString(pathStr, path, PATH_MAX, kCFStringEncodingUTF8);
+  CFRelease(mainBundleURL);
+  CFRelease(pathStr);
+
+  dir = std::string(path) + "/Contents/Resources/data";
+  testfname = dir + "/credits.txt";
+  sourcedir = false;
+  f = fopen(testfname.c_str(), "r");
+  if(f) {
+    fclose(f);
+    fs.mount(dir, "/", true);
+    sourcedir = true;
+    /*if(!PHYSFS_addToSearchPath(dir.c_str(), 1)) {
+      log_warning << "Couldn't add '" << dir << "' to physfs searchpath: " << PHYSFS_getLastError() << std::endl;
+    } else {
+      sourcedir = true;
+    }*/
+  }
+#endif
+
+#ifdef _WIN32
+  fs.mount(".\\data", "/", true);
+  //PHYSFS_addToSearchPath(".\\data", 1);
+#endif
+
+  if(!sourcedir) {
+#if defined(APPDATADIR) || defined(ENABLE_BINRELOC)
+    std::string datadir;
+#ifdef ENABLE_BINRELOC
+
+    char* dir;
+    br_init (NULL);
+    dir = br_find_data_dir(APPDATADIR);
+    datadir = dir;
+    free(dir);
+
+#else
+    datadir = APPDATADIR;
+#endif
+    datadir += "/";
+    datadir += application;
+    fs.mount(datadir, "/", true);
+    /*if(!PHYSFS_addToSearchPath(datadir.c_str(), 1)) {
+      log_warning << "Couldn't add '" << datadir << "' to physfs searchpath: " << PHYSFS_getLastError() << std::endl;
+    }*/
+#endif
+  }
+
+  // allow symbolic links
+  //PHYSFS_permitSymbolicLinks(1);
+  //fs.follow_sym_links(true);
+
+  //show search Path
+  std::vector<std::string> searchpath = fs.get_search_path();
+  for(std::vector<std::string>::iterator iter = searchpath.begin(); iter != searchpath.end(); ++iter)
+    log_info << "[" << *iter << "] is in the search path" << std::endl;
+  /*
+  char** searchpath = PHYSFS_getSearchPath();
+  for(char** i = searchpath; *i != NULL; i++)
+    log_info << "[" << *i << "] is in the search path" << std::endl;
+  PHYSFS_freeList(searchpath);
+  */
+
+#if 0
   if(!PHYSFS_init(argv0)) {
     std::stringstream msg;
     msg << "Couldn't initialize physfs: " << PHYSFS_getLastError();
@@ -234,6 +349,7 @@ static void init_physfs(const char* argv0)
   for(char** i = searchpath; *i != NULL; i++)
     log_info << "[" << *i << "] is in the search path" << std::endl;
   PHYSFS_freeList(searchpath);
+#endif
 }
 
 static void print_usage(const char* argv0)
@@ -427,9 +543,12 @@ void init_video()
   context_pointer->init_renderer();
   screen = SDL_GetVideoSurface();
 
-  SDL_WM_SetCaption(PACKAGE_NAME " " PACKAGE_VERSION, 0);
+  Unison::Video::Window::get().set_title(PACKAGE_NAME " " PACKAGE_VERSION);
+  Unison::Video::Window::get().set_icon(Unison::Video::Surface("images/engine/icons/supertux.xpm"));
+  //SDL_WM_SetCaption(PACKAGE_NAME " " PACKAGE_VERSION, 0);
 
   // set icon
+  /*
   SDL_Surface* icon = IMG_Load_RW(
       get_physfs_SDLRWops("images/engine/icons/supertux.xpm"), true);
   if(icon != 0) {
@@ -441,6 +560,7 @@ void init_video()
     log_warning << "Couldn't find icon 'images/engine/icons/supertux.xpm'" << std::endl;
   }
 #endif
+  */
 
   SDL_ShowCursor(0);
 
@@ -566,7 +686,8 @@ int main(int argc, char** argv)
       // we have a normal path specified at commandline not physfs paths.
       // So we simply mount that path here...
       std::string dir = FileSystem::dirname(config->start_level);
-      PHYSFS_addToSearchPath(dir.c_str(), true);
+      Unison::VFS::FileSystem::get().mount(dir, "/", true);
+      //PHYSFS_addToSearchPath(dir.c_str(), true);
 
       if(config->start_level.size() > 4 &&
               config->start_level.compare(config->start_level.size() - 5, 5, ".stwm") == 0) {
@@ -621,10 +742,10 @@ int main(int argc, char** argv)
   delete Console::instance;
   Console::instance = NULL;
   Scripting::exit_squirrel();
-  delete texture_manager;
-  texture_manager = NULL;
+  //delete texture_manager;
+  //texture_manager = NULL;
   SDL_Quit();
-  PHYSFS_deinit();
+  //PHYSFS_deinit();
 
   return result;
 }
index 4ad2b6e..76c3be9 100644 (file)
 //  along with this program; if not, write to the Free Software
 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
+#include <unison/vfs/stream.hpp>
+#include <unison/vfs/sdl/Utils.hpp>
+
+#include <stdexcept>
+
+SDL_RWops* get_physfs_SDLRWops(const std::string& filename)
+{
+       // check this as PHYSFS seems to be buggy and still returns a
+       // valid pointer in this case
+       if(filename == "") {
+               throw std::runtime_error("Couldn't open file: empty filename");
+       }
+  return Unison::VFS::SDL::Utils::open_physfs_in(filename);
+}
+
+#if 0
 #include <config.h>
 
 #include "physfs_sdl.hpp"
@@ -100,3 +116,4 @@ SDL_RWops* get_physfs_SDLRWops(const std::string& filename)
     ops->close = funcClose;
     return ops;
 }
+#endif
index c4347b2..beb5848 100644 (file)
@@ -17,6 +17,7 @@
 //  along with this program; if not, write to the Free Software
 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
+#if 0
 #include <config.h>
 
 #include "physfs_stream.hpp"
@@ -177,3 +178,4 @@ OFileStream::~OFileStream()
 {
     delete rdbuf();
 }
+#endif
index 077a876..d861236 100644 (file)
 #ifndef __PHYSFSSTREAM_HPP__
 #define __PHYSFSSTREAM_HPP__
 
+#include <unison/vfs/stream.hpp>
+
+typedef Unison::VFS::istream IFileStream;
+typedef Unison::VFS::ostream OFileStream;
+
+#if 0
 #include <stddef.h>
 #include <physfs.h>
 #include <string>
@@ -74,5 +80,6 @@ public:
     OFileStream(const std::string& filename);
     ~OFileStream();
 };
+#endif
 
 #endif
index 57418fd..cd4276b 100644 (file)
@@ -28,7 +28,8 @@
 #include <float.h>
 #include <math.h>
 #include <limits>
-#include <physfs.h>
+//#include <physfs.h>
+#include <unison/vfs/FileSystem.hpp>
 
 #include "sector.hpp"
 #include "object/player.hpp"
@@ -245,7 +246,7 @@ Sector::parse_old_format(const lisp::Lisp& reader)
     if (backgroundimage == "arctis2.jpg") backgroundimage = "arctis.jpg";
     if (backgroundimage == "ocean.png") backgroundimage = "ocean.jpg";
     backgroundimage = "images/background/" + backgroundimage;
-    if (!PHYSFS_exists(backgroundimage.c_str())) {
+    if (!Unison::VFS::FileSystem::get().exists(backgroundimage)) {
       log_warning << "Background image \"" << backgroundimage << "\" not found. Ignoring." << std::endl;
       backgroundimage = "";
     }
index d22ae2a..d2df1e5 100644 (file)
@@ -31,6 +31,7 @@
 #include "tinygettext.hpp"
 #include "log.hpp"
 #include "physfs/physfs_stream.hpp"
+#include <unison/vfs/FileSystem.hpp>
 #include "log.hpp"
 #include "findlocale.hpp"
 
@@ -264,65 +265,99 @@ DictionaryManager::get_dictionary(const std::string& spec)
 
   Dictionaries::iterator i = dictionaries.find(get_language_from_spec(lang));
   if (i != dictionaries.end())
-    {
-      return i->second;
-    }
+  {
+    return i->second;
+  }
   else // Dictionary for languages lang isn't loaded, so we load it
-    {
-      //log_debug << "get_dictionary: " << lang << std::endl;
-      Dictionary& dict = dictionaries[lang];
+  {
+    //log_debug << "get_dictionary: " << lang << std::endl;
+    Dictionary& dict = dictionaries[lang];
 
-      dict.set_language(get_language_def(lang));
-      if(charset != "")
-        dict.set_charset(charset);
+    dict.set_language(get_language_def(lang));
+    if(charset != "")
+      dict.set_charset(charset);
 
-      for (SearchPath::iterator p = search_path.begin(); p != search_path.end(); ++p)
-        {
-          char** files = PHYSFS_enumerateFiles(p->c_str());
-          if(!files)
-            {
-              log_warning << "Error: enumerateFiles() failed on " << *p << std::endl;
+    for (SearchPath::iterator p = search_path.begin(); p != search_path.end(); ++p)
+    {
+      std::vector<std::string> files = Unison::VFS::FileSystem::get().ls(*p);
+      for(std::vector<std::string>::iterator iter = files.begin();iter != files.end();++iter)
+      {
+        // check if filename matches requested language
+        std::string fname = *iter;
+        std::string load_from_file = "";
+        if(fname == lang + ".po") {
+          load_from_file = fname;
+        } else {
+          std::string::size_type s = lang.find("_");
+          if(s != std::string::npos) {
+            std::string lang_short = std::string(lang, 0, s);
+            if (fname == lang_short + ".po") {
+              load_from_file = lang_short;
             }
-          else
-            {
-              for(const char* const* filename = files;
-                      *filename != 0; filename++) {
-
-                // check if filename matches requested language
-               std::string fname = std::string(*filename);
-               std::string load_from_file = "";
-                if(fname == lang + ".po") {
-                 load_from_file = fname;
-               } else {
-                  std::string::size_type s = lang.find("_");
-                  if(s != std::string::npos) {
-                    std::string lang_short = std::string(lang, 0, s);
-                   if (fname == lang_short + ".po") {
-                     load_from_file = lang_short;
-                   }
-                  }
-               }
-
-               // if it matched, load dictionary
-               if (load_from_file != "") {
-                  //log_debug << "Loading dictionary for language \"" << lang << "\" from \"" << filename << "\"" << std::endl;
-                  std::string pofile = *p + "/" + *filename;
-                  try {
-                      IFileStream in(pofile);
-                      read_po_file(dict, in);
-                  } catch(std::exception& e) {
-                      log_warning << "Error: Failure file opening: " << pofile << std::endl;
-                      log_warning << e.what() << "" << std::endl;
-                  }
-                }
+          }
+        }
 
-              }
-              PHYSFS_freeList(files);
-            }
+        // if it matched, load dictionary
+        if (load_from_file != "") {
+          //log_debug << "Loading dictionary for language \"" << lang << "\" from \"" << filename << "\"" << std::endl;
+          std::string pofile = *p + "/" + *iter;
+          try {
+            IFileStream in(pofile);
+            read_po_file(dict, in);
+          } catch(std::exception& e) {
+            log_warning << "Error: Failure file opening: " << pofile << std::endl;
+            log_warning << e.what() << "" << std::endl;
+          }
+        }
+      }
+
+#if 0
+      char** files = PHYSFS_enumerateFiles(p->c_str());
+      if(!files)
+      {
+        log_warning << "Error: enumerateFiles() failed on " << *p << std::endl;
+      }
+      else
+      {
+        for(const char* const* filename = files;
+        *filename != 0; filename++) {
+
+        // check if filename matches requested language
+        std::string fname = std::string(*filename);
+        std::string load_from_file = "";
+        if(fname == lang + ".po") {
+          load_from_file = fname;
+        } else {
+          std::string::size_type s = lang.find("_");
+          if(s != std::string::npos) {
+            std::string lang_short = std::string(lang, 0, s);
+          if (fname == lang_short + ".po") {
+            load_from_file = lang_short;
+          }
         }
+      }
+
+      // if it matched, load dictionary
+      if (load_from_file != "") {
+        //log_debug << "Loading dictionary for language \"" << lang << "\" from \"" << filename << "\"" << std::endl;
+        std::string pofile = *p + "/" + *filename;
+        try {
+          IFileStream in(pofile);
+          read_po_file(dict, in);
+        } catch(std::exception& e) {
+          log_warning << "Error: Failure file opening: " << pofile << std::endl;
+          log_warning << e.what() << "" << std::endl;
+        }
+      }
 
-      return dict;
+      }
+      PHYSFS_freeList(files);
+      }
+#endif
     }
+
+    return dict;
+  }
 }
 
 std::set<std::string>
@@ -332,6 +367,15 @@ DictionaryManager::get_languages()
 
   for (SearchPath::iterator p = search_path.begin(); p != search_path.end(); ++p)
     {
+      std::vector<std::string> files = Unison::VFS::FileSystem::get().ls(*p);
+      for(std::vector<std::string>::iterator iter = files.begin();iter != files.end();++iter)
+      {
+        if(has_suffix(*iter, ".po")) {
+          std::string filename = *iter;
+          languages.insert(filename.substr(0, filename.length()-3));
+        }
+      }
+#if 0
       char** files = PHYSFS_enumerateFiles(p->c_str());
       if (!files)
         {
@@ -347,6 +391,7 @@ DictionaryManager::get_languages()
           }
           PHYSFS_freeList(files);
         }
+#endif
     }
   return languages;
 }
index a53f8ab..3778b17 100644 (file)
@@ -30,8 +30,9 @@
 #include <errno.h>
 #include <unistd.h>
 #include <SDL.h>
-#include <SDL_image.h>
-#include <physfs.h>
+//#include <SDL_image.h>
+//#include <physfs.h>
+#include <unison/vfs/FileSystem.hpp>
 
 #include "title.hpp"
 #include "mainloop.hpp"
@@ -105,13 +106,20 @@ TitleScreen::generate_contrib_menu()
 {
   /** Generating contrib levels list by making use of Level Subset  */
   std::vector<std::string> level_worlds;
-  char** files = PHYSFS_enumerateFiles("levels/");
+  std::vector<std::string> files = Unison::VFS::FileSystem::get().ls("levels/");
+  for(std::vector<std::string>::iterator iter = files.begin();iter != files.end();++iter)
+  {
+    std::string filepath = "levels/" + *iter;
+    if(Unison::VFS::FileSystem::get().is_dir(filepath))
+      level_worlds.push_back(filepath);
+  }
+  /*char** files = PHYSFS_enumerateFiles("levels/");
   for(const char* const* filename = files; *filename != 0; ++filename) {
     std::string filepath = std::string("levels/") + *filename;
     if(PHYSFS_isDirectory(filepath.c_str()))
       level_worlds.push_back(filepath);
   }
-  PHYSFS_freeList(files);
+  PHYSFS_freeList(files);*/
 
   free_contrib_menu();
   contrib_menu.reset(new Menu());
@@ -532,7 +540,8 @@ TitleScreen::get_slotinfo(int slot)
   stream << "save/" << worlddirname << "_" << slot << ".stsg";
   std::string slotfile = stream.str();
 
-  try {
+  if(Unison::VFS::FileSystem::get().exists(slotfile))
+  {
     lisp::Parser parser;
     const lisp::Lisp* root = parser.parse(slotfile);
 
@@ -541,7 +550,9 @@ TitleScreen::get_slotinfo(int slot)
       throw std::runtime_error("file is not a supertux-savegame.");
 
     savegame->get("title", title);
-  } catch(std::exception& ) {
+  }
+  else
+  {
     std::ostringstream slottitle;
     slottitle << _("Slot") << " " << slot << " - " << _("Free");
     return slottitle.str();
diff --git a/src/unison/CMakeLists.txt b/src/unison/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f3a758d
--- /dev/null
@@ -0,0 +1,55 @@
+#          Copyright Timothy Goya 2007.
+# Distributed under the Boost Software License, Version 1.0.
+#    (See accompanying file LICENSE_1_0.txt or copy at
+#          http://www.boost.org/LICENSE_1_0.txt)
+
+PROJECT(UNISON)
+
+INCLUDE_DIRECTORIES(${UNISON_SOURCE_DIR}/include/)
+
+FIND_PACKAGE(SDL REQUIRED)
+INCLUDE_DIRECTORIES(${SDL_INCLUDE_DIR})
+LINK_LIBRARIES(${SDL_LIBRARY})
+
+FIND_PACKAGE(SDL_image REQUIRED)
+INCLUDE_DIRECTORIES(${SDLIMAGE_INCLUDE_DIR})
+LINK_LIBRARIES(${SDLIMAGE_LIBRARY})
+
+FIND_PACKAGE(PhysFS)
+IF(${PHYSFS_FOUND} STREQUAL "NO")
+  SET(PHYSFS_BUILD_SHARED FALSE)
+  ADD_SUBDIRECTORY(physfs-1.1.1)
+  SET(PHYSFS_INCLUDE_DIR physfs-1.1.1)
+  SET(PHYSFS_LIBRARY ${UNISON_BINARY_DIR}/physfs-1.1.1/libphysfs.a)
+ENDIF(${PHYSFS_FOUND} STREQUAL "NO")
+INCLUDE_DIRECTORIES(${PHYSFS_INCLUDE_DIR})
+LINK_LIBRARIES(${PHYSFS_LIBRARY})
+
+IF(CMAKE_COMPILER_IS_GNUCC)
+  ADD_DEFINITIONS(-g -O2 -Wall -Wextra)
+ENDIF(CMAKE_COMPILER_IS_GNUCC)
+
+IF(MSVC)
+  ADD_DEFINITIONS(-D_CRG_SECURE_NO_WARNINGS=1)
+ENDIF(MSVC)
+
+CHECK_INCLUDE_FILE(assert.h HAVE_ASSERT_H)
+IF(HAVE_ASSERT_H)
+    ADD_DEFINITIONS(-DHAVE_ASSERT_H=1)
+ENDIF(HAVE_ASSERT_H)
+
+FILE(GLOB_RECURSE UNISON_SOURCES RELATIVE ${UNISON_SOURCE_DIR} src/*.cpp src/*.c)
+
+ADD_LIBRARY(unison ${UNISON_SOURCES})
+
+IF(${PHYSFS_FOUND} STREQUAL "NO")
+  ADD_DEPENDENCIES(unison physfs-static)
+  SET(PHYSFS_FOUND "YES")
+ENDIF(${PHYSFS_FOUND} STREQUAL "NO")
+
+FIND_PACKAGE(Doxygen)
+IF(DOXYGEN_FOUND)
+    ADD_CUSTOM_TARGET(docs ${DOXYGEN_EXECUTABLE} COMMENT "Building documentation")
+ELSE(DOXYGEN_FOUND)
+    MESSAGE(STATUS "Doxygen not found. You won't be able to build documentation.")
+ENDIF(DOXYGEN_FOUND)
diff --git a/src/unison/Doxyfile b/src/unison/Doxyfile
new file mode 100644 (file)
index 0000000..efcf103
--- /dev/null
@@ -0,0 +1,1257 @@
+# Doxyfile 1.5.2
+
+# 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
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file that 
+# follow. The default is UTF-8 which is also the encoding used for all text before 
+# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into 
+# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of 
+# possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = Unison
+
+# 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.
+
+PROJECT_NUMBER         = 
+
+# 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       = 
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 
+# 4096 sub-directories (in 2 levels) under the output directory of each output 
+# format and will distribute the generated files over these directories. 
+# Enabling this option can be useful when feeding doxygen a huge amount of 
+# source files, where putting all generated files in the same directory would 
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# 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: 
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 
+# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, 
+# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, 
+# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, 
+# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE        = English
+
+# 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
+
+# This tag implements a quasi-intelligent brief description abbreviator 
+# that is used to form the text in various listings. Each string 
+# in this list, if found as the leading text of the brief description, will be 
+# stripped from the text and the result after processing the whole list, is 
+# used as the annotated text. Otherwise, the brief description is used as-is. 
+# If left blank, the following values are used ("$name" is automatically 
+# replaced with the name of the entity): "The $name class" "The $name widget" 
+# "The $name file" "is" "provides" "specifies" "contains" 
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       = 
+
+# 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        = YES
+
+# 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. The tag can be used to show relative paths in the file list. 
+# If left blank the directory from which doxygen is run is used as the 
+# path to strip.
+
+STRIP_FROM_PATH        = 
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 
+# the path mentioned in the documentation of a class, which tells 
+# the reader which header file to include in order to use a class. 
+# If left blank only the name of the header file containing the class 
+# definition is used. Otherwise one should specify the include paths that 
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_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 
+# explicit @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 
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce 
+# a new page for each member. If set to NO, the documentation of a member will 
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = 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               = 8
+
+# 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  = NO
+
+# 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
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to 
+# include (a tag file for) the STL sources as input, then you should 
+# set this tag to YES in order to let doxygen match functions declarations and 
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. 
+# func(std::string) {}). This also make the inheritance and collaboration 
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# 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
+
+# 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  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local 
+# methods, which are defined in the implementation section but not in 
+# the interface are included in the documentation. 
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = 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 
+# and Mac 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
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
+# brief documentation of file, namespace and class members alphabetically 
+# by member name. If set to NO (the default) the members will appear in 
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 
+# sorted by fully-qualified names, including namespaces. If set to 
+# NO (the default), the class list will be sorted only by class name, 
+# not including the namespace part. 
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the 
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# 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
+
+# If the sources in your project are distributed over multiple directories 
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy 
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that 
+# doxygen should invoke to get the current version for each file (typically from the 
+# version control system). Doxygen will invoke the program by executing (via 
+# popen()) the command <command> <input-file>, where <command> is the value of 
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file 
+# provided by doxygen. Whatever the program writes to standard output 
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    = 
+
+#---------------------------------------------------------------------------
+# 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
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for 
+# functions that are documented, but have no documentation for their parameters 
+# or return value. If set to NO (the default) doxygen will only warn about 
+# wrong or incomplete parameter documentation, but not about the absence of 
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# 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. Optionally the format may contain 
+# $version, which will be replaced by the version of the file (if it could 
+# be obtained via FILE_VERSION_FILTER)
+
+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                  = include/unison/video include/unison/video/backend
+
+# This tag can be used to specify the character encoding of the source files that 
+# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default 
+# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. 
+# See http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# 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 *.m *.mm *.py
+
+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. Note that the wildcards are matched 
+# against the file with absolute path, so to exclude all test directories 
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       = 
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names 
+# (namespaces, classes, functions, etc.) that should be excluded from the output. 
+# The symbol name can be a fully qualified name, a word, or if the wildcard * is used, 
+# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        = 
+
+# 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.  If FILTER_PATTERNS is specified, this tag will be 
+# ignored.
+
+INPUT_FILTER           = 
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 
+# basis.  Doxygen will compare the file name with each pattern and apply the 
+# filter if there is a match.  The filters are a list of the form: 
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER 
+# is applied to all files.
+
+FILTER_PATTERNS        = 
+
+# 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. 
+# Note: To get rid of all source code in the generated output, make sure also 
+# VERBATIM_HEADERS is set to NO.
+
+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 REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.  Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code 
+# will point to the HTML generated by the htags(1) tool instead of doxygen 
+# built-in source browser. The htags tool is part of GNU's global source 
+# tagging system (see http://www.gnu.org/software/global/global.html). You 
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# 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            = docs
+
+# 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. Note that doxygen will try to copy 
+# the style sheet file to the HTML output directory, so don't put your own 
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+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 directory.
+
+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         = NO
+
+# 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 optimized 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 assignments. 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           = NO
+
+# 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              = NO
+
+#---------------------------------------------------------------------------
+# 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.
+
+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                = 
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will 
+# dump the program listings (including syntax highlighting 
+# and cross-referencing information) to the XML output. Note that 
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# 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        = NO
+
+# 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_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# 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. To prevent a macro definition from being 
+# undefined via #undef or recursively expanded use the := operator 
+# instead of the = operator.
+
+PREDEFINED             = 
+
+# 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::additions 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 superseded 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         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc 
+# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to 
+# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to 
+# specify the directory where the mscgen tool resides. If left empty the tool is assumed to 
+# be found in the default search path.
+
+MSCGEN_PATH            = 
+
+# 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            = YES
+
+# 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    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
+# collaboration diagrams in a style similar 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          = YES
+
+# 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 CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will 
+# generate a caller 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 caller graphs for selected 
+# functions only using the \callergraph command.
+
+CALLER_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
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES 
+# then doxygen will show the dependencies a directory has on other directories 
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = 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 in 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_MAX_NODES tag can be used to set the maximum number of 
+# nodes that will be shown in the graph. If the number of nodes in a graph 
+# becomes larger than this value, doxygen will truncate the graph, which is 
+# visualized by representing a node as a red box. Note that doxygen will always 
+# show the root nodes and its direct children regardless of this setting.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 
+# background. This is disabled by default, which results in a white background. 
+# Warning: Depending on the platform used, enabling this option may lead to 
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to 
+# read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output 
+# files in one run (i.e. multiple -o and -T options on the command line). This 
+# makes dot run faster, but since only newer versions of dot (>1.8.10) 
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# 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::additions 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
diff --git a/src/unison/LICENSE_1_0.txt b/src/unison/LICENSE_1_0.txt
new file mode 100644 (file)
index 0000000..36b7cd9
--- /dev/null
@@ -0,0 +1,23 @@
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/src/unison/include/unison/vfs/FileSystem.hpp b/src/unison/include/unison/vfs/FileSystem.hpp
new file mode 100644 (file)
index 0000000..40286a2
--- /dev/null
@@ -0,0 +1,53 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef UNISON_VFS_FILE_SYSTEM_HPP
+#define UNISON_VFS_FILE_SYSTEM_HPP
+
+#include <string>
+#include <vector>
+
+namespace Unison
+{
+   namespace VFS
+   {
+      class FileSystem
+      {
+         public:
+            static FileSystem &get()
+            {
+               static FileSystem vfs;
+               return vfs;
+            }
+
+            void follow_sym_links(bool follow);
+
+            std::string get_dir_sep();
+            std::string get_base_dir();
+            std::string get_user_dir();
+
+            std::string get_write_dir();
+            void set_write_dir(const std::string &write_dir);
+
+            void mount(const std::string &path, const std::string &mount_point = "/", bool append = false);
+            void umount(const std::string &path);
+            std::vector<std::string> get_search_path();
+            std::string get_mount_point(const std::string &path);
+
+            void mkdir(const std::string &dir);
+            void rm(const std::string &filename);
+            std::vector<std::string> ls(const std::string &path);
+            bool exists(const std::string &filename);
+            bool is_dir(const std::string &filename);
+
+            std::string get_real_dir(const std::string &filename);
+         private:
+            FileSystem();
+            ~FileSystem();
+      };
+   }
+}
+
+#endif
diff --git a/src/unison/include/unison/vfs/sdl/Utils.hpp b/src/unison/include/unison/vfs/sdl/Utils.hpp
new file mode 100644 (file)
index 0000000..be5b3c8
--- /dev/null
@@ -0,0 +1,27 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef UNISON_VFS_SDL_UTILS_HPP
+#define UNISON_VFS_SDL_UTILS_HPP
+
+#include <string>
+
+#include "SDL.h"
+
+namespace Unison
+{
+   namespace VFS
+   {
+      namespace SDL
+      {
+         struct Utils
+         {
+            static SDL_RWops *open_physfs_in(const std::string &filename);
+         };
+      }
+   }
+}
+
+#endif
diff --git a/src/unison/include/unison/vfs/stream.hpp b/src/unison/include/unison/vfs/stream.hpp
new file mode 100644 (file)
index 0000000..4212563
--- /dev/null
@@ -0,0 +1,31 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef UNISON_VFS_STREAM_HPP
+#define UNISON_VFS_STREAM_HPP
+
+#include <iostream>
+
+namespace Unison
+{
+   namespace VFS
+   {
+      class istream : public std::istream
+      {
+         public:
+            istream(const std::string &filename);
+            ~istream();
+      };
+
+      class ostream : public std::ostream
+      {
+         public:
+            ostream(const std::string &filename);
+            ~ostream();
+      };
+   }
+}
+
+#endif
diff --git a/src/unison/include/unison/video/Blittable.hpp b/src/unison/include/unison/video/Blittable.hpp
new file mode 100644 (file)
index 0000000..d8febe3
--- /dev/null
@@ -0,0 +1,107 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef UNISON_VIDEO_BLITTABLE_HPP
+#define UNISON_VIDEO_BLITTABLE_HPP
+
+#include <unison/video/Coord.hpp>
+#include <unison/video/Rect.hpp>
+#include <unison/video/RenderOptions.hpp>
+
+namespace Unison
+{
+   namespace Video
+   {
+      class Surface;
+      class SurfaceSection;
+      class Texture;
+      class TextureSection;
+      class DisplayList;
+      class Blittable
+      {
+         public:
+            virtual ~Blittable();
+
+            /// Does a surface blit
+            /// \param[in] src The source surface
+            /// \param[in] dst_pos The position to blit to
+            /// \param[in] src_rect The part of the source surface to blit from
+            /// \param[in] options Extra blit options
+            virtual void blit(const Surface &src, const Point &dst_pos = Point(), const Rect &src_rect = Rect(), const RenderOptions &options = RenderOptions()) = 0;
+
+            /// Does a texture blit
+            /// \param[in] src The source texture
+            /// \param[in] dst_pos The position to blit to
+            /// \param[in] src_rect The part of the source texture to blit from
+            /// \param[in] options Extra blit options
+            virtual void blit(const Texture &src, const Point &dst_pos = Point(), const Rect &src_rect = Rect(), const RenderOptions &options = RenderOptions()) = 0;
+            /// Does a surface section blit
+            /// \param[in] section The section to blit
+            /// \param[in] dst_pos The position to blit to
+            /// \param[in] options Extra blit options
+            void blit_section(const SurfaceSection &section, const Point &dst_pos = Point(), const RenderOptions &options = RenderOptions());
+
+            /// Does a texture section blit
+            /// \param[in] section The section to blit
+            /// \param[in] dst_pos The position to blit to
+            /// \param[in] options Extra blit options
+            void blit_section(const TextureSection &section, const Point &dst_pos = Point(), const RenderOptions &options = RenderOptions());
+
+            /// \param[in] color The color
+            /// \param[in] rect The portion to fill
+            virtual void fill(const Color &color, const Rect &rect = Rect()) = 0;
+
+            /// \param[in] color The color
+            /// \param[in] rect The portion to fill
+            virtual void fill_blend(const Color &color, const Rect &rect = Rect()) = 0;
+
+            /// Draw the requests in the display list
+            /// \param[in] list The display list
+            void draw(const DisplayList &list);
+      };
+
+      /// A section of a blittable
+      class BlittableSection : public Blittable
+      {
+         public:
+            /// The image
+            Blittable &image;
+
+            /// The clip rectangle
+            Rect clip_rect;
+
+            /// Create a section from an image and a rectangle
+            /// \param[in] image The image
+            /// \param[in] rect The clip rectangle
+            BlittableSection(Blittable &image, const Rect &clip_rect = Rect());
+
+            /// Does a clipped blit to the image
+            /// \param[in] src The source surface
+            /// \param[in] dst_pos The position to blit to
+            /// \param[in] src_rect The part of the blit source to blit from
+            /// \param[in] options Extra blit options
+            void blit(const Surface &src, const Point &dst_pos = Point(), const Rect &src_rect = Rect(), const RenderOptions &options = RenderOptions());
+
+            /// Does a clipped blit to the image
+            /// \param[in] src The source texture
+            /// \param[in] dst_pos The position to blit to
+            /// \param[in] src_rect The part of the blit source to blit from
+            /// \param[in] options Extra blit options
+            void blit(const Texture &src, const Point &dst_pos = Point(), const Rect &src_rect = Rect(), const RenderOptions &options = RenderOptions());
+
+            /// Fills the camera viewable portion with a color
+            /// \param[in] color The color
+            /// \param[in] rect The portion to fill
+            void fill(const Color &color, const Rect &rect = Rect());
+
+            /// Fills the camera viewable portion with a color using alpha blending
+            /// \param[in] color The color
+            /// \param[in] rect The portion to fill
+            void fill_blend(const Color &color, const Rect &rect = Rect());
+      };
+   }
+}
+
+#endif
diff --git a/src/unison/include/unison/video/Blitters.hpp b/src/unison/include/unison/video/Blitters.hpp
new file mode 100644 (file)
index 0000000..d201cb9
--- /dev/null
@@ -0,0 +1,83 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef UNISON_VIDEO_BLITTERS_HPP
+#define UNISON_VIDEO_BLITTERS_HPP
+
+#include <unison/video/Coord.hpp>
+#include <unison/video/RenderOptions.hpp>
+
+namespace Unison
+{
+   namespace Video
+   {
+      class Rect;
+      class Surface;
+
+      struct Blitters
+      {
+         static void blit_upper(const Surface &src, Rect src_rect, Surface &dst, Point dst_pos, void (*blit_lower)(const Surface &, const Rect &, Surface &, const Point &));
+
+         static void blit_lower_none(const Surface &src, const Rect &src_rect, Surface &dst, const Point &dst_pos);
+
+         static void blit_lower_mask(const Surface &src, const Rect &src_rect, Surface &dst, const Point &dst_pos);
+
+         static void blit_lower_alpha(const Surface &src, const Rect &src_rect, Surface &dst, const Point &dst_pos);
+
+         static void blit_lower_add(const Surface &src, const Rect &src_rect, Surface &dst, const Point &dst_pos);
+
+         static void blit_lower_mod(const Surface &src, const Rect &src_rect, Surface &dst, const Point &dst_pos);
+
+         static void blit_blend_none(const Surface &src, const Rect &src_rect, Surface &dst, const Point &dst_pos)
+         {
+            blit_upper(src, src_rect, dst, dst_pos, blit_lower_none);
+         }
+
+         static void blit_blend_mask(const Surface &src, const Rect &src_rect, Surface &dst, const Point &dst_pos)
+         {
+            blit_upper(src, src_rect, dst, dst_pos, blit_lower_mask);
+         }
+
+         static void blit_blend_alpha(const Surface &src, const Rect &src_rect, Surface &dst, const Point &dst_pos)
+         {
+            blit_upper(src, src_rect, dst, dst_pos, blit_lower_alpha);
+         }
+
+         static void blit_blend_add(const Surface &src, const Rect &src_rect, Surface &dst, const Point &dst_pos)
+         {
+            blit_upper(src, src_rect, dst, dst_pos, blit_lower_add);
+         }
+
+         static void blit_blend_mod(const Surface &src, const Rect &src_rect, Surface &dst, const Point &dst_pos)
+         {
+            blit_upper(src, src_rect, dst, dst_pos, blit_lower_mod);
+         }
+
+         static void blit_blend(const Surface &src, const Rect &src_rect, Surface &dst, const Point &dst_pos, BlendMode blend)
+         {
+            switch(blend)
+            {
+               case BLEND_NONE:
+                  blit_blend_none(src, src_rect, dst, dst_pos);
+                  break;
+               case BLEND_MASK:
+                  blit_blend_mask(src, src_rect, dst, dst_pos);
+                  break;
+               case BLEND_ALPHA:
+                  blit_blend_alpha(src, src_rect, dst, dst_pos);
+                  break;
+               case BLEND_ADD:
+                  blit_blend_add(src, src_rect, dst, dst_pos);
+                  break;
+               case BLEND_MOD:
+                  blit_blend_mod(src, src_rect, dst, dst_pos);
+                  break;
+            }
+         }
+      };
+   }
+}
+
+#endif
diff --git a/src/unison/include/unison/video/Color.hpp b/src/unison/include/unison/video/Color.hpp
new file mode 100644 (file)
index 0000000..6f9ee00
--- /dev/null
@@ -0,0 +1,111 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef UNISON_VIDEO_COLOR_HPP
+#define UNISON_VIDEO_COLOR_HPP
+
+//#include "SDL_stdinc.h"
+
+namespace Unison
+{
+   namespace Video
+   {
+      /// A RGBA color
+      class Color
+      {
+         public:
+            /// The red component (0x00 to 0xff)
+            unsigned char red;
+
+            /// The green component (0x00 to 0xff)
+            unsigned char green;
+
+            /// The blue component (0x00 to 0xff)
+            unsigned char blue;
+
+            /// The alpha component (0x00 to 0xff)
+            unsigned char alpha;
+
+            /// Default constructor (transparent black)
+            Color() :
+               red(),
+               green(),
+               blue(),
+               alpha()
+            {
+            }
+
+            /// Create a color from the given values
+            /// \param[in] red The red component (0x00 to 0xff)
+            /// \param[in] green The red component (0x00 to 0xff)
+            /// \param[in] blue The red component (0x00 to 0xff)
+            /// \param[in] alpha The red component (0x00 to 0xff)
+            Color(unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha = 0xff) :
+               red(red),
+               green(green),
+               blue(blue),
+               alpha(alpha)
+            {
+            }
+
+            /// Equality operator
+            /// \param[in] rhs The color to test
+            /// \return Whether the colors are equal
+            bool operator == (const Color &rhs) const
+            {
+               return red == rhs.red && green == rhs.green && blue == rhs.blue && alpha == rhs.alpha;
+            }
+
+            /// Equality operator
+            /// \param[in] rhs The color to test
+            /// \return Whether the colors are not equal
+            bool operator != (const Color &rhs) const
+            {
+               return !(*this == rhs);
+            }
+
+            /// Less than operator
+            /// \param[in] rhs The color to test
+            /// \return Whether the color's grayscale value is less than the tested color
+            bool operator < (const Color &rhs) const
+            {
+               return grayscale() < rhs.grayscale();
+            }
+
+            /// Calculate the grayscale value of the color
+            /// \return The grayscale value (30% red, 59% green, 11% blue)
+            unsigned char grayscale() const
+            {
+               return (red * 30 + green * 59 + blue * 11) / 100;
+            }
+
+            /// Opaque black (red = 0x00, green = 0x00, blue = 0x00)
+            static const Color BLACK;
+
+            /// Opaque red (red = 0xff, green = 0x00, blue = 0x00)
+            static const Color RED;
+
+            /// Opaque green (red = 0x00, green = 0xff, blue = 0x00)
+            static const Color GREEN;
+
+            /// Opaque blue (red = 0x00, green = 0x00, blue = 0xff)
+            static const Color BLUE;
+
+            /// Opaque cyan (red = 0x00, green = 0xff, blue = 0xff)
+            static const Color CYAN;
+
+            /// Opaque magenta (red = 0xff, green = 0x00, blue = 0xff)
+            static const Color MAGENTA;
+
+            /// Opaque yellow (red = 0xff, green = 0xff, blue = 0x00)
+            static const Color YELLOW;
+
+            /// Opaque white (red = 0xff, green = 0xff, blue = 0xff)
+            static const Color WHITE;
+      };
+   }
+}
+
+#endif
diff --git a/src/unison/include/unison/video/Coord.hpp b/src/unison/include/unison/video/Coord.hpp
new file mode 100644 (file)
index 0000000..576502a
--- /dev/null
@@ -0,0 +1,275 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef UNISON_VIDEO_COORD_HPP
+#define UNISON_VIDEO_COORD_HPP
+
+namespace Unison
+{
+   namespace Video
+   {
+      /// A 2 dimensional quantity in rectangular space
+      template<typename T> class Coord
+      {
+         public:
+            /// The horizontal value
+            T x;
+
+            /// The vertical value
+            T y;
+
+            /// Default constructor (0, 0)
+            Coord()
+             : x(),
+               y()
+            {
+            }
+
+            /// Create a coordinate from the given values
+            /// \param[in] x The horizontal value
+            /// \param[in] y The vertical value
+            Coord(T x, T y)
+             : x(x),
+               y(y)
+            {
+            }
+
+            /// Copy constructor
+            /// \param[in] rhs The source coordinate
+            template<typename V> Coord(const Coord<V> &rhs)
+             : x(rhs.x),
+               y(rhs.y)
+            {
+            }
+
+            /// Assignment operator
+            /// \param[in] rhs The source color
+            template<typename V> Coord<T> &operator =(const Coord<V> &rhs)
+            {
+               x = rhs.x;
+               y = rhs.y;
+               return *this;
+            }
+
+            /// Equality operator
+            /// \param[in] rhs The coordinate to test
+            /// \return Whether the coordinates are equal
+            template<typename V> bool operator ==(const Coord<V> &rhs) const
+            {
+               return x == rhs.x && y == rhs.y;
+            }
+
+            /// Equality operator
+            /// \param[in] rhs The coordinate to test
+            /// \return Whether the coordinates are not equal
+            template<typename V> bool operator !=(const Coord<V> &rhs) const
+            {
+               return !(*this == rhs);
+            }
+
+            /// Add two coordinates and assign to the left operand
+            /// \param[in] rhs The right operand
+            /// \return The resultant coordinate
+            template<typename V> Coord<T> &operator +=(const Coord<V> &rhs)
+            {
+               x += rhs.x;
+               y += rhs.y;
+               return *this;
+            }
+
+            /// Subtract two coordinates and assign to the left operand
+            /// \param[in] rhs The right operand
+            /// \return The resultant coordinate
+            template<typename V> Coord<T> &operator -=(const Coord<V> &rhs)
+            {
+               x -= rhs.x;
+               y -= rhs.y;
+               return *this;
+            }
+
+            /// Multiply two coordinates and assign to the left operand
+            /// \param[in] rhs The right operand
+            /// \return The resultant coordinate
+            template<typename V> Coord<T> &operator *=(const Coord<V> &rhs)
+            {
+               x *= rhs.x;
+               y *= rhs.y;
+               return *this;
+            }
+
+            /// Multiply two coordinates and assign to the left operand
+            /// \param[in] rhs The right operand
+            /// \return The resultant coordinate
+            template<typename V> Coord<T> &operator /=(const Coord<V> &rhs)
+            {
+               x /= rhs.x;
+               y /= rhs.y;
+               return *this;
+            }
+
+            /// Add a coordinate with a scalar and assign to the left operand
+            /// \param[in] rhs The right operand
+            /// \return The resultant coordinate
+            template<typename V> Coord<T> &operator +=(const V &rhs)
+            {
+               x += rhs;
+               y += rhs;
+               return *this;
+            }
+
+            /// Subtract a coordinate with a scalar and assign to the left operand
+            /// \param[in] rhs The right operand
+            /// \return The resultant coordinate
+            template<typename V> Coord<T> &operator -=(const V &rhs)
+            {
+               x -= rhs;
+               y -= rhs;
+               return *this;
+            }
+
+            /// Multiply a coordinate with a scalar and assign to the left operand
+            /// \param[in] rhs The right operand
+            /// \return The resultant coordinate
+            template<typename V> Coord<T> &operator *=(const V &rhs)
+            {
+               x *= rhs;
+               y *= rhs;
+               return *this;
+            }
+
+            /// Divide a coordinate with a scalar and assign to the left operand
+            /// \param[in] rhs The right operand
+            /// \return The resultant coordinate
+            template<typename V> Coord<T> &operator /=(const V &rhs)
+            {
+               x /= rhs;
+               y /= rhs;
+               return *this;
+            }
+
+            /*T length()
+            {
+               double sq = x*x + y*y;
+               return T(sqrt(sq) + 0.5);
+            }*/
+      };
+
+      /// Add two coordinates
+      /// \param[in] lhs The left operand
+      /// \param[in] rhs The right operand
+      /// \return The resultant coordinate
+      template<typename T, typename V> const Coord<T> operator +(const Coord<T> &lhs, const Coord<V> &rhs)
+      {
+         return Coord<T>(lhs) += rhs;
+      }
+
+      /// Subtract two coordinates
+      /// \param[in] lhs The left operand
+      /// \param[in] rhs The right operand
+      /// \return The resultant coordinate
+      template<typename T, typename V> const Coord<T> operator -(const Coord<T> &lhs, const Coord<V> &rhs)
+      {
+         return Coord<T>(lhs) -= rhs;
+      }
+
+      /// Multiply two coordinates
+      /// \param[in] lhs The left operand
+      /// \param[in] rhs The right operand
+      /// \return The resultant coordinate
+      template<typename T, typename V> const Coord<T> operator *(const Coord<T> &lhs, const Coord<V> &rhs)
+      {
+         return Coord<T>(lhs) *= rhs;
+      }
+
+      /// Divide two coordinates
+      /// \param[in] lhs The left operand
+      /// \param[in] rhs The right operand
+      /// \return The resultant coordinate
+      template<typename T, typename V> const Coord<T> operator /(const Coord<T> &lhs, const Coord<V> &rhs)
+      {
+         return Coord<T>(lhs) /= rhs;
+      }
+
+      /// Add a coordinate with a scalar
+      /// \param[in] lhs The left operand
+      /// \param[in] rhs The right operand
+      /// \return The resultant coordinate
+      template<typename T, typename V> const Coord<T> operator +(const Coord<T> &lhs, const V &rhs)
+      {
+         return Coord<T>(lhs) += rhs;
+      }
+
+      /// Subtract a coordinate with a scalar
+      /// \param[in] lhs The left operand
+      /// \param[in] rhs The right operand
+      /// \return The resultant coordinate
+      template<typename T, typename V> const Coord<T> operator -(const Coord<T> &lhs, const V &rhs)
+      {
+         return Coord<T>(lhs) -= rhs;
+      }
+
+      /// Multiply a coordinate with a scalar
+      /// \param[in] lhs The left operand
+      /// \param[in] rhs The right operand
+      /// \return The resultant coordinate
+      template<typename T, typename V> const Coord<T> operator *(const Coord<T> &lhs, const V &rhs)
+      {
+         return Coord<T>(lhs) *= rhs;
+      }
+
+      /// Divide a coordinate with a scalar
+      /// \param[in] lhs The left operand
+      /// \param[in] rhs The right operand
+      /// \return The resultant coordinate
+      template<typename T, typename V> const Coord<T> operator /(const Coord<T> &lhs, const V &rhs)
+      {
+         return Coord<T>(lhs) /= rhs;
+      }
+
+      /// Add a coordinate with a scalar
+      /// \param[in] lhs The left operand
+      /// \param[in] rhs The right operand
+      /// \return The resultant coordinate
+      template<typename V, typename T> const Coord<T> operator +(const V &lhs, const Coord<T> &rhs)
+      {
+         return Coord<T>(rhs) += lhs;
+      }
+
+      /// Subtract a coordinate with a scalar
+      /// \param[in] lhs The left operand
+      /// \param[in] rhs The right operand
+      /// \return The resultant coordinate
+      template<typename V, typename T> const Coord<T> operator -(const V &lhs, const Coord<T> &rhs)
+      {
+         return Coord<T>(rhs) -= lhs;
+      }
+
+      /// Multiply a coordinate with a scalar
+      /// \param[in] lhs The left operand
+      /// \param[in] rhs The right operand
+      /// \return The resultant coordinate
+      template<typename V, typename T> const Coord<T> operator *(const V &lhs, const Coord<T> &rhs)
+      {
+         return Coord<T>(rhs) *= lhs;
+      }
+
+      /// Divide a coordinate with a scalar
+      /// \param[in] lhs The left operand
+      /// \param[in] rhs The right operand
+      /// \return The resultant coordinate
+      template<typename V, typename T> const Coord<T> operator /(const V &lhs, const Coord<T> &rhs)
+      {
+         return Coord<T>(rhs) /= lhs;
+      }
+
+      /// A point in 2-dimensional space
+      typedef Coord<int> Point;
+
+      /// A 2-dimensional area
+      typedef Coord<unsigned int> Area;
+   }
+}
+
+#endif
diff --git a/src/unison/include/unison/video/DisplayList.hpp b/src/unison/include/unison/video/DisplayList.hpp
new file mode 100644 (file)
index 0000000..1da6a03
--- /dev/null
@@ -0,0 +1,240 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef UNISON_VIDEO_DISPLAY_LIST_HPP
+#define UNISON_VIDEO_DISPLAY_LIST_HPP
+
+#include <unison/video/Blittable.hpp>
+#include <unison/video/RenderOptions.hpp>
+#include <unison/video/Surface.hpp>
+#include <unison/video/Texture.hpp>
+
+#include <string>
+#include <vector>
+#include <map>
+
+namespace Unison
+{
+   namespace Video
+   {
+      class DisplayList : public Blittable
+      {
+         public:
+            DisplayList() :
+               requests()
+            {
+            }
+
+            DisplayList(const std::map<int, DisplayList> &layers) :
+               requests(std::for_each(layers.begin(), layers.end(), Collator()).requests)
+            {
+               std::for_each(requests.begin(), requests.end(), std::mem_fun(&Unison::Video::DisplayList::Request::ref));
+            }
+
+            DisplayList(const DisplayList &rhs) :
+               Blittable(),
+               requests(rhs.requests)
+            {
+               std::for_each(requests.begin(), requests.end(), std::mem_fun(&Unison::Video::DisplayList::Request::ref));
+            }
+
+            ~DisplayList()
+            {
+               std::for_each(requests.begin(), requests.end(), std::mem_fun(&Unison::Video::DisplayList::Request::unref));
+            }
+
+            DisplayList &operator = (const DisplayList &rhs)
+            {
+               std::for_each(rhs.requests.begin(), rhs.requests.end(), std::mem_fun(&Unison::Video::DisplayList::Request::ref));
+               std::for_each(requests.begin(), requests.end(), std::mem_fun(&Unison::Video::DisplayList::Request::unref));
+               requests = rhs.requests;
+               return *this;
+            }
+
+            /// Add a request to do a surface-to-image blit
+            /// \param[in] src The source surface
+            /// \param[in] dst_pos The position to blit to
+            /// \param[in] src_rect The part of the source surface to blit from
+            /// \param[in] options Extra blit options
+            /// \param[in] layer The drawing layer to sort by
+            void blit(const Surface &src, const Point &dst_pos = Point(), const Rect &src_rect = Rect(), const RenderOptions &options = RenderOptions())
+            {
+               add_request(new SurfaceBlitRequest(src, dst_pos, src_rect, options));
+            }
+
+            /// Add a request to do a texture-to-image blit
+            /// \param[in] src The source texture
+            /// \param[in] dst_pos The position to blit to
+            /// \param[in] src_rect The part of the source texture to blit from
+            /// \param[in] options Extra blit options
+            /// \param[in] layer The drawing layer to sort by
+            void blit(const Texture &src, const Point &dst_pos = Point(), const Rect &src_rect = Rect(), const RenderOptions &options = RenderOptions())
+            {
+               add_request(new TextureBlitRequest(src, dst_pos, src_rect, options));
+            }
+
+            /// Add a request to fill a portion of the image
+            /// \param[in] color The color
+            /// \param[in] rect The portion to fill
+            /// \param[in] layer The drawing layer to sort by
+            void fill(const Color &color, const Rect &rect = Rect())
+            {
+               add_request(new FillRequest(color, rect));
+            }
+
+            /// Add a request to blended fill a portion of the image
+            /// \param[in] color The color
+            /// \param[in] rect The portion to fill
+            /// \param[in] layer The drawing layer to sort by
+            void fill_blend(const Color &color, const Rect &rect = Rect())
+            {
+               add_request(new BlendedFillRequest(color, rect));
+            }
+
+            /// Draw requests in display list onto blittable
+            /// \param[in] dst The destination blittable
+            void draw(Blittable *dst) const
+            {
+               std::for_each(requests.begin(), requests.end(), std::bind2nd(std::mem_fun(&Request::do_request), dst));
+            }
+
+            void clear()
+            {
+               requests.clear();
+            }
+
+            class Request
+            {
+               public:
+                  Request() :
+                     refcount(1)
+                  {
+                  }
+
+                  virtual ~Request()
+                  {
+                  }
+
+                  virtual void do_request(Blittable *dst) const = 0;
+
+                  void ref()
+                  {
+                     refcount++;
+                  }
+
+                  void unref()
+                  {
+                     assert(refcount > 0);
+                     refcount--;
+                     if(refcount == 0)
+                     {
+                        delete this;
+                     }
+                  }
+               private:
+                  int refcount;
+            };
+
+            void add_request(Request *request)
+            {
+               requests.push_back(request);
+            }
+         private:
+            class Collator
+            {
+               public:
+                  void operator () (std::pair<int, DisplayList> pair)
+                  {
+                     requests.insert(requests.end(), pair.second.requests.begin(), pair.second.requests.end());
+                  }
+                  std::vector<Request *> requests;
+            };
+
+            class SurfaceBlitRequest : public Request
+            {
+               public:
+                  SurfaceBlitRequest(const Surface &src, const Point &dst_pos, const Rect &src_rect, const RenderOptions &options)
+                   : src(src),
+                     dst_pos(dst_pos),
+                     src_rect(src_rect),
+                     options(options)
+                  {
+                  }
+
+                  void do_request(Blittable *dst) const
+                  {
+                     dst->blit(src, dst_pos, src_rect, options);
+                  }
+               private:
+                  Surface src;
+                  Point dst_pos;
+                  Rect src_rect;
+                  RenderOptions options;
+            };
+
+            class TextureBlitRequest : public Request
+            {
+               public:
+                  TextureBlitRequest(const Texture &src, const Point &dst_pos, const Rect &src_rect, const RenderOptions &options)
+                   : src(src),
+                     dst_pos(dst_pos),
+                     src_rect(src_rect),
+                     options(options)
+                  {
+                  }
+
+                  void do_request(Blittable *dst) const
+                  {
+                     dst->blit(src, dst_pos, src_rect, options);
+                  }
+               private:
+                  Texture src;
+                  Point dst_pos;
+                  Rect src_rect;
+                  RenderOptions options;
+            };
+
+            class FillRequest : public Request
+            {
+               public:
+                  FillRequest(const Color &color, const Rect &rect)
+                   : color(color),
+                     rect(rect)
+                  {
+                  }
+
+                  void do_request(Blittable *dst) const
+                  {
+                     dst->fill(color, rect);
+                  }
+               private:
+                  Color color;
+                  Rect rect;
+            };
+
+            class BlendedFillRequest : public Request
+            {
+               public:
+                  BlendedFillRequest(const Color &color, const Rect &rect)
+                   : color(color),
+                     rect(rect)
+                  {
+                  }
+
+                  void do_request(Blittable *dst) const
+                  {
+                     dst->fill_blend(color, rect);
+                  }
+               private:
+                  Color color;
+                  Rect rect;
+            };
+
+            std::vector<Request *> requests;
+      };
+   }
+}
+
+#endif
diff --git a/src/unison/include/unison/video/Rect.hpp b/src/unison/include/unison/video/Rect.hpp
new file mode 100644 (file)
index 0000000..7fee65f
--- /dev/null
@@ -0,0 +1,186 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef UNISON_VIDEO_RECT_HPP
+#define UNISON_VIDEO_RECT_HPP
+
+#include <algorithm>
+
+#include <unison/video/Coord.hpp>
+
+#include "SDL.h"
+
+namespace Unison
+{
+   namespace Video
+   {
+      /// Represents a rectangular area
+      class Rect
+      {
+         public:
+            /// The position of the rectangle
+            Point pos;
+
+            /// The size of the rectangle
+            Area size;
+
+            /// Default constructor
+            Rect() :
+               pos(),
+               size(),
+               rect()
+            {
+            }
+
+            /// Create a rectangle from the given coordinates
+            /// \param[in] pos The position of the rectangle
+            /// \param[in] size The size of the rectangle
+            Rect(const Point &pos, const Area &size) :
+               pos(pos),
+               size(size),
+               rect()
+            {
+            }
+
+            /// Create a rectangle from the given values
+            /// \param[in] x The x-position of the rectangle
+            /// \param[in] y The y-position of the rectangle
+            /// \param[in] w The width of the rectangle
+            /// \param[in] h The height of the rectangle
+            Rect(int x, int y, int w, int h) :
+               pos(x, y),
+               size(w, h),
+               rect()
+            {
+            }
+
+            /// Equality operator
+            /// \param[in] rhs The rectangle to test
+            /// \return Whether the rectangles are equal
+            bool operator == (const Rect &rhs) const
+            {
+               return pos == rhs.pos && size == rhs.size;
+            }
+
+            /// Equality operator
+            /// \param[in] rhs The rectangle to test
+            /// \return Whether the rectangles are not equal
+            bool operator != (const Rect &rhs) const
+            {
+               return !(*this == rhs);
+            }
+
+            /// Get the left edge of the rectnagle
+            /// \return The location of the left edge
+            int get_left() const
+            {
+               return pos.x;
+            }
+
+            /// Get the top edge of the rectnagle
+            /// \return The location of the top edge
+            int get_top() const
+            {
+               return pos.y;
+            }
+
+            /// Get the right edge of the rectnagle
+            /// \return The location of the right edge
+            int get_right() const
+            {
+               return pos.x + size.x;
+            }
+
+            /// Get the bottom edge of the rectnagle
+            /// \return The location of the bottom edge
+            int get_bottom() const
+            {
+               return pos.y + size.y;
+            }
+
+            /// Calculate the overlap between the rectangles
+            /// \param[in] rhs The rectangle to check
+            /// \return The part of the rectangle that is overlapping
+            Rect get_overlap(const Rect &rhs)
+            {
+               if(*this == Rect())
+               {
+                  return rhs;
+               }
+               if(rhs == Rect())
+               {
+                  return *this;
+               }
+               Rect overlap;
+               if(get_left() < rhs.get_right())
+               {
+                  overlap.pos.x = std::max(get_left(), rhs.get_left());
+               }
+               else
+               {
+                  return Rect();
+               }
+               if(rhs.get_left() < get_right())
+               {
+                  overlap.size.x = std::min(rhs.get_right(), get_right()) - overlap.pos.x;
+               }
+               else
+               {
+                  return Rect();
+               }
+               if(get_top() < rhs.get_bottom())
+               {
+                  overlap.pos.y = std::max(get_top(), rhs.get_top());
+               }
+               else
+               {
+                  return Rect();
+               }
+               if(rhs.get_top() < get_bottom())
+               {
+                  overlap.size.y = std::min(rhs.get_bottom(), get_bottom()) - overlap.pos.y;
+               }
+               else
+               {
+                  return Rect();
+               }
+               return overlap;
+            }
+
+            /// Allow rectangles to be treated like SDL_Rect
+            /// \return The equavalent SDL_Rect
+            operator SDL_Rect () const
+            {
+               rect.x = pos.x;
+               rect.y = pos.y;
+               rect.w = size.x;
+               rect.h = size.y;
+               return rect;
+            }
+
+            /// Allow rectangles to be treated like SDL_Rect
+            /// \return The internal SDL_Rect
+            SDL_Rect *operator &() const
+            {
+               if(*this == Rect())
+               {
+                  return 0;
+               }
+               else
+               {
+                  rect.x = pos.x;
+                  rect.y = pos.y;
+                  rect.w = size.x;
+                  rect.h = size.y;
+                  return &rect;
+               }
+            }
+         private:
+            mutable SDL_Rect rect;
+      };
+   }
+}
+
+#endif
diff --git a/src/unison/include/unison/video/RenderOptions.hpp b/src/unison/include/unison/video/RenderOptions.hpp
new file mode 100644 (file)
index 0000000..ca496d1
--- /dev/null
@@ -0,0 +1,79 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef UNISON_VIDEO_RENDER_OPTIONS_HPP
+#define UNISON_VIDEO_RENDER_OPTIONS_HPP
+
+#include <unison/video/Color.hpp>
+
+namespace Unison
+{
+   namespace Video
+   {
+      /// The color blending modes
+      enum BlendMode
+      {
+         BLEND_NONE,
+         BLEND_MASK,
+         BLEND_ALPHA,
+         BLEND_ADD,
+         BLEND_MOD
+      };
+
+      /// Extra rendering options
+      class RenderOptions
+      {
+         public:
+            /// The additional color value used (alpha is ignored)
+            Color color;
+
+            /// The additional alpha value used
+            unsigned char alpha;
+
+            /// The blend mode used
+            BlendMode blend;
+
+            /// Flip rendering horizontally
+            bool h_flip;
+
+            /// Flip rendering vertically
+            bool v_flip;
+
+            /// Default constructor
+            RenderOptions() :
+               color(Color::WHITE),
+               alpha(0xff),
+               blend(BLEND_ALPHA),
+               h_flip(false),
+               v_flip(false)
+            {
+            }
+
+            /// Create a set of render options with the given data
+            /// \param[in] color The color modulation (alpha ignored)
+            RenderOptions(const Color &color) :
+               color(color),
+               alpha(0xff),
+               blend(BLEND_ALPHA),
+               h_flip(false),
+               v_flip(false)
+            {
+            }
+
+            /// Create a set of render options with the given data
+            /// \param[in] blend The blend mode
+            RenderOptions(BlendMode blend) :
+               color(Color::WHITE),
+               alpha(0xff),
+               blend(blend),
+               h_flip(false),
+               v_flip(false)
+            {
+            }
+      };
+   }
+}
+
+#endif
diff --git a/src/unison/include/unison/video/Renderers.hpp b/src/unison/include/unison/video/Renderers.hpp
new file mode 100644 (file)
index 0000000..adb0821
--- /dev/null
@@ -0,0 +1,57 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef UNISON_VIDEO_RENDERERS_HPP
+#define UNISON_VIDEO_RENDERERS_HPP
+
+#include <string>
+#include <vector>
+
+namespace Unison
+{
+   namespace Video
+   {
+      namespace Backend
+      {
+         class Renderer;
+      }
+      /// Manages renderers
+      class Renderers
+      {
+         public:
+            /// Initialize and retrieve singleton
+            static Renderers &get();
+
+            /// Set the backend renderer to use
+            /// \param[in] name The name of a renderer backend (can be "auto")
+            void set_renderer(const std::string &name);
+
+            /// Get the current backend renderer
+            /// \return The current backend renderer
+            Backend::Renderer &get_renderer();
+
+            /// Add a backend renderer
+            /// \param[in] renderer The backend renderer to add
+            void add_renderer(Backend::Renderer *renderer);
+         private:
+            /// The auto renderer backend
+            Backend::Renderer *auto_renderer;
+
+            /// The current renderer backend
+            Backend::Renderer *renderer;
+
+            /// The known backend renderers
+            std::vector<Backend::Renderer *> renderers;
+
+            /// Default constructor
+            Renderers();
+
+            /// Destructor
+            ~Renderers();
+      };
+   }
+}
+
+#endif
diff --git a/src/unison/include/unison/video/Surface.hpp b/src/unison/include/unison/video/Surface.hpp
new file mode 100644 (file)
index 0000000..074140a
--- /dev/null
@@ -0,0 +1,245 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef UNISON_VIDEO_SURFACE_HPP
+#define UNISON_VIDEO_SURFACE_HPP
+
+#include <unison/video/Blittable.hpp>
+#include <unison/video/RenderOptions.hpp>
+
+#include <string>
+#include <istream>
+#include <assert.h>
+
+namespace Unison
+{
+   namespace Video
+   {
+      class Color;
+      class Rect;
+      class Texture;
+      /// An image that is optimized for easy manipulation
+      class Surface : public Blittable
+      {
+         public:
+            /// Default constructor
+            Surface();
+
+            /// Create a Surface from an input stream
+            /// \param[in] src The input stream
+            Surface(std::istream &stream);
+
+            /// Create a Surface from an input stream
+            /// \param[in] src The input stream
+            /// \param[in] colorkey The colorkey used by the file
+            Surface(std::istream &stream, const Color &colorkey);
+
+            /// Opens image file indicated by filename
+            /// \param[in] filename The filename of the image file
+            Surface(const std::string &filename);
+
+            /// Opens image file indicated by filename and use the specified color key
+            /// \param[in] filename The filename of the image file
+            /// \param[in] colorkey The colorkey used by the file
+            Surface(const std::string &filename, const Color &colorkey);
+
+            /// Creates Surface of indicated dimensions
+            /// \param[in] size The size of the desired surface
+            Surface(const Area &size);
+
+            /// Copy constructor
+            /// \param[in] rhs The source surface
+            Surface(const Surface &rhs);
+
+            /// Destructor
+            ~Surface();
+
+            /// Assignment operator
+            /// \param[in] rhs The source surface
+            Surface &operator =(const Surface &rhs);
+
+            /// Saves the surface to file
+            /// \param[in] filename The destination filename
+            void save(const std::string &filename) const;
+
+            /// Retrieves the window's size
+            /// \return The size of the surface
+            Area get_size() const
+            {
+               return pixels ? pixels->size : Area();
+            }
+
+            /// Retrieves a pixel at the specified coordinates
+            /// \param[in] pos The position of the pixel to retrieve
+            /// \return The pixel at the specified position
+            Color &get_pixel(const Point &pos)
+            {
+               cow();
+               assert(pixels);
+               return pixels->buffer[pos.y * pixels->size.x + pos.x];
+            }
+
+            /// Retrieves the pixel color at the specified coordinates
+            /// \param[in] x The x position of the pixel to retrieve
+            /// \param[in] y The y position of the pixel to retrieve
+            /// \return The color of the pixel at the specified position
+            Color& get_pixel(int x, int y)
+            {
+               cow();
+               assert(pixels);
+               return pixels->buffer[y * pixels->size.x + x];
+            }
+
+            /// Retrieves the pixel color at the specified coordinates
+            /// \param[in] pos The position of the pixel to retrieve
+            /// \return The color of the pixel at the specified position
+            Color get_pixel(const Point &pos) const
+            {
+               assert(pixels);
+               return pixels->buffer[pos.y * pixels->size.x + pos.x];
+            }
+
+            /// Retrieves the pixel color at the specified coordinates
+            /// \param[in] x The x position of the pixel to retrieve
+            /// \param[in] y The y position of the pixel to retrieve
+            /// \return The color of the pixel at the specified position
+            Color get_pixel(int x, int y) const
+            {
+               assert(pixels);
+               return pixels->buffer[y * pixels->size.x + x];
+            }
+
+            /// Acquire the pixel color buffer
+            /// \return the pixel color buffer
+            Color *get_pixels()
+            {
+               cow();
+               assert(pixels);
+               return pixels->buffer;
+            }
+
+            /// Acquire the pixel color buffer
+            /// \return the pixel color buffer
+            const Color *get_pixels() const
+            {
+               assert(pixels);
+               return pixels->buffer;
+            }
+
+            /// Does a surface-to-surface blit
+            /// \param[in] src The source surface
+            /// \param[in] dst_pos The position to blit to
+            /// \param[in] src_rect The part of the source surface to blit from
+            /// \param[in] options Extra blit options
+            void blit(const Surface &src, const Point &dst_pos = Point(), const Rect &src_rect = Rect(), const RenderOptions &options = RenderOptions());
+
+            /// Does a texture-to-surface blit
+            /// \param[in] src The source texture
+            /// \param[in] dst_pos The position to blit to
+            /// \param[in] src_rect The part of the source texture to blit from
+            /// \param[in] options Extra blit options
+            void blit(const Texture &src, const Point &dst_pos = Point(), const Rect &src_rect = Rect(), const RenderOptions &options = RenderOptions());
+
+            /// Fills a portion of the image with the given color
+            /// \param[in] color The color
+            /// \param[in] rect The portion to fill
+            void fill(const Color &color, const Rect &rect = Rect());
+
+            /// Fills and alpha blend a portion of the image with the given color
+            /// \param[in] color The color
+            /// \param[in] rect The portion to fill
+            void fill_blend(const Color &color, const Rect &rect = Rect());
+
+            /// Scale the surface by a factor of (numerator / denominator)
+            /// \param[in] numerator The numerator of the scale factor
+            /// \param[in] denominator The denominator of the scale factor
+            /// \return The scaled surface
+            Surface scale(unsigned int numerator, unsigned int denominator) const;
+
+            /// Flip the surface horizontally
+            /// \return The flipped surface
+            Surface h_flip() const;
+
+            /// Flip the surface vertically
+            /// \return The flipped surface
+            Surface v_flip() const;
+
+            /// Modulate the image with a color
+            /// \return The modulated surface
+            Surface modulate(const Color &color) const;
+
+            /// Modulate the image with an alpha
+            /// \return The modulated surface
+            Surface modulate(unsigned char alpha) const;
+         private:
+            /// Copy on Write
+            void cow();
+
+            class PixelBuffer
+            {
+               public:
+                  PixelBuffer(Area size)
+                   : buffer(0),
+                     size(size),
+                     refcount(1)
+                  {
+                     if(size != Area())
+                     {
+                        buffer = new Color[size.x * size.y];
+                     }
+                  }
+
+                  ~PixelBuffer()
+                  {
+                     delete buffer;
+                  }
+
+                  void ref()
+                  {
+                     refcount++;
+                  }
+
+                  void unref()
+                  {
+                     assert(refcount > 0);
+                     refcount--;
+                     if(refcount == 0)
+                     {
+                        delete this;
+                     }
+                  }
+
+                  Color *buffer;
+                  Area size;
+                  int refcount;
+            };
+
+            /// The pixels
+            PixelBuffer *pixels;
+      };
+
+      /// A section of a surface
+      class SurfaceSection
+      {
+         public:
+            /// The image
+            Surface image;
+
+            /// The clip rectangle
+            Rect clip_rect;
+
+            /// Create a section from an image and a rectangle
+            /// \param[in] image The image
+            /// \param[in] rect The clip rectangle
+            SurfaceSection(const Surface &image = Surface(), const Rect &clip_rect = Rect()) :
+               image(image),
+               clip_rect(clip_rect)
+            {
+            }
+      };
+   }
+}
+
+#endif
diff --git a/src/unison/include/unison/video/Texture.hpp b/src/unison/include/unison/video/Texture.hpp
new file mode 100644 (file)
index 0000000..7209801
--- /dev/null
@@ -0,0 +1,124 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef UNISON_VIDEO_TEXTURE_HPP
+#define UNISON_VIDEO_TEXTURE_HPP
+
+#include <unison/video/Blittable.hpp>
+#include <unison/video/Surface.hpp>
+#include <unison/video/Coord.hpp>
+
+#include <string>
+#include <vector>
+#include <set>
+
+namespace Unison
+{
+   namespace Video
+   {
+      typedef unsigned int TextureID;
+      static const TextureID INVALID_TEXTURE_ID = ~0;
+      /// An image that is optimized for fast drawing
+      class Texture : public Blittable
+      {
+         public:
+            /// Default constructor
+            Texture();
+
+            /// Opens image file indicated by filename
+            /// \param[in] filename The filename of the image file
+            Texture(const std::string &filename);
+
+            /// Opens image file indicated by filename and use the specified colorkey
+            /// \param[in] filename The filename of the image file
+            /// \param[in] colorkey The colorkey used by the file
+            Texture(const std::string &filename, const Color &colorkey);
+
+            /// Create a texture from the given surface
+            /// \param[in] surface The surface to optimize
+            Texture(const Surface &surface);
+
+            /// Copy constructor
+            /// \param[in] rhs The source texture
+            Texture(const Texture &rhs);
+
+            /// Destructor
+            ~Texture();
+
+            /// Assignment operator
+            /// \param[in] rhs The source surface
+            Texture &operator =(const Texture &rhs);
+
+            /// Retrieves the texture's id
+            /// \return The id of the surface
+            TextureID get_id() const;
+
+            /// Retrieves the texture's size
+            /// \return The size of the surface
+            Area get_size() const;
+
+            /// Does a surface-to-texture blit
+            /// \param[in] src The source surface
+            /// \param[in] dst_pos The position to blit to
+            /// \param[in] src_rect The part of the source surface to blit from
+            /// \param[in] options Extra blit options
+            void blit(const Surface &src, const Point &dst_pos = Point(), const Rect &src_rect = Rect(), const RenderOptions &options = RenderOptions());
+
+            /// Does a texture-to-texture blit
+            /// \param[in] src The source texture
+            /// \param[in] dst_pos The position to blit to
+            /// \param[in] src_rect The part of the source texture to blit from
+            /// \param[in] options Extra blit options
+            void blit(const Texture &src, const Point &dst_pos = Point(), const Rect &src_rect = Rect(), const RenderOptions &options = RenderOptions());
+
+            /// Fills a portion of the image with the given color
+            /// \param[in] color The color
+            /// \param[in] rect The portion to fill
+            void fill(const Color &color, const Rect &rect = Rect());
+
+            /// Fills and alpha blend a portion of the image with the given color
+            /// \param[in] color The color
+            /// \param[in] rect The portion to fill
+            void fill_blend(const Color &color, const Rect &rect = Rect());
+
+            static std::vector<Surface> save_textures();
+            static void load_textures(const std::vector<Surface> &surfaces);
+
+            /// Recover previously used but now unused texture IDs
+            static void recover_texture_ids();
+         private:
+            /// Copy on Write
+            void cow();
+
+            /// The texture ID
+            TextureID id;
+
+            /// All the textures in existence
+            static std::set<Texture *> textures;
+      };
+
+      /// A section of a texture
+      class TextureSection
+      {
+         public:
+            /// The image
+            Texture image;
+
+            /// The clip rectangle
+            Rect clip_rect;
+
+            /// Create a section from an image and a rectangle
+            /// \param[in] image The image
+            /// \param[in] rect The clip rectangle
+            TextureSection(const Texture &image = Texture(), const Rect &clip_rect = Rect()) :
+               image(image),
+               clip_rect(clip_rect)
+            {
+            }
+      };
+   }
+}
+
+#endif
diff --git a/src/unison/include/unison/video/Window.hpp b/src/unison/include/unison/video/Window.hpp
new file mode 100644 (file)
index 0000000..5178af5
--- /dev/null
@@ -0,0 +1,148 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef UNISON_VIDEO_WINDOW_HPP
+#define UNISON_VIDEO_WINDOW_HPP
+
+#include <unison/video/Blittable.hpp>
+#include <unison/video/DisplayList.hpp>
+#include <unison/video/RenderOptions.hpp>
+#include <unison/video/Surface.hpp>
+#include <unison/video/Texture.hpp>
+
+#include <string>
+#include <vector>
+#include <map>
+
+namespace Unison
+{
+   namespace Video
+   {
+      class Color;
+      class Rect;
+      class Texture;
+      class Surface;
+      namespace Backend
+      {
+         class Window;
+      }
+      /// Window management singleton
+      class Window : public Blittable
+      {
+         public:
+            /// Initialize and retrieve singleton
+            static Window &get();
+
+            /// Set the logical size of the window
+            /// \param[in] logical_size The logical size of the window
+            void set_logical_size(const Area &logical_size);
+
+            /// Get the logical size of the window
+            /// \return The logical size of the window
+            Area get_logical_size() const;
+
+            /// Open the window
+            /// \param[in] size The size of the window
+            /// \param[in] fullscreen Whether to open in fullscreen mode
+            void open(const Area &size, bool fullscreen = false);
+
+            /// Take a screenshot of the window
+            /// \param[in] filename The destination filename
+            void take_screenshot(const std::string &filename) const;
+
+            /// Flip request buffers
+            /// \note Should be called only once per frame!
+            void flip();
+
+            /// Redraw requests
+            void redraw();
+
+            /// Set window title
+            void set_title(const std::string &title);
+
+            /// Set window icon
+            void set_icon(const Surface &icon);
+
+            /// Retrieves the window's size
+            /// \return The size of the window
+            Area get_size() const;
+
+            /// Queries whether the window is open
+            /// \return Whether the window is open
+            bool is_open() const;
+
+            /// Queries whether the window is in fullscreen mode
+            /// \return Whether the window is fullscreen
+            bool is_fullscreen() const;
+
+            /// Does a surface-to-window blit
+            /// \param[in] src The source surface
+            /// \param[in] dst_pos The position to blit to
+            /// \param[in] src_rect The part of the source surface to blit from
+            /// \param[in] options Extra blit options
+            void blit(const Surface &src, const Point &dst_pos = Point(), const Rect &src_rect = Rect(), const RenderOptions &options = RenderOptions())
+            {
+               layers[0].blit(src, dst_pos, src_rect, options);
+            }
+
+            /// Does a texture-to-window blit
+            /// \param[in] src The source texture
+            /// \param[in] dst_pos The position to blit to
+            /// \param[in] src_rect The part of the source texture to blit from
+            /// \param[in] options Extra blit options
+            void blit(const Texture &src, const Point &dst_pos = Point(), const Rect &src_rect = Rect(), const RenderOptions &options = RenderOptions())
+            {
+               layers[0].blit(src, dst_pos, src_rect, options);
+            }
+
+            /// Fills a portion of the window with the given color
+            /// \param[in] color The color
+            /// \param[in] rect The portion to fill
+            void fill(const Color &color, const Rect &rect = Rect())
+            {
+               layers[0].fill(color, rect);
+            }
+
+            /// Fills and alpha blend a portion of the window with the given color
+            /// \param[in] color The color
+            /// \param[in] rect The portion to fill
+            void fill_blend(const Color &color, const Rect &rect = Rect())
+            {
+               layers[0].fill_blend(color, rect);
+            }
+
+            DisplayList &operator [] (int layer)
+            {
+               return layers[layer];
+            }
+         private:
+            /// The logical size of the window
+            Area logical_size;
+
+            /// The title of the window
+            std::string title;
+
+            /// The window icon
+            Surface icon;
+
+            /// The window
+            Backend::Window *window;
+
+            /// Display list currently being drawn
+            DisplayList list;
+
+            /// Layers of pending display lists
+            std::map<int, DisplayList> layers;
+
+            /// Default constructor
+            Window();
+
+            /// Destructor
+            ~Window();
+      };
+   }
+}
+
+#endif
diff --git a/src/unison/include/unison/video/backend/Renderer.hpp b/src/unison/include/unison/video/backend/Renderer.hpp
new file mode 100644 (file)
index 0000000..0f04b4e
--- /dev/null
@@ -0,0 +1,102 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef UNISON_VIDEO_BACKEND_RENDERER_HPP
+#define UNISON_VIDEO_BACKEND_RENDERER_HPP
+
+#include <unison/video/Coord.hpp>
+
+#include <string>
+#include <istream>
+
+namespace Unison
+{
+   namespace Video
+   {
+      class Surface;
+      class Texture;
+      class Window;
+      class Color;
+      class Rect;
+      class RenderOptions;
+
+      namespace Backend
+      {
+         class Texture;
+         class Window;
+         /// Backend-specific renderer interface
+         class Renderer
+         {
+            public:
+               /// Destructor
+               virtual ~Renderer()
+               {
+               }
+
+               /// Initialize the backend
+               virtual void init() = 0;
+
+               /// Cleanup the backend
+               virtual void quit() = 0;
+
+               /// Get the name of the renderer
+               /// \return the name of the renderer
+               virtual std::string get_name() = 0;
+
+               /// Check if the backend is usable
+               /// \return Whether the backend is usable
+               virtual bool is_usable() = 0;
+
+               virtual Surface load_surface(const std::string &filename) = 0;
+               virtual Surface load_surface(const std::string &filename, const Color &colorkey) = 0;
+
+               virtual void save_surface(const Surface &surface, const std::string &filename) = 0;
+
+               /// Does a surface-to-surface blit
+               /// \param[in] src The source surface
+               /// \param[in] src_rect The part of the source surface to blit from
+               /// \param[in] dst The destination surface
+               /// \param[in] dst_pos The position to blit to
+               /// \param[in] options Extra blit options
+               virtual void blit(const Surface &src, const Rect &src_rect, Surface &dst, const Point &dst_pos, const RenderOptions &options) = 0;
+
+               /// Does a texture-to-surface blit
+               /// \param[in] src The source texture
+               /// \param[in] src_rect The part of the source texture to blit from
+               /// \param[in] dst The destination surface
+               /// \param[in] dst_pos The position to blit to
+               /// \param[in] options Extra blit options
+               virtual void blit(Texture *src, const Rect &src_rect, Surface &dst, const Point &dst_pos, const RenderOptions &options) = 0;
+
+               /// Fills a portion of a surface with the given color
+               /// \param[in] dst The destination surface
+               /// \param[in] color The color
+               /// \param[in] rect The portion to fill
+               virtual void fill(Surface &dst, const Color &color, const Rect &rect) = 0;
+
+               /// Fills with alpha blend a portion of a surface with the given color
+               /// \param[in] dst The destination surface
+               /// \param[in] color The color
+               /// \param[in] rect The portion to fill
+               virtual void fill_blend(Surface &dst, const Color &color, const Rect &rect) = 0;
+
+               /// Create a window
+               /// \param[in] size The size of the window
+               /// \param[in] logical_size The logical size of the window
+               /// \param[in] fullscreen Whether to open in fullscreen mode
+               /// \return The created window
+               virtual Window *create_window(const Area &size, const Area &logical_size, bool fullscreen) = 0;
+
+               /// Create a texture for the given surface
+               /// \param[in] surface The surface to convert
+               /// \param[in] name The name of the texture
+               /// \return The texture for the surface
+               virtual Texture *create_texture(const Surface &surface) = 0;
+         };
+      }
+   }
+}
+
+#endif
diff --git a/src/unison/include/unison/video/backend/Texture.hpp b/src/unison/include/unison/video/backend/Texture.hpp
new file mode 100644 (file)
index 0000000..0d82371
--- /dev/null
@@ -0,0 +1,115 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef UNISON_VIDEO_BACKEND_TEXTURE_HPP
+#define UNISON_VIDEO_BACKEND_TEXTURE_HPP
+
+#include <unison/video/Blittable.hpp>
+#include <unison/video/Surface.hpp>
+#include <unison/video/Texture.hpp>
+
+#include <string>
+#include <vector>
+#include <map>
+
+namespace Unison
+{
+   namespace Video
+   {
+      namespace Backend
+      {
+         class Renderer;
+         /// Backend-specific texture interface
+         class Texture : public Blittable
+         {
+            public:
+               /// Destructor
+               virtual ~Texture();
+
+               /// Get the size of the texture
+               /// \return The texture size 
+               Area get_size();
+
+               /// Called when referenced
+               void ref();
+
+               /// Called when a reference goes away
+               void unref();
+
+               /// Get the number of references to the texture
+               /// \return The reference count
+               int get_refcount();
+
+               /// Get the equavalent surface to the texture
+               virtual const Surface get_surface() = 0;
+
+               /// Save the texture, called when the window is about to be created or recreated
+               virtual void save() = 0;
+
+               /// Save all the textures
+               static std::vector<Surface> save_textures();
+
+               /// Load the textures
+               static void load_textures(const std::vector<Surface> &surfaces);
+
+               /// Recover previously used but now unused texture IDs
+               /// \return A map of what IDs changed during recovery
+               static std::map<TextureID, TextureID> recover_texture_ids();
+
+               /// Retrieve the texture ID for the filename
+               /// \param[in] filename The filename of the image file
+               /// \return The texture ID of the texture
+               static TextureID get_texture_id(const std::string &filename);
+
+               /// Retrieve the texture ID for the filename
+               /// \param[in] filename The filename of the image file
+               /// \param[in] colorkey The colorkey used by the file
+               /// \return The texture ID of the texture
+               static TextureID get_texture_id(const std::string &filename, const Color &colorkey);
+
+               /// Retrieve the texture ID for the surface
+               /// \param[in] surface The surface to optimize
+               /// \return The texture ID of the texture
+               static TextureID get_texture_id(const Surface &surface);
+
+               /// Retrieve the texture ID for the texture
+               /// \param[in] texture The texture
+               /// \return The texture ID of the texture
+               static TextureID get_texture_id(Texture *texture);
+
+               /// Retrieve the texture corresponding to the texture ID
+               /// \param[in] id The texture ID
+               /// \return The corresponding texture
+               static Texture *get_texture(TextureID id);
+
+               /// Retrieve the name associated with the texture ID
+               /// \param[in] texture The texture
+               /// \return The texture ID of the texture
+               static std::string get_name(TextureID id);
+            protected:
+               /// Create a texture from the given surface with the given name
+               /// \param[in] surface The surface to optimize
+               Texture(const Surface &surface);
+
+               /// The surface the texture is based from
+               Surface surface;
+
+               /// The size of the texture
+               Area size;
+
+               /// The number of references to the texture
+               int refcount;
+
+               /// All of the textures in existence
+               static std::vector<Texture *> textures;
+
+               /// The subset of all textures that have names
+               static std::map<std::string, TextureID> named_textures;
+         };
+      }
+   }
+}
+
+#endif
diff --git a/src/unison/include/unison/video/backend/Window.hpp b/src/unison/include/unison/video/backend/Window.hpp
new file mode 100644 (file)
index 0000000..136420c
--- /dev/null
@@ -0,0 +1,62 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef UNISON_VIDEO_BACKEND_WINDOW_HPP
+#define UNISON_VIDEO_BACKEND_WINDOW_HPP
+
+#include <unison/video/Blittable.hpp>
+#include <unison/video/RenderOptions.hpp>
+#include <unison/video/Coord.hpp>
+#include <unison/video/Rect.hpp>
+
+#include <string>
+#include <vector>
+
+namespace Unison
+{
+   namespace Video
+   {
+      class Color;
+      class Rect;
+      class Texture;
+      class Surface;
+      namespace Backend
+      {
+         /// Backend-specific window interface
+         class Window : public Blittable
+         {
+            public:
+               /// Destructor
+               virtual ~Window()
+               {
+               }
+
+               /// Take a screenshot of the window
+               /// \param[in] filename The destination filename
+               virtual void take_screenshot(const std::string &filename) const = 0;
+
+               /// Flip request buffers
+               /// \note Should be called only once per frame!
+               virtual void flip() = 0;
+
+               /// Set window title
+               virtual void set_title(const std::string &title) = 0;
+
+               /// Set window icon
+               virtual void set_icon(const Surface &icon) = 0;
+
+               /// Retrieves the window's size
+               /// \return The size of the window
+               virtual Area get_size() const = 0;
+
+               /// Queries whether the window is in fullscreen mode
+               /// \return Whether the window is fullscreen
+               virtual bool is_fullscreen() const = 0;
+         };
+      }
+   }
+}
+
+#endif
diff --git a/src/unison/include/unison/video/sdl/Blitters.hpp b/src/unison/include/unison/video/sdl/Blitters.hpp
new file mode 100644 (file)
index 0000000..c718544
--- /dev/null
@@ -0,0 +1,108 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef UNISON_VIDEO_SDL_BLITTERS_HPP
+#define UNISON_VIDEO_SDL_BLITTERS_HPP
+
+#include <unison/video/Blitters.hpp>
+#include <unison/video/Coord.hpp>
+#include <unison/video/Surface.hpp>
+
+#include "SDL.h"
+
+namespace Unison
+{
+   namespace Video
+   {
+      namespace SDL
+      {
+         struct Blitters
+         {
+            static SDL_Surface *create_sdl_surface_from(Surface &src)
+            {
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+               SDL_Surface *surface = SDL_CreateRGBSurfaceFrom(src.get_pixels(), src.get_size().x, src.get_size().y, 32, src.get_size().x * 4, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
+#else
+               SDL_Surface *surface = SDL_CreateRGBSurfaceFrom(src.get_pixels().get_pixels(), src.get_size().x, src.get_size().y, 32, src.get_size().x * 4, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
+#endif
+               return surface;
+            }
+
+            static SDL_Surface *create_sdl_surface_from(const Surface &src)
+            {
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+               SDL_Surface *surface = SDL_CreateRGBSurfaceFrom(const_cast<Color *>(src.get_pixels()), src.get_size().x, src.get_size().y, 32, src.get_size().x * 4, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
+#else
+               SDL_Surface *surface = SDL_CreateRGBSurfaceFrom(const_cast<Color *>(src.get_pixels()).get_pixels(), src.get_size().x, src.get_size().y, 32, src.get_size().x * 4, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
+#endif
+               return surface;
+            }
+
+            static SDL_Surface *optimize(const Surface &src);
+
+            static void blit_upper(SDL_Surface *src, Rect src_rect, SDL_Surface *dst, Point dst_pos, void (*blit_lower)(SDL_Surface *, const Rect &, SDL_Surface *, const Point &));
+
+            static void blit_lower_none(SDL_Surface *src, const Rect &src_rect, SDL_Surface *dst, const Point &dst_pos);
+
+            static void blit_lower_mask(SDL_Surface *src, const Rect &src_rect, SDL_Surface *dst, const Point &dst_pos);
+
+            static void blit_lower_alpha(SDL_Surface *src, const Rect &src_rect, SDL_Surface *dst, const Point &dst_pos);
+
+            static void blit_lower_add(SDL_Surface *src, const Rect &src_rect, SDL_Surface *dst, const Point &dst_pos);
+
+            static void blit_lower_mod(SDL_Surface *src, const Rect &src_rect, SDL_Surface *dst, const Point &dst_pos);
+
+            static void blit_blend_none(SDL_Surface *src, const Rect &src_rect, SDL_Surface *dst, const Point &dst_pos)
+            {
+               blit_upper(src, src_rect, dst, dst_pos, blit_lower_none);
+            }
+
+            static void blit_blend_mask(SDL_Surface *src, const Rect &src_rect, SDL_Surface *dst, const Point &dst_pos)
+            {
+               blit_upper(src, src_rect, dst, dst_pos, blit_lower_mask);
+            }
+
+            static void blit_blend_alpha(SDL_Surface *src, const Rect &src_rect, SDL_Surface *dst, const Point &dst_pos)
+            {
+               blit_upper(src, src_rect, dst, dst_pos, blit_lower_alpha);
+            }
+
+            static void blit_blend_add(SDL_Surface *src, const Rect &src_rect, SDL_Surface *dst, const Point &dst_pos)
+            {
+               blit_upper(src, src_rect, dst, dst_pos, blit_lower_add);
+            }
+
+            static void blit_blend_mod(SDL_Surface *src, const Rect &src_rect, SDL_Surface *dst, const Point &dst_pos)
+            {
+               blit_upper(src, src_rect, dst, dst_pos, blit_lower_mod);
+            }
+
+            static void blit_blend(SDL_Surface *src, const Rect &src_rect, SDL_Surface *dst, const Point &dst_pos, BlendMode blend)
+            {
+               switch(blend)
+               {
+                  case BLEND_NONE:
+                     blit_blend_none(src, src_rect, dst, dst_pos);
+                     break;
+                  case BLEND_MASK:
+                     blit_blend_mask(src, src_rect, dst, dst_pos);
+                     break;
+                  case BLEND_ALPHA:
+                     blit_blend_alpha(src, src_rect, dst, dst_pos);
+                     break;
+                  case BLEND_ADD:
+                     blit_blend_add(src, src_rect, dst, dst_pos);
+                     break;
+                  case BLEND_MOD:
+                     blit_blend_mod(src, src_rect, dst, dst_pos);
+                     break;
+               }
+            }
+         };
+      }
+   }
+}
+
+#endif
diff --git a/src/unison/physfs-1.1.1/CHANGELOG.txt b/src/unison/physfs-1.1.1/CHANGELOG.txt
new file mode 100644 (file)
index 0000000..805b7be
--- /dev/null
@@ -0,0 +1,602 @@
+/*
+ * CHANGELOG.
+ */
+
+04032007 - Added a "make dist" target for packing up source code releases.
+           Reverted Unix recursive mutex code. There were some portability
+           issues I didn't anticipate. Upped version to 1.1.1!
+04022007 - Added wxWidgets-based test program (incomplete). Filled in and
+           corrected some Doxygen comments.
+04012007 - Added PHYSFS_isInit() and PHYSFS_symbolicLinksPermitted() functions.
+03312007 - Added a quick'n'dirty unpack utility to the extras directory. Moved
+           DIR archiver to start of the list, so we don't have to have every
+           other archiver fail to open a directory as a file before mounting
+           it. Fixed typos in makeos2.cmd and the Doxygen comments. Added
+           symlink support to windows.c for use on Vista-based systems.
+03282007 - Logic bug in MVL/HOG/GRP archivers: only enumerated files when
+           looking in a directory other than the root, instead of enumerating
+           only for the root (thanks, Chris!). Minor fix for compilers that
+           don't like the BAIL_* macros with an empty argument
+           (thanks, Chris!)
+03262007 - Tons of Unicode work in windows.c ... should now use UCS-2 on
+           NT/XP/Vista/etc versions of the OS, and fallback to "ANSI" versions
+           for 95/98/ME, tapdancing around the system codepage if it has to.
+           Since the Unicode entry points are dynamically loaded, it won't
+           have issues with missing symbols on Win9x, nor does it need to be
+           built separately with #define UNICODE (although it will work the
+           same with or without this define, as it doesn't use TCHARs or
+           the non-[WA] versions of APIs. Other minor Windows cleanups and
+           corrections.
+03252007 - Improved dynamic loader and initial Unicode work in windows.c ...
+03242007 - Replaced BeOS semaphores with BLockers for the mutex implementation.
+           It's much simpler, it has "benaphores" built in behind the scenes
+           for faster performance, and it's recursive...also, we were
+           previously setting the PhysicsFS error state if BeOS mutex grabbing
+           failed (a big no no!), and that's now fixed. Good wins all around.
+03222007 - Replaced some Malloc and all the alloca() calls with
+           __PHYSFS_smallAlloc(), which will stack allocate small (128 or
+           less bytes) blocks and Malloc the rest...naturally these now have
+           to be paired with __PHYSFS_smallFree() calls, so you can't be as
+           lazy as a basic alloca() would let you be. The benefit is both less
+           malloc pressure for those temporary allocations and better stack
+           overflow safety (so if some jerk tries to push a 78 megabyte string
+           through the library as a filename, we won't try to strcpy it to
+           the stack). Hopefully some internal interfaces can now get
+           refactored to stop generating heap pointers and let the caller use
+           smallAlloc to further reduce malloc pressure.
+03212007 - Replaced LONGLONGLITERAL with __PHYSFS_UI64/__PHYSFS_SI64 ...
+03202007 - Removed platform/skeleton.c (it was out of date), added
+           platform/macosx.c (To further Macify the code and get the #ifdefs
+           out of unix.c), and refactored the platform layer to try and
+           make the unix/posix/macosx/beos sources try to find a split that
+           works. Moved the platform allocators to physfs.c, since all but
+           Mac OS X were using malloc()...there's now an interface for the
+           platform to supply a custom allocator if they don't want the malloc
+           version. Removed __PHYSFS_platformTimeslice(), as it's no longer
+           being used. Replaced manual management of pthread mutexes with
+           PTHREAD_MUTEX_RECURSIVE attribute...let's see what platforms
+           throw up on that. Handled documentation comment FIXME in physfs.h.
+03192007 - Fixed two switched strings in CMakeLists.txt ... patch to compile
+           with latest Windows Platform SDK. Explicitly check for NULL in
+           PHYSFS_init() when we can't go on without a real string here.
+           Removed ANSI-C workaround for missing lstat() nonsense in posix.c
+           (POSIX != ANSI, time to give up here). Try to use /proc/self/exe
+           to find the base dir on Unix, so we can do without argv[0] on
+           systems with a Linux-like /proc filesystem.
+03162007 - Changed PHYSFS_file from a typedef to a #define (in case it would
+           cause an aggressive compiler to think you're passing the wrong type
+           to a function) and added Doxygen comments to explain it.
+03152007 - Bunch of work on Unicode...added case-folding stricmp, removed
+           platform-specific stricmp implementations, changed appropriate
+           calls to an ASCII-only stricmp that ignores locale. Fixed case on
+           UTF-8 API entry points.
+03142007 - Dropped classic Mac OS support. It's just too hard to find a working
+           Mac OS 9 install and reasonable development tools, so it's not
+           worth it. If you still target OS 8 or 9, please use PhysicsFS 1.0.
+03112007 - Removed zlib_license_change.txt ... it's in Subversion and the 1.0
+           branch for history's sake. Added shared and static build options
+           to CMakeLists.txt, and the expected "make install" target.
+           Renamed some FILENAME files to FILENAME.txt, removed physfs.rc.
+           Now compiles everything whether we need it or not, removing whole
+           files with #ifdefs...this will make it easier to "embed" this
+           library in other projects or use a different build system: just
+           push everything through the compiler with preprocessor defines for
+           the parts you want/need...platform modules are determined
+           automatically without the build system needing to intervene, so you
+           just have to #define the archivers, etc that you want.
+           Updated makeos2.cmd for newer Innotek toolchain (thanks, Dave!)
+03082007 - Fixed a comment in physfs.h. Renamed win32.c to windows.c.
+           Cleaned up whitespace/formatting in pocketpc.c. Updated PocketPC
+           code to expect UTF-8 strings from the higher level. Changed
+           PHYSFS_SUPPORTS_LZMA to PHYSFS_SUPPORTS_7Z. Killed some #ifdefs
+           in physfs.c. Moved to CMake...so long, autotools! Killed MIX
+           archiver, too.
+11052006 - More 7zip archiver work (thanks, Dennis!). Initial Unicode work.
+           Minor BeOS realpath tweak.
+09272006 - Reworked 7zip archiver (thanks, Dennis!).
+09232006 - Fixed typo in doxygen comment.
+04112006 - Added LZMA archiver...7zip support (thanks, Dennis!).
+03232006 - Added -fvisibility for gcc4 (http://gcc.gnu.org/wiki/Visibility)
+01012006 - Cleaned up overflow checks in platform memory allocators (thanks to
+           Nicolas Lebedenco for pointing out the original issue with
+           long long literals). Added physfs.rc (thanks, Dennis!). Changed my
+           email address. Removed acconfig.h.
+11282005 - Corrected docs on PHYSFS_setWriteDir().
+10122005 - Fixed locateInStringList() in physfs.c (thanks, Matze!). Patched
+           archivers/wad.c to compile.
+09192005 - Make unix mutexes recursive above pthread layer...fixes deadlock on
+           MacOS X, for now.
+09182005 - API BREAKAGE: PHYSFS_enumerateFilesCallback() now passes the
+           original directory name back to the app in the callback. This
+           API was only in 1.1.0, and wasn't promised to be stable at this
+           point. Please update your apps! Cleaned out a FIXME in file
+           enumeration that would confuse the library under certain
+           circumstances.
+09092005 - Some tweaks to PHYSFS_Allocator. Apparently configure.in doesn't
+           work like I thought for version bumps, so it thinks 1.1.0 isn't
+           binary compatible with 1.0...fixed, I think.
+09062005 - Happy September. Changed the allocation abstraction to use
+           PHYSFS_uint64 instead of size_t, so we don't have to include
+           system headers inside physfs.h. Minor MingW fixes (but it's still
+           broken, I think).
+08202005 - Fixed bug in verifyPath() that was breaking PHYSFS_setSaneConfig()
+           and other corner cases.
+07242005 - Patched to compile on BeOS.
+07232005 - Fixed bug in zip archiver (thanks, Jörg Walter!).
+           More minor OS/2 tweaks. Updated zlib to 1.2.3, which properly
+           includes the security fix. Fixed "make dist" to handle .svn dirs
+           and other file changes. Removed "debian" directory. Allow a mount
+           point of NULL to be "/", per the documentation. Fixed warning in
+           physfs.c. Assert definition fix. Updated CWProjects.sit.
+           Upped version to 1.1.0 ... first release of 1.1 dev branch!
+07212005 - Patched to compile on OS/2 again.
+07132005 - Updated zlib to 1.2.2, and patched it for this security hole:
+           http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-2096
+06122005 - Added support for mingw to Unix build process (thanks, Matze!).
+03162005 - Added missing translation and Portuguese support (thanks, Danny!).
+           MPW support and several MacOS Classic fixes (thanks, Chris!).
+           Changed CWProjects from SITX to SIT format, so OS9 users can
+           unpack it.
+03132005 - More mount work, added PHYSFS_getMountPoint() and more cleanups.
+           Replaced all the C runtime allocations with PhysFS allocation hooks.
+           Added pocketpc.c to EXTRA_DIST. Added allocation hooks to some
+           platform drivers. Updated Mac Classic build.
+03122005 - Added evil GOTO_*_MACRO_* macros. Fixed unix.c to compile again on
+           MacOS X. Added PHYSFS_mount() (thanks, Philip!). Cleaned up the
+           INSTALL and CREDITS files a little. Split off start of
+           verifySecurity() into a path sanitizer and changed entry points to
+           sanitize input paths into a stack-allocated buffer before further
+           processing. This removes the need for a malloc() for almost all
+           file system operations, and generally cleaned things up. Added a
+           "mount" command to test_physfs. Other general cleanups.
+02152005 - Minor comment fix in platform/pocketpc.c
+01052005 - Fixed HOG archiver file lookup (thanks, Chris!)
+12162004 - Fixed some documentation/header comment typos (thanks, Gaetan!)
+10302004 - Fixed a strcpy that should have been a strcat. (thanks, Tolga!)
+           Build system respects external CFLAGS now. (thanks, Adam!)
+           Fixed infinite loop in new enumeration code. (thanks, Adam!)
+10062004 - Removed profiling code from physfs.c.
+09292004 - Every API that can return a list of strings can now use a
+           callback mechanism if the application wants to do it's own
+           allocation or handling on a per-item basis. The guts of those
+           APIs that create string lists now use the callbacks themselves to
+           build the lists, too. The callback functionality goes all the way
+           down to the archivers and platform drivers where appropriate, which
+           cleans things up and simplifies some internal tasks very nicely.
+           Got rid of all the annoying forward declarations in all the
+           archivers and moved their PHYSFS_Archiver data to the end of the
+           file, since this was annoying me and I was getting sick of updating
+           function signatures in two places when the internal API changed.
+           Removed the code/data for LinkedStringLists...it isn't used anymore
+           now that the callback code is in place.
+09262004 - Did the same thing to FileHandles than I did to DirHandles, but
+           this triggered massive tweaking in physfs.c. A lot of code got
+           little cleanups, which was nice. Less malloc pressure, too, since
+           opening a file used to allocate a ton of crap and mush it
+           together...now it's basically down to one structure and the
+           instance data in whatever archiver. Minor varname tweak in win32.c
+           and pocketpc.c. Changed PHYSFS_file to PHYSFS_File to match the
+           rest of the API's naming scheme (but put a typedef for source
+           compatibility).
+09252004 - Cleaned up archiver interface to not deal with DirHandles anymore,
+           which simplifies things, removes some responsibility and code
+           duplication from the archivers, and trims some malloc pressure.
+           Ripped up the allocation hook code a little. We'll try to screw
+           with memory locking later, since it makes everything ugly and
+           complex. Oh well.
+09232004 - Started adding allocation hooks.
+09222004 - Happy September. Added Spanish translation back in.
+04092004 - Added MIX support for legacy Westwood titles (Thanks, Sebastian!).
+           Made bootstrap script MacOSX-friendly. Moved byteorder defines into
+           physfs_internal.h ...
+01152003 - Added Portuguese (Brazil) translation (Thanks, Danny!)
+
+
+--- This is where the 1.1 development branch starts. ---
+
+12292003 - Updated CodeWarrior projects from CW6 to CW7, and made a bunch of
+           patches to get the Mac Classic target building again. Removed
+           zlib114 from CVS repository. Updated OS/2 build batch file.
+           Added Z_PREFIX define to Unix builds that use internal zlib.
+           Patched up some (outdated?) Visual C project files for zlib121.
+           Patched Doxyfile and physfs.h for newer Doxygen. Fixed OS/2
+           build script. Tweaked Project Builder files to at least compile.
+           Added some last minute BeOS and Cygwin build fixes. Updated
+           Visual Studio projects and tweaked some Makefile.am crap. Made
+           changes so Visual Studio files would pack with DOS endlines and...
+           Upped version to 1.0.0 (woohoo!).
+12222003 - Fixed a search-and-replace mistake in win32.c that preventing
+           compiling on Windows. (thanks, Brian!) Converted VC6 .dsp to use
+           zlib121; made Z_PREFIX=1 enabled by default to avoid link clashes;
+           put zlib files in separate logical folder in .dsp project; updated
+           zlib121/zconf.h to address remaining symbols that were still
+           causing link warnings.
+12182003 - WAD archiver now puts maps into subdirectories, making them
+           accessible to the application. (Thanks, Travis!) RPM spec and
+           Makefile.am* now package zlib_license_change.txt (Thanks, Edward!)
+12142003 - Added Doom WAD support (Thanks, Travis!)
+12082003 - Fixed some win32.c deficiencies that Robby Dermody pointed
+           out (thanks!)
+12072003 - Upgraded internal zlib to 1.2.1 (thanks, Adam!) Other
+           Unix build fixes.
+11112003 - Patches to make OS/2 support compile again.
+11092003 - Added __PHYSFS_platformStrnicmp(), and made qpak.c case-insensitive.
+09122003 - Happy September. Actually released current tree as 0.1.9.
+08262003 - Added MiNT support to build process and fixed cross-compiling
+           (thanks Patrice Mandin!)
+08092003 - Some Windows build fixes (thanks, Brian Hook!)
+07232003 - Upped version to 0.1.9.
+07202003 - Switched to zlib license (see new LICENSE text in root of source
+           tree, and zlib_license_switch.txt for details). Had to remove
+           archivers/qpak.c, the Ruby bindings from the extras directory, and
+           the Russian and Spanish translations, since those contributors
+           couldn't be contacted. If they show up, we'll readd them to the
+           project, otherwise we'll eventually replace their work...everyone
+           else signed on for the change. Committed a patch to convert all
+           tabs to spaces (Thanks, James!). Added patch to zip.c to fix
+           crash (thanks, dillo!). Reimplmented qpak.c, by welding together
+           bits of grp.c and zip.c. Ed contacted me, so I could readd his
+           contributions post-license change...I'm going to keep the new
+           qpak.c, but I've readded his Ruby bindings and Russian translations.
+06112003 - Patches to globbing.c to handle corner cases (thanks, Bradley!).
+06102003 - Added globbing.c to "extras" directory.
+05232003 - Rewrote MacOSX/Darwin CD-ROM detection code to use IOKit, which is
+           much much more accurate than the previous code. Updated
+           configure.in and Makefile.am.newautomake for some MacOSX stuff.
+05222003 - Fixed win32 crash if PHYSFS_init() is called with a NULL.
+05182003 - PocketPC fixes (thanks, David Hedbor!)
+05162003 - Compiler warning cleanup in HOG and MVL archivers (Thanks, Bradley!)
+04082003 - Minor changes to extras/abs-file.h (Thanks, Adam!)
+03302003 - Fixed seeking in uncompressed ZIP entries, and handle a
+           misbehaviour in Java's JAR creation tools. Thanks to "Tree" for
+           pointing these bugs out. Added HOG and MVL archive support for
+           Descent I and II (Thanks, Bradley Bell!). Added example code to
+           do case-insensitive file searches ("extras/ignorecase.*").
+03192003 - Fixed problem in PHYSFS_mkdir() when dirs to be created already
+           exist. Fixed problem where PHYSFS_mkdir() incorrectly tripped an
+           alarm in __PHYSFS_verifySecurity().
+03122003 - Attempt at cleaning up some type correctness for VC++6. Made QPAK
+           archiver case-insensitive (since Quake2 has problems without it).
+01302003 - Added buffering API to OS/2 build's exported symbol list. Updated
+           CWProjects.sit and made several fixes to get physfs building on
+           MacOS Classic again.
+01282003 - Fixed seeking in buffered files opened for read.
+01072003 - .NET assembly and C# wrapper by Gregory S. Read in the extras dir.
+01042003 - Added a hack for dealing with OSX bundles and newer PBProjects
+           (thanks, Eric Wing!). Added some missing files to "make dist".
+           Fixed minor Doxygen typo in PHYSFS_flush() docs. Upped version to
+           0.1.8.
+12172002 - Added Apple Project Builder support files (thanks, Eric Wing!).
+12112002 - Added Ruby bindings to extras directory (thanks, Ed Sinjiashvili!).
+           Patched win32.c to compile with Mingw32 (thanks, Niels Wagenaar!).
+12032002 - Adam updated his extras/abs-file.h for the new buffering API.
+12022002 - German translation added, compliments of Michael Renner.
+12012002 - Minor fix to configure.in: reported --enable-debug's default
+           setting incorrectly. Added buffering to the API: you can now
+           buffer a file with PHYSFS_setBuffer(), and flush the buffer to
+           disk with PHYSFS_flush(). PhysicsFS file handles are unbuffered
+           by default (as they were before this API addition), so this does
+           not break the API. Other fixes for bugs I stumbled upon during
+           this work are in CVS, too.
+11292002 - Minor fix for strange PATH strings in unix.c (thanks, Alexander!)
+11222002 - Initial PocketPC port by Corona688.
+10222002 - Fixed segfault in test_physfs.c when user hits CTRL-D (and
+           readline() thus returns NULL)...now gracefully exits, as it should.
+10142002 - Added check for AMD's x86-64 ("Hammer") architecture when
+           determining platform byte order.
+10112002 - Fixed "setsaneconfig" command in test_physfs.c ...
+09232002 - Happy September. Updated VC++6 project files, fixed some
+           VC++ compile nags (more work to be done in zip.c).
+08302002 - Cleaned tab stops out of zip.c, and fixed a possible infinite loop
+           in zip_find_entry().
+08292002 - Fixed a mistake in makeos2.cmd, and updated the INSTALL docs.
+           Added physfs.spec.in to EXTRA_DIST in Makefile.am*
+08292002 - Added a physfs/stdio wrapper header to the "extras" dir,
+           compliments of Adam D. Moss (file is "abs-file.h").
+08282002 - Cleanups in grp.c so that Visual C++ doesn't complain anymore.
+           zip.c now works correctly when PhysicsFS is disallowing symlinks.
+           A few minor optimizations in zip.c, with a few more to come later.
+           Added VS.NET project files to CVS.
+08222002 - Fixed ZIP_exists() to work with directories. Now breaks out of
+           __PHYSFS_verifySecurity() early if a path element is missing
+           (since all the others will be, too)...this check is only done
+           if symlinks are disabled, but we might as well save easy cycles
+           where we can.
+08212002 - Did a couple tedious-for-small-rewards cleanups, optimizations,
+           corrections and streamlinings I've been meaning to do. Touched a
+           lot of code. One of the side results is that ZIP_isDirectory()
+           got fixed.
+08192002 - Generalized sorting routines, moved them into physfs.c and removed
+           the multiple copies from the various archivers. Adding profiling
+           code (currently only for sort routines)...enable it with
+           --enable-profiling in the configure script. Fixed incorrect
+           behaviours in configure.in.
+08172002 - Patched configure.in to work around buggy autoconfs.
+08162002 - Fixed QPAK archiver, since I broke it (sorry!). Also fixed a
+           qpak memory leak.
+08092002 - Added Quake PAK archiver (qpak.c) by Ed Sinjiashvili. Thanks!
+           Made (successful?) attempt to fix pthread-to-ui64 cast problem.
+           Check for OS/2 in configure.in, in case anyone gets autoconf and
+           such to work right on their OS/2 box.
+08012002 - Patched win32.c to compile.
+07302002 - Minor error handling fix (thanks, Alexander!)
+07292002 - Found some memory leaks, thanks to Valgrind (which rules, btw).
+           Added Russian translations (koi8-r, cp1251, cp866, and iso-8859-5)
+           by Ed Sinjiashvili. Added Spanish translation by Pedro J. Pérez.
+           Debian package support in CVS, thanks to Colin Bayer. French
+           translation by Stéphane Peter.
+07282002 - macclassic.c now returns human readable error messages instead of
+           ERR_OS_ERROR. Closing files on MacOS no longer fails if the volume
+           info can't be flushed. Minor error message tweak in os2.c. All
+           possible human-readable literal strings (including all those OS/2
+           and MacOS error messages) have moved to constants in
+           physfs_internal.h...this allows the library to be translated to
+           other spoken languages fairly easily.
+07272002 - Patched the OS/2 code to be useful...works pretty well, now. Added
+           makeos2.cmd for building (not an ideal solution, but oh well).
+           Initialized some variables in zip.c to prevent compiler whining.
+07262002 - Fixed a typo in documentation. Archivers with matching file
+           extensions are now given first shot at opening an archive, but if
+           they fail, the other archivers are tried. More fixes to zip.c's
+           ZIP_enumerateFiles(). Wrote an OS/2 platform driver based on API
+           specs and a heavy pounding of Google Groups...as I don't have an
+           OS/2 compiler at the moment, it probably doesn't even compile.  :)
+07252002 - configure.in and unix.c now deal with platforms that lack a
+           functional pthread library. Edward Rudd sent in a patch to the RPM
+           specfile to have the build system set the correct version.
+           Clean ups in grp.c, beos.cpp and macclassic.c.
+07242002 - Rewrote ZIP_enumerate(). Hopefully it sucks less this time.
+           unix.c and configure.in now have the infrastructure to disable
+           the CD-ROM detection code, and use a stub that successfully (and
+           unconditionally) reports no detected discs. Currently this is
+           used on AtheOS (which doesn't have CD-ROM support at the moment
+           anyhow), but it will be useful to get the library up on odd,
+           Unix-like systems that don't use either getmntinfo() or getmntent().
+07232002 - Cleaned up the cut-and-pastes in the various file enumeration
+           routines and moved it into __PHYSFS_addToLinkedStringList().
+           Tons more ZIP file enhancing. I'm fairly certain it's robust and
+           fast in every reasonable respect, now. GRP archiver now caches
+           the file table...it was generally overhauled like the ZIP driver.
+           Added "ls" as an alias of "enumerate" in test_physfs.
+           I lied about zip.c's robustness; disabled the enumeration code.
+07212002 - More FreeBSD build system patches. Added some new autoconf spew to
+           .cvsignore. bootstrap now copies the appropriate Makefile.am
+           instead of rename()ing it.
+07192002 - Cleaned up configure.in and unix.c so that we check by available
+           header to determine the appropriate CD-ROM detection code...this
+           should make this more future-proof (and probably get it building
+           out of the box on other BSD platforms.)
+07172002 - Fixed seeking backwards in ZIP_seek(). Changed the error message
+           ERR_TOO_MANY_SYMLINKS to ERR_SYMLINK_LOOP. Patches to build system
+           and unix.c for FreeBSD compatibility. Added physfs.spec to
+           "make dist" archives (thanks, Edward Rudd!).
+07152002 - Symlinks in ZIP archives are detected correctly now, I think.
+07142002 - Use GetVolumeInformation() instead of GetDiskFreeSpace() in
+           win32.c's mediaInDrive() function. This allows Windows NT 3.x to
+           correctly detect CD-ROM drives. Library now appears to be fully
+           functional on WinNT 3.51...need to try NT 3.1 still.  :)
+           Patches to new ZIP code; cleaned up bugs in symlink reading code,
+           but we incorrectly identify some entries as symlinks, which doesn't
+           fly...for now, symlink code is commented out, so symlinks look
+           like regular files (and reading from a symlink entry gives you
+           the link as file data).
+07122002 - Rewrote the ZIP archiver to no longer use Gilles Vollant's unzip.c
+           code. Losing that abstraction should make the ZIP archiver
+           significantly more efficient, and halved the amount of code used.
+           Plus, being a control freak, I like my coding style more than
+           Gilles's. :)  There are still bugs to shake out, but this is good
+           progress.
+07112002 - configure.in updated to make it happier on newer autoconfs
+           (thanks again, Alexander!). FIXME cleanups.
+07102002 - Added a byteorder-friendly convenience API, so you can read/write
+           data and convert to the native byteorder without too much effort.
+           Upped version to 0.1.7.
+           Build system corrections for BeOS and Cygwin (thanks, Alexander!).
+           Added RPM specfile for PhysicsFS (thanks, Edward Rudd!).
+06292002 - Fixed incorrect error message when opening a file for read without
+           defining a search path. LOTS of win32 updates and fixes; lots of
+           things that were broken work now, and we are slowly becoming
+           more compatible with legacy win32 systems. Builds on Cygwin again.
+           All platform drivers (except beos.cpp) had a buffer overflow when
+           detecting mounted CD-ROM drives...it only occurs when a drive is
+           detected, and it probably won't result in your box getting rooted,
+           but upgrade soon anyhow. Readded the .cvsignore files from the old
+           build system.
+06282002 - Reworked build system _AGAIN_.
+06222002 - Alexander Pipelka spotted a bug in the file open routines in
+           posix.c; patched.
+06152002 - Autoconf build system will now generate shared libraries on BeOS,
+           and (supposedly) Cygwin.
+06142002 - Rewrote autoconf build system. It now works around the MacOS X bug
+           that prevented shared libraries from building.
+06112002 - Updated CodeWarrior projects and added them to CVS. _Finally_
+           officially released 0.1.6.
+06102002 - Major overhauls to platform/win32.c ... should work on all Windows
+           platforms, including 95/98/ME and NT/2K/XP flavors. Someone should
+           see if this builds on WinCE!  :)  You no longer need the latest
+           platform SDK to build it, either; the questionable DLL is accessed
+           with LoadLibrary() at runtime now, and handled if not present. This
+           now builds correctly on a freshly installed Visual Studio 6.0, and
+           the DLL it builds works everywhere. Plus, a bunch of other bugs
+           and incorrect behaviours were squashed. Visual Studio 6.0 project
+           file added to CVS.
+06082002 - Fixes to __PHYSFS_platformEnumerateFiles() in win32.c: cleaned up
+           memory leak, handles paths more robustly, and prevents possible
+           skipped file entries. Removed AC_C_CONST and AC_TYPE_SIZE_T checks
+           from configure.in (not needed, and they broke BeOS build). Clean
+           out the docs/ directory when doing a "make dist". Fixed crashbug
+           when calling PHYSFS_deinit() more than once in a row. Tried to get
+           MacOS X to build a shared library, gave up; I'm doing something
+           wrong in my Makefile.am, I think. On MacOS X, running ./configure
+           --enable-static --disable-shared works, though. Hopefully someone
+           will fix this soon. In unix.c, the Darwin version of
+           __PHYSFS_platformDetectAvailableCDs() was free()ing a static
+           buffer; fixed.
+06072002 - Manpages! Finally installed Doxygen and scratched together a
+           Doxyfile. After some revision to physfs.h, we've got a rather
+           nice API reference.
+06062002 - Fixed __PHYSFS_platformSeek() in archivers/posix.c. Implemented the
+           getLastModTime method in archivers/zip.c (returns legitimate info)
+           and archivers/grp.c (returns lastmodtime of GRPfile itself in the
+           physical filesystem). Put a 64-bit _llseek() version of the seek()
+           and tell() methods in platform/posix.c, but you need to hack (or
+           rather, fix) configure.in to enable it. From Greg on win32.c: Fixed
+           file enumerator function (needed a wildcard '*' specification), CD
+           enumeration only reports CDs that have media, getLastModTime() has
+           been implemented.
+06012002 - Added -Wall to debug builds. Removed ANSI stdio calls from
+           platform/posix.c, and replaced them with actual POSIX calls (that
+           is, fopen() became open(), fseek() became lseek(), etc...)
+05272002 - Added some explicit casts when calling malloc() in platform/posix.c
+05252002 - Added John Hall's file modification time patch, and added a
+           getlastmodtime command to test_physfs. Corrected error reporting
+           for missing files a little bit. Changed build system to only try
+           building beos.cpp if on a BeOS system (since we need a C++ compiler
+           available to do so). Implemented getLastModTime in macclassic.c.
+05242002 - Upped version to 0.1.6 (not officially released yet).
+05232002 - Fixed the build system to always package the complete source, not
+           just what we built for a given system, when doing a "make dist".
+           Updated INSTALL. Wrote BeOS platform code (platform/beos.cpp).
+           Split unix.c into unix.c and posix.c. Linux and BeOS both share
+           posix.c, although I don't think it's completely POSIX compliant at
+           this point (not that it matters much).
+05212002 - Cleaned up some FIXMEs.
+05202002 - Added .cvsignore files.
+05162002 - Edward Rudd also caught an embarrassing screwup by me in
+           unix.c: the open-for-append call was using "wb+" instead of
+           "ab" when calling fopen(). Doh!
+05152002 - configure script now deals with systems that have a readline
+           lib, but require it to be linked with curses. Thanks to Edward
+           Rudd for the patch.
+05102002 - A trimmed-down zlib 1.1.4 is now included in the source distro, for
+           use by win32, MacOS, and Unix systems that don't have it installed
+           on the system. Autoconf support! Initial attempt at this. Lots of
+           stuff may be very broken.
+05082002 - From Greg: More win32 work. Library is now 95% functional on win32.
+           Only known win32 problem is that the CD drives are reported whether
+           they contain a disc or not).
+05062002 - From Greg: Win32 boxes without the latest Platform SDK can now
+           #define DISABLE_NT_SUPPORT. Other fixes.
+04242002 - Updated win32 info in INSTALL to discuss Platform SDK issues.
+04202002 - Added a (very) quick and (very) dirty http server to the
+           extras directory (public domain), as another example of using
+           the library.
+04192002 - Corrected some win32 info in INSTALL. Changed Makefile to
+           package releases as .tar.gz instead of .tar.bz2.
+04122002 - Some win32 cleanups and fixes across several files. Upped
+           version to 0.1.5.
+04082002 - Fixed problem when calling __PHYSFS_setError before PHYSFS_init.
+04062002 - Added MacOS info, etc to INSTALL. Patched unix.c and
+           test_physfs.c to compile on Darwin again.
+04052002 - Added byte ordering API. Byte ordering fixes in grp.c, and some
+           cleanups in unzip.c. Mac work is more or less complete.
+04042002 - Mac work continues. Almost complete, now. test_physfs now has
+           tests for write, append, and filelength, and most of the
+           commands can tolerate a quoted argument (although this is
+           hacky, it's good enough for these purposes). Upped test_physfs
+           version to 0.1.1. Added a malloc-failure check in the Unix
+           CD-ROM detection code.
+04032002 - PHYSFS_init always makes sure the calling thread initializes its
+           error state. Win32 codebase is updated with mutex implementation
+           (thanks, Greg!).
+04022002 - Mac work continues. Found a bug where we put a double dir
+           separator in if we had to resort to the fallback userdir (if
+           __PHYSFS_platformGetUserDir() returned NULL to calculateUserDir().
+           Made note of potential infinite recursion in platform driver docs.
+04012002 - (_NOT_ an April Fool's Joke:) Started working on MacOS Classic
+           port. Added skeleton.c to platform directory. Minor patches to
+           get things compiling on Mac (notably, DirInfo conflicts with
+           a type exposed by MacOS's namespace-polluting API, and some
+           typecasting issues). Found a call to ferror() I had missed in
+           unzip.c.
+03302002 - Mutexes! PhysicsFS should be thread safe now, so long as you
+           don't try to do something like close a file at the same time as
+           you are reading from it in another thread. All reasonable race
+           conditions should now be gone, but the new code will need some
+           eyeballing before we install it on life support systems or anything.
+           The mutex abstraction is implemented in unix.c, win32.c will be
+           updated shortly.
+03292002 - Fixed a potential problem in ZIP_realpath() and some byte order
+           issues in zip.c. Converted unzip.c to use physfs file i/o
+           abstractions. Converted CHANGELOG to list latest entries first.
+03242002 - Added __PHYSFS_platformInit() and __PHYSFS_platformDeinit(). Win32
+           improvements by Gregory S. Read. Added PHYSFS_[us]int(8|16|32)
+           types...this breaks binary compatibility with previous PhysicsFS
+           releases! Added platform specific i/o functions, so we don't have
+           to rely on stdio anymore. Updated TODO with my comments on the
+           physfs mailing list. 1.0, here we come! Removed race condition from
+           grp.c and converted to file i/o abstraction layer calls from stdio.
+           Tons of other fixes and enhancements.
+03202002 - Patched platform/win32.c to compile.
+03152002 - PHYSFS_setSaneConfig() now handles failure to set the write dir
+           better. Patched makefile to link the test program. Changed all the
+           "write" functions to get data from a "const" buffer. Added an
+           "extras" dir, which currently contains PhysFS->SDL_RWops glue code.
+03052002 - Made unix.c's timeslice implementation more portable, and added a
+           Darwin-specific means to detect CDs (thanks to Patrick Stein).
+           Minor cleanup in win32.c (changed "for (; condition ;)" into
+           "while (condition)" ...)
+11142001 - Removed a redundant error check in platform/win32.c
+10092001 - Syntax fixes in dir.c, a FIXME in grp.c, and a "cat" command in
+           the test program. Apparently I had accidentally removed a rather
+           crucial line from dir.c a few revisions ago, and no one noticed. :(
+           Fixed. The win32 userdir will default to the base dir, now.
+09252001 - Changed API: PHYSFS_setSaneConfig() takes an organization name, and
+           sets up less directories. Be warned. Fixes from David Hedbor:
+           make setSaneConfig() set write directory correctly if it had to
+           create the directory, and make sure that the writing functions
+           get used in dir.c when a file is opened for writing/appending.
+           Updated CREDITS.
+09142001 - David Hedbor submitted a patch to handle a case where the
+           current working directory has been deleted out from under the
+           process (both in platform/unix.c and physfs.c itself). Thanks,
+           David! Added a CREDITS file. Changed the format of the author field
+           in PHYSFS_ArchiveInfo to put the email address between "<>" instead
+           of "()" chars. Updated TODO. make install now deletes previous
+           revisions of the library. Changed version to 0.1.4.
+09012001 - Happy September. Moved the Visual C project files and the zlib
+           source to a separate download. Look for it at
+           http://icculus.org/physfs/downloads/physfs-win32-support.zip ...
+           Updated the INSTALL doc for Win32 building. Rewrote win32.c's
+           __PHYSFS_platformRealPath() to not rely on Visual C's runtime lib,
+           which was the last Cygwin incompatibility (although the Makefile
+           needs to be updated to build a DLL under Cygwin). Tinkered with the
+           Makefile a little, but it needs more work. Started working on a
+           MacOS version. All I have is CodeWarrior 4, which is way out of
+           date, and (for what is supposed to be an ultra-user-friendly
+           environment) is completely uninituitive to me. Still, managed to
+           get most everything compiling, which improved the quality of the
+           code somewhat). Haven't tried to compile the zipfile support, and
+           I still can't link the library. Dunno what the hell I'm supposed
+           to do there. Isn't Unix supposed to be hard compared to this?
+08312001 - Built PhysicsFS on Mandrake 8.0 for the PowerPC. Compiles clean,
+           but there's at least one byte-ordering issue in zip.c that needs
+           to be fixed.
+08292001 - win32.c calculates the base dir with GetModuleFileName() first, now,
+           and falls back to SearchPath() if there were problems. Changed an
+           occurence of _MAX_PATH to MAX_PATH, so both CygWin and Visual C can
+           handle it.
+08282001 - win32.c now checks HOMEDRIVE, HOMEPATH, and HOME when calculating
+           the userdir. Added include files that make it a little closer to
+           compiling under Cygwin. Added a TODO file. Fixed unix.c's
+           __PHYSFS_platformCalcBaseDir() so that it actually works. Fixed
+           Makefile so that it links the test program properly.
+           Changed version to 0.1.3.
+08232001 - Fixed a potential free()ing of a NULL pointer in
+           __PHYSFS_platformEnumerateFiles() in platform/unix.c. Added
+           platform/win32.c. Other cleanups to get this compiling with
+           Visual C and CygWin. Added BAIL_MACRO for times when we were doing
+           BAIL_IF_MACRO(1, ...). Abstracted mkdir() in the platform drivers.
+           Added GRP setting output to showcfg in the Makefile. Updated INSTALL
+           with license info and Win32 build instructions. Dependency on the
+           readline library in test_physfs.c is now optional.
+           Changed version to 0.1.2.
+08072001 - Changed version to 0.1.1.
+08062001 - Added CD-ROM detection code to the unix platform driver.
+08012001 - Added a safety memset in error setting, fixed URLs and email addr.
+07282001 - Initial release.
+
+--ryan. (icculus@icculus.org)
+
+/* end of CHANGELOG ... */
+
diff --git a/src/unison/physfs-1.1.1/CMakeLists.txt b/src/unison/physfs-1.1.1/CMakeLists.txt
new file mode 100644 (file)
index 0000000..418a337
--- /dev/null
@@ -0,0 +1,383 @@
+# 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 1.1.1)
+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)
+
+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)
+        ADD_DEFINITIONS(-fvisibility=hidden)
+    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/7zBuffer.c
+    lzma/7zCrc.c
+    lzma/7zDecode.c
+    lzma/7zExtract.c
+    lzma/7zHeader.c
+    lzma/7zIn.c
+    lzma/7zItem.c
+    lzma/7zMethodID.c
+    lzma/LzmaDecode.c
+    lzma/LzmaStateDecode.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)
+    SET(OPTIONAL_LIBRARY_LIBS ${OPTIONAL_LIBRARY_LIBS} be root)
+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)
+        ELSE(HAVE_PTHREAD_H)
+            ADD_DEFINITIONS(-DPHYSFS_NO_PTHREADS_SUPPORT=1)
+        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)
+    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})
+    INCLUDE_DIRECTORIES(lzma)
+    ADD_DEFINITIONS(-D_LZMA_IN_CB=1)
+    ADD_DEFINITIONS(-D_LZMA_PROB32=1)
+    ADD_DEFINITIONS(-D_LZMA_SYSTEM_SIZE_T=1)
+    ADD_DEFINITIONS(-D_SZ_ONE_DIRECTORY=1)
+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)
+    CHECK_INCLUDE_FILE(zlib.h HAVE_ZLIB_H)
+    IF(HAVE_ZLIB_H)
+        CHECK_LIBRARY_EXISTS("z" "inflate" "" HAVE_LIBZ)
+        IF(HAVE_LIBZ)
+            SET(HAVE_SYSTEM_ZLIB TRUE)
+        ENDIF(HAVE_LIBZ)
+    ENDIF(HAVE_ZLIB_H)
+
+    IF(HAVE_SYSTEM_ZLIB)
+        OPTION(PHYSFS_INTERNAL_ZLIB "Link own zlib instead of system library" FALSE)
+    ELSE(HAVE_SYSTEM_ZLIB)
+        SET(PHYSFS_INTERNAL_ZLIB TRUE)
+    ENDIF(HAVE_SYSTEM_ZLIB)
+
+    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} z)
+    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)
+    CHECK_INCLUDE_FILE(readline/readline.h HAVE_READLINE_H)
+    CHECK_INCLUDE_FILE(readline/history.h HAVE_HISTORY_H)
+    IF(HAVE_READLINE_H AND HAVE_HISTORY_H)
+        SET(CMAKE_REQUIRED_LIBRARIES curses)
+        CHECK_LIBRARY_EXISTS("readline" "readline" "" HAVE_LIBREADLINE)
+        CHECK_LIBRARY_EXISTS("readline" "history" "" HAVE_LIBHISTORY)
+        IF(HAVE_LIBREADLINE AND HAVE_LIBHISTORY)
+            SET(HAVE_SYSTEM_READLINE TRUE)
+            SET(TEST_PHYSFS_LIBS ${TEST_PHYSFS_LIBS} " " readline curses)
+            ADD_DEFINITIONS(-DPHYSFS_HAVE_READLINE=1)
+        ENDIF(HAVE_LIBREADLINE AND HAVE_LIBHISTORY)
+    ENDIF(HAVE_READLINE_H AND HAVE_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." TRUE)
+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
+        ARCHIVE DESTINATION lib)
+INSTALL(FILES physfs.h DESTINATION include)
+
+FIND_PACKAGE(Doxygen)
+IF(DOXYGEN_FOUND)
+    ADD_CUSTOM_TARGET(docs ${DOXYGEN_EXECUTABLE} COMMENT "Building documentation")
+ELSE(DOXYGEN_FOUND)
+    MESSAGE(STATUS "Doxygen not found. You won't be able to build documentation.")
+ENDIF(DOXYGEN_FOUND)
+
+IF(UNIX)
+    ADD_CUSTOM_TARGET(dist ./extras/makedist.sh ${PHYSFS_VERSION} COMMENT "Building source 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 ...
+
diff --git a/src/unison/physfs-1.1.1/CREDITS.txt b/src/unison/physfs-1.1.1/CREDITS.txt
new file mode 100644 (file)
index 0000000..105631c
--- /dev/null
@@ -0,0 +1,95 @@
+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
+
+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
+
+Bug fixes:
+    Jörg Walter
+
+Windows .rc file,
+7zip/lzma archiver:
+    Dennis Schridde
+
+OS/2 updates:
+    Dave Yeo
+
+Other stuff:
+    Your name here! Patches go to icculus@icculus.org ...
+
+/* end of CREDITS.txt ... */
+
diff --git a/src/unison/physfs-1.1.1/Doxyfile b/src/unison/physfs-1.1.1/Doxyfile
new file mode 100644 (file)
index 0000000..0954d7a
--- /dev/null
@@ -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.
+
+PROJECT_NUMBER         = 1.1.0
+
+# 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
diff --git a/src/unison/physfs-1.1.1/INSTALL.txt b/src/unison/physfs-1.1.1/INSTALL.txt
new file mode 100644 (file)
index 0000000..7e89ac9
--- /dev/null
@@ -0,0 +1,149 @@
+
+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.
+
+Run "cmake ." in the root of the source directory 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.
+
+Primary Unix development is done with GNU/Linux, but PhysicsFS is known to
+ work out of the box with several flavors of Unix. It it doesn't work, patches
+ to get it running can be sent to icculus@icculus.org.
+
+
+
+BeOS:
+
+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 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 icculus@icculus.org ...
+
+If someone is willing to maintain prebuilt PhysicsFS DLLs, I'd like to hear
+from you; send an email to icculus@icculus.org ...
+
+
+
+PocketPC/WindowsCE:
+
+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 almost a decade at this point, none of the hardware
+ they've shipped will boot it for almost as many years, and finding
+ developer tools for it is becoming almost impossible. As the switch to Intel
+ hardware has removed the "Classic" emulation environment, it was time to
+ remove support from PhysicsFS. That being said, the PhysicsFS 1.0 branch can
+ still target back to Mac OS 8.5, so you can use that if you need support for
+ this legacy OS. We still very much support Mac OS X, though: see below.
+
+
+
+MAC OS X:
+
+You will need CMake (http://www.cmake.org/) 2.4 or later installed.
+
+You can either generate a Unix makefile with CMake, or generate an Xcode
+ project, whichever makes you more comfortable.
+
+PowerPC and Intel Macs should both be supported.
+
+If someone is willing to maintain prebuilt PhysicsFS Shared Libraries for
+ Mac OS X, I'd like to hear from you; send an email to icculus@icculus.org.
+
+
+
+OS/2:
+
+You need Innotek GCC and libc installed (or kLIBC). I tried this on a stock
+ Warp 4 install, no fixpaks. You need to install link386.exe (Selective
+ Install, "link object modules" option). Once klibc and GCC are installed
+ correctly, unpack the source to PhysicsFS and run the script
+ file "makeos2.cmd". I know this isn't ideal, but I wanted to have this build
+ without users having to hunt down a "make" program.
+
+Someone please port CMake to OS/2. Ideally I'd like to be able to target
+ Innotek GCC and OpenWatcom with CMake.
+
+If someone is willing to maintain prebuilt PhysicsFS Shared Libraries for
+ OS/2, I'd like to hear from you; send an email to icculus@icculus.org.
+
+
+
+OTHER PLATFORMS:
+
+Many Unix-like platforms might "just work" with CMake. Some of these platforms
+ are known to have worked at one time, but have not been heavily tested, if
+ tested at all. PhysicsFS is, as far as we know, 64-bit and byteorder clean,
+ and is known to compile on several compilers across many platforms. To
+ implement a new platform or archiver, please read the heavily-commented
+ physfs_internal.h and look in the platform/ and archiver/ directories for
+ examples.
+
+--ryan. (icculus@icculus.org)
+
diff --git a/src/unison/physfs-1.1.1/LICENSE.txt b/src/unison/physfs-1.1.1/LICENSE.txt
new file mode 100644 (file)
index 0000000..3f0223b
--- /dev/null
@@ -0,0 +1,29 @@
+
+   Copyright (c) 2003 Ryan C. Gordon and others.
+
+   This software is provided 'as-is', without any express or implied warranty.
+   In no event will the authors be held liable for any damages arising from
+   the use of this software.
+
+   Permission is granted to anyone to use this software for any purpose,
+   including commercial applications, and to alter it and redistribute it
+   freely, subject to the following restrictions:
+
+   1. The origin of this software must not be misrepresented; you must not
+   claim that you wrote the original software. If you use this software in a
+   product, an acknowledgment in the product documentation would be
+   appreciated but is not required.
+
+   2. Altered source versions must be plainly marked as such, and must not be
+   misrepresented as being the original software.
+
+   3. This notice may not be removed or altered from any source distribution.
+
+       Ryan C. Gordon <icculus@icculus.org>
+
+
+(Please note that 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.)
+
diff --git a/src/unison/physfs-1.1.1/TODO.txt b/src/unison/physfs-1.1.1/TODO.txt
new file mode 100644 (file)
index 0000000..9425051
--- /dev/null
@@ -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 ...
+
diff --git a/src/unison/physfs-1.1.1/archivers/dir.c b/src/unison/physfs-1.1.1/archivers/dir.c
new file mode 100644 (file)
index 0000000..a580743
--- /dev/null
@@ -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 <icculus@icculus.org>",
+    "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 ... */
+
diff --git a/src/unison/physfs-1.1.1/archivers/grp.c b/src/unison/physfs-1.1.1/archivers/grp.c
new file mode 100644 (file)
index 0000000..820a881
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+ * 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)
+{
+    GRPentry *a = (GRPentry *) _a;
+    return(strcmp(a[one].name, a[two].name));
+} /* grp_entry_cmp */
+
+
+static void grp_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 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));
+} /* 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 <icculus@icculus.org>",
+    "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 ... */
+
diff --git a/src/unison/physfs-1.1.1/archivers/hog.c b/src/unison/physfs-1.1.1/archivers/hog.c
new file mode 100644 (file)
index 0000000..136b7cb
--- /dev/null
@@ -0,0 +1,506 @@
+/*
+ * 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)
+{
+    HOGentry *a = (HOGentry *) _a;
+    return(__PHYSFS_stricmpASCII(a[one].name, a[two].name));
+} /* hog_entry_cmp */
+
+
+static void hog_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 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));
+} /* 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 <btb@icculus.org>",
+    "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 ... */
+
diff --git a/src/unison/physfs-1.1.1/archivers/lzma.c b/src/unison/physfs-1.1.1/archivers/lzma.c
new file mode 100644 (file)
index 0000000..1f52620
--- /dev/null
@@ -0,0 +1,693 @@
+/*
+ * LZMA support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file is 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 "physfs.h"
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+#ifndef _LZMA_IN_CB
+#define _LZMA_IN_CB
+/* Use callback for input data */
+#endif
+
+/* #define _LZMA_OUT_READ */
+/* Use read function for output data */
+
+#ifndef _LZMA_PROB32
+#define _LZMA_PROB32
+/* It can increase speed on some 32-bit CPUs,
+   but memory usage will be doubled in that case */
+#endif
+
+#ifndef _LZMA_SYSTEM_SIZE_T
+#define _LZMA_SYSTEM_SIZE_T
+/* Use system's size_t. You can use it to enable 64-bit sizes supporting */
+#endif
+
+#include "7zIn.h"
+#include "7zCrc.h"
+#include "7zExtract.h"
+
+
+/* 7z internal from 7zIn.c */
+int TestSignatureCandidate(Byte *testBytes);
+
+
+typedef struct _CFileInStream
+{
+    ISzInStream InStream;
+    void *File;
+} CFileInStream;
+
+/*
+ * In LZMA the archive is splited in blocks, those are called folders
+ * Set by LZMA_read()
+*/
+typedef struct _LZMAfolder
+{
+    PHYSFS_uint8 *cache; /* Cached folder */
+    PHYSFS_uint32 size; /* Size of folder */
+    PHYSFS_uint32 index; /* Index of folder in archive */
+    PHYSFS_uint32 references; /* Number of files using this block */
+} LZMAfolder;
+
+/*
+ * Set by LZMA_openArchive(), except folder which gets it's values
+ *  in LZMA_read()
+ */
+typedef struct _LZMAarchive
+{
+    struct _LZMAentry *firstEntry; /* Used for cleanup on shutdown */
+    struct _LZMAentry *lastEntry;
+    LZMAfolder *folder; /* Array of folders */
+    CArchiveDatabaseEx db; /* For 7z: Database */
+    CFileInStream stream; /* For 7z: Input file incl. read and seek callbacks */
+} LZMAarchive;
+
+/* Set by LZMA_openRead(), except offset which is set by LZMA_read() */
+typedef struct _LZMAentry
+{
+    struct _LZMAentry *next; /* Used for cleanup on shutdown */
+    struct _LZMAentry *previous;
+    LZMAarchive *archive; /* Link to corresponding archive */
+    CFileItem *file; /* For 7z: File info, eg. name, size */
+    PHYSFS_uint32 fileIndex; /* Index of file in archive */
+    PHYSFS_uint32 folderIndex; /* Index of folder in archive */
+    size_t offset; /* Offset in folder */
+    PHYSFS_uint64 position; /* Current "virtual" position in file */
+} LZMAentry;
+
+
+/* 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
+
+#define kBufferSize (1 << 12)
+static Byte g_Buffer[kBufferSize];  /* !!! FIXME: not thread safe! */
+
+SZ_RESULT SzFileReadImp(void *object, void **buffer, size_t maxReqSize,
+                        size_t *processedSize)
+{
+    CFileInStream *s = (CFileInStream *)object;
+    PHYSFS_sint64 processedSizeLoc;
+    if (maxReqSize > kBufferSize)
+        maxReqSize = kBufferSize;
+    processedSizeLoc = __PHYSFS_platformRead(s->File, g_Buffer, 1, maxReqSize);
+    *buffer = g_Buffer;
+    if (processedSize != NULL)
+        *processedSize = (size_t) processedSizeLoc;
+    return SZ_OK;
+} /* SzFileReadImp */
+
+#else
+
+SZ_RESULT SzFileReadImp(void *object, void *buffer, size_t size,
+                        size_t *processedSize)
+{
+    CFileInStream *s = (CFileInStream *)object;
+    size_t processedSizeLoc = __PHYSFS_platformRead(s->File, buffer, 1, size);
+    if (processedSize != 0)
+        *processedSize = processedSizeLoc;
+    return SZ_OK;
+} /* SzFileReadImp */
+
+#endif
+
+SZ_RESULT SzFileSeekImp(void *object, CFileSize pos)
+{
+    CFileInStream *s = (CFileInStream *) object;
+    if (__PHYSFS_platformSeek(s->File, (PHYSFS_uint64) pos))
+        return SZ_OK;
+    return SZE_FAIL;
+} /* SzFileSeekImp */
+
+
+/*
+ * Find entry 'name' in 'archive' and report the 'index' back
+ */
+static int lzma_find_entry(LZMAarchive *archive, const char *name,
+                           PHYSFS_uint32 *index)
+{
+    for (*index = 0; *index < archive->db.Database.NumFiles; (*index)++)
+    {
+        if (strcmp(archive->db.Database.Files[*index].Name, name) == 0)
+            return 1;
+    } /* for */
+
+    BAIL_MACRO(ERR_NO_SUCH_FILE, 0);
+} /* lzma_find_entry */
+
+
+/*
+ * Report the first file index of a directory
+ */
+static PHYSFS_sint32 lzma_find_start_of_dir(LZMAarchive *archive,
+                                            const char *path,
+                                            int stop_on_first_find)
+{
+    PHYSFS_sint32 lo = 0;
+    PHYSFS_sint32 hi = (PHYSFS_sint32) (archive->db.Database.NumFiles - 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 = archive->db.Database.Files[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);
+} /* lzma_find_start_of_dir */
+
+
+/*
+ * 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)
+{
+    LZMAentry *entry = (LZMAentry *) opaque;
+
+    PHYSFS_sint64 wantedSize = objSize*objCount;
+    PHYSFS_sint64 remainingSize = entry->file->Size - entry->position;
+
+    size_t fileSize;
+    ISzAlloc allocImp;
+    ISzAlloc allocTempImp;
+
+    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 */
+
+    /* Prepare callbacks for 7z */
+    allocImp.Alloc = SzAllocPhysicsFS;
+    allocImp.Free = SzFreePhysicsFS;
+
+    allocTempImp.Alloc = SzAllocPhysicsFS;
+    allocTempImp.Free = SzFreePhysicsFS;
+
+    /* Only decompress the folder if it is not allready cached */
+    if (entry->archive->folder[entry->folderIndex].cache == NULL)
+    {
+        size_t tmpsize = entry->archive->folder[entry->folderIndex].size;
+        int rc = lzma_err(SzExtract(
+            &entry->archive->stream.InStream, /* compressed data */
+            &entry->archive->db,
+            entry->fileIndex,
+            /* Index of cached folder, will be changed by SzExtract */
+            &entry->archive->folder[entry->folderIndex].index,
+            /* Cache for decompressed folder, allocated/freed by SzExtract */
+            &entry->archive->folder[entry->folderIndex].cache,
+            /* Size of cache, will be changed by SzExtract */
+            &tmpsize,
+            /* Offset of this file inside the cache, set by SzExtract */
+            &entry->offset,
+            &fileSize, /* Size of this file */
+            &allocImp,
+            &allocTempImp));
+
+        entry->archive->folder[entry->folderIndex].size = tmpsize;
+        if (rc != SZ_OK)
+            return -1;
+    } /* if */
+
+    /* Copy wanted bytes over from cache to outBuffer */
+/* !!! FIXME: strncpy for non-string data? */
+       strncpy(outBuffer,
+            (void*) (entry->archive->folder[entry->folderIndex].cache +
+                     entry->offset + entry->position),
+            (size_t) wantedSize);
+    entry->position += wantedSize;
+    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)
+{
+    LZMAentry *entry = (LZMAentry *) opaque;
+    return (entry->position >= entry->file->Size);
+} /* LZMA_eof */
+
+
+static PHYSFS_sint64 LZMA_tell(fvoid *opaque)
+{
+    LZMAentry *entry = (LZMAentry *) opaque;
+    return (entry->position);
+} /* LZMA_tell */
+
+
+static int LZMA_seek(fvoid *opaque, PHYSFS_uint64 offset)
+{
+    LZMAentry *entry = (LZMAentry *) opaque;
+
+    BAIL_IF_MACRO(offset < 0, ERR_SEEK_OUT_OF_RANGE, 0);
+    BAIL_IF_MACRO(offset > entry->file->Size, ERR_PAST_EOF, 0);
+
+    entry->position = offset;
+    return 1;
+} /* LZMA_seek */
+
+
+static PHYSFS_sint64 LZMA_fileLength(fvoid *opaque)
+{
+    LZMAentry *entry = (LZMAentry *) opaque;
+    return (entry->file->Size);
+} /* LZMA_fileLength */
+
+
+static int LZMA_fileClose(fvoid *opaque)
+{
+    LZMAentry *entry = (LZMAentry *) opaque;
+
+    /* Fix archive */
+    if (entry == entry->archive->firstEntry)
+        entry->archive->firstEntry = entry->next;
+    if (entry == entry->archive->lastEntry)
+        entry->archive->lastEntry = entry->previous;
+
+    /* Fix neighbours */
+    if (entry->previous != NULL)
+        entry->previous->next = entry->next;
+    if (entry->next != NULL)
+        entry->next->previous = entry->previous;
+
+    entry->archive->folder[entry->folderIndex].references--;
+    if (entry->archive->folder[entry->folderIndex].references == 0)
+    {
+        allocator.Free(entry->archive->folder[entry->folderIndex].cache);
+        entry->archive->folder[entry->folderIndex].cache = NULL;
+    }
+
+    allocator.Free(entry);
+    entry = NULL;
+
+    return(1);
+} /* LZMA_fileClose */
+
+
+static int LZMA_isArchive(const char *filename, int forWriting)
+{
+    PHYSFS_uint8 sig[k7zSignatureSize];
+    PHYSFS_uint8 res;
+    void *in;
+
+    BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, 0);
+
+    in = __PHYSFS_platformOpenRead(filename);
+    BAIL_IF_MACRO(in == NULL, NULL, 0);
+
+    if (__PHYSFS_platformRead(in, sig, k7zSignatureSize, 1) != 1)
+        BAIL_MACRO(NULL, 0);
+
+    /* Test whether sig is the 7z signature */
+    res = TestSignatureCandidate(sig);
+
+    __PHYSFS_platformClose(in);
+
+    return res;
+} /* LZMA_isArchive */
+
+
+static void *LZMA_openArchive(const char *name, int forWriting)
+{
+    PHYSFS_uint64 len;
+    LZMAarchive *archive = NULL;
+    ISzAlloc allocImp;
+    ISzAlloc allocTempImp;
+
+    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);
+
+    archive->firstEntry = NULL;
+    archive->lastEntry = NULL;
+
+    if ((archive->stream.File = __PHYSFS_platformOpenRead(name)) == NULL)
+    {
+        allocator.Free(archive);
+        return NULL;
+    } /* if */
+
+    /* Prepare structs for 7z */
+    archive->stream.InStream.Read = SzFileReadImp;
+    archive->stream.InStream.Seek = SzFileSeekImp;
+
+    allocImp.Alloc = SzAllocPhysicsFS;
+    allocImp.Free = SzFreePhysicsFS;
+
+    allocTempImp.Alloc = SzAllocPhysicsFS;
+    allocTempImp.Free = SzFreePhysicsFS;
+
+    InitCrcTable();
+    SzArDbExInit(&archive->db);
+    if (lzma_err(SzArchiveOpen(&archive->stream.InStream, &archive->db,
+                               &allocImp, &allocTempImp)) != SZ_OK)
+    {
+        __PHYSFS_platformClose(archive->stream.File);
+        allocator.Free(archive);
+        return NULL;
+    } /* if */
+
+    len = archive->db.Database.NumFolders * sizeof (LZMAfolder);
+    archive->folder = (LZMAfolder *) allocator.Malloc(len);
+    BAIL_IF_MACRO(archive->folder == NULL, 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->folder, 0, (size_t) len);
+
+    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, 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 LZMA_enumerateFiles(dvoid *opaque, const char *dname,
+                                int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+                                const char *origdir, void *callbackdata)
+{
+    LZMAarchive *archive = (LZMAarchive *) opaque;
+    PHYSFS_sint32 dlen;
+    PHYSFS_sint32 dlen_inc;
+    PHYSFS_sint32 max;
+    PHYSFS_sint32 i;
+
+    i = lzma_find_start_of_dir(archive, 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) archive->db.Database.NumFiles;
+    while (i < max)
+    {
+        char *add;
+        char *ptr;
+        PHYSFS_sint32 ln;
+        char *e = archive->db.Database.Files[i].Name;
+        if ((dlen) && ((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 = archive->db.Database.Files[i].Name;
+            if ((strncmp(e, e_new, ln) != 0) || (e_new[ln] != '/'))
+                break;
+        } /* while */
+    } /* while */
+} /* LZMA_enumerateFiles */
+
+
+static int LZMA_exists(dvoid *opaque, const char *name)
+{
+    LZMAarchive *archive = (LZMAarchive *) opaque;
+    PHYSFS_uint32 index = 0;
+    return(lzma_find_entry(archive, name, &index));
+} /* LZMA_exists */
+
+
+static PHYSFS_sint64 LZMA_getLastModTime(dvoid *opaque,
+                                         const char *name,
+                                         int *fileExists)
+{
+    /* !!! FIXME: Lacking support in the LZMA C SDK. */
+    BAIL_MACRO(ERR_NOT_IMPLEMENTED, -1);
+} /* LZMA_getLastModTime */
+
+
+static int LZMA_isDirectory(dvoid *opaque, const char *name, int *fileExists)
+{
+    LZMAarchive *archive = (LZMAarchive *) opaque;
+    PHYSFS_uint32 index = 0;
+
+    *fileExists = lzma_find_entry(archive, name, &index);
+
+    return(archive->db.Database.Files[index].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;
+    LZMAentry *entry = NULL;
+    PHYSFS_uint32 fileIndex = 0;
+    PHYSFS_uint32 folderIndex = 0;
+
+    *fileExists = lzma_find_entry(archive, name, &fileIndex);
+    BAIL_IF_MACRO(!*fileExists, ERR_NO_SUCH_FILE, NULL);
+
+    folderIndex = archive->db.FileIndexToFolderIndexMap[fileIndex];
+    BAIL_IF_MACRO(folderIndex == (PHYSFS_uint32)-1, ERR_UNKNOWN_ERROR, NULL);
+
+    entry = (LZMAentry *) allocator.Malloc(sizeof (LZMAentry));
+    BAIL_IF_MACRO(entry == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+    entry->fileIndex = fileIndex;
+    entry->folderIndex = folderIndex;
+    entry->archive = archive;
+    entry->file = archive->db.Database.Files + entry->fileIndex;
+    entry->offset = 0; /* Offset will be set by LZMA_read() */
+    entry->position = 0;
+
+    archive->folder[folderIndex].references++;
+
+    entry->next = NULL;
+    entry->previous = entry->archive->lastEntry;
+    if (entry->previous != NULL)
+        entry->previous->next = entry;
+    entry->archive->lastEntry = entry;
+    if (entry->archive->firstEntry == NULL)
+        entry->archive->firstEntry = entry;
+
+    return(entry);
+} /* 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;
+    LZMAentry *entry = archive->firstEntry;
+    LZMAentry *tmpEntry = entry;
+
+    while (entry != NULL)
+    {
+        tmpEntry = entry->next;
+        LZMA_fileClose(entry);
+        entry = tmpEntry;
+    } /* while */
+
+    SzArDbExFree(&archive->db, SzFreePhysicsFS);
+    __PHYSFS_platformClose(archive->stream.File);
+
+    /* Free the cache which might have been allocated by LZMA_read() */
+    allocator.Free(archive->folder);
+    allocator.Free(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 <devurandom@gmx.net>",
+    "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 ... */
+
diff --git a/src/unison/physfs-1.1.1/archivers/mvl.c b/src/unison/physfs-1.1.1/archivers/mvl.c
new file mode 100644 (file)
index 0000000..650b49b
--- /dev/null
@@ -0,0 +1,463 @@
+/*
+ * 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)
+{
+    MVLentry *a = (MVLentry *) _a;
+    return(strcmp(a[one].name, a[two].name));
+} /* mvl_entry_cmp */
+
+
+static void mvl_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 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));
+} /* 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 <btb@icculus.org>",
+    "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 ... */
+
diff --git a/src/unison/physfs-1.1.1/archivers/qpak.c b/src/unison/physfs-1.1.1/archivers/qpak.c
new file mode 100644 (file)
index 0000000..f4aa7e7
--- /dev/null
@@ -0,0 +1,622 @@
+/*
+ * 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)
+{
+    QPAKentry *a = (QPAKentry *) _a;
+    return(QPAK_strcmp(a[one].name, a[two].name));
+} /* qpak_entry_cmp */
+
+
+static void qpak_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 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));
+} /* 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]);
+            else
+                hi = middle - 1;  /* adjust search params, try again. */
+        } /* 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 <icculus@icculus.org>",
+    "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 ... */
+
diff --git a/src/unison/physfs-1.1.1/archivers/wad.c b/src/unison/physfs-1.1.1/archivers/wad.c
new file mode 100644 (file)
index 0000000..fddc22a
--- /dev/null
@@ -0,0 +1,526 @@
+/*
+ * 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)
+{
+    WADentry *a = (WADentry *) _a;
+    return(strcmp(a[one].name, a[two].name));
+} /* wad_entry_cmp */
+
+
+static void wad_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 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));
+} /* 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;
+    char lastDirectory[9];
+
+    lastDirectory[8] = 0; /* Make sure lastDirectory stays null-terminated. */
+
+    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 <traviswells@mchsi.com>",
+    "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 ... */
+
diff --git a/src/unison/physfs-1.1.1/archivers/zip.c b/src/unison/physfs-1.1.1/archivers/zip.c
new file mode 100644 (file)
index 0000000..33de475
--- /dev/null
@@ -0,0 +1,1441 @@
+/*
+ * 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_sint32 i = 0;
+    PHYSFS_sint64 filelen;
+    PHYSFS_sint64 filepos;
+    PHYSFS_sint32 maxread;
+    PHYSFS_sint32 totalread = 0;
+    int found = 0;
+    PHYSFS_uint32 extra = 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);
+            *((PHYSFS_uint32 *) (&buf[maxread - 4])) = extra;
+            totalread += maxread - 4;
+        } /* if */
+        else
+        {
+            if (__PHYSFS_platformRead(in, buf, maxread, 1) != 1)
+                return(-1);
+            totalread += maxread;
+        } /* else */
+
+        extra = *((PHYSFS_uint32 *) (&buf[0]));
+
+        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);
+    } /* 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. */
+        {
+            if (isDir != NULL)
+            {
+                *isDir = (thispath[pathlen] == '/');
+                if (*isDir)
+                    return(NULL);
+            } /* if */
+
+            if (thispath[pathlen] == '\0') /* found entry? */
+                return(&a[middle]);
+            else
+                hi = middle - 1;  /* adjust search params, try again. */
+        } /* if */
+    } /* 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;
+        } /* 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(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)
+{
+    ZIPentry *a = (ZIPentry *) _a;
+    return(strcmp(a[one].name, a[two].name));
+} /* zip_entry_cmp */
+
+
+static void zip_entry_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 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));
+} /* 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;
+    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 <icculus@icculus.org>",
+    "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 ... */
+
diff --git a/src/unison/physfs-1.1.1/extras/PhysFS.NET/AssemblyInfo.cs b/src/unison/physfs-1.1.1/extras/PhysFS.NET/AssemblyInfo.cs
new file mode 100755 (executable)
index 0000000..2ba4887
--- /dev/null
@@ -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("")]
diff --git a/src/unison/physfs-1.1.1/extras/PhysFS.NET/PhysFS.NET.csproj b/src/unison/physfs-1.1.1/extras/PhysFS.NET/PhysFS.NET.csproj
new file mode 100755 (executable)
index 0000000..d271946
--- /dev/null
@@ -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>
+
diff --git a/src/unison/physfs-1.1.1/extras/PhysFS.NET/PhysFS.NET.sln b/src/unison/physfs-1.1.1/extras/PhysFS.NET/PhysFS.NET.sln
new file mode 100755 (executable)
index 0000000..93b4480
--- /dev/null
@@ -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
diff --git a/src/unison/physfs-1.1.1/extras/PhysFS.NET/PhysFS.cs b/src/unison/physfs-1.1.1/extras/PhysFS.NET/PhysFS.cs
new file mode 100755 (executable)
index 0000000..bad6172
--- /dev/null
@@ -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;
+      }
+   }
+}
diff --git a/src/unison/physfs-1.1.1/extras/PhysFS.NET/PhysFSFileStream.cs b/src/unison/physfs-1.1.1/extras/PhysFS.NET/PhysFSFileStream.cs
new file mode 100755 (executable)
index 0000000..725b2c4
--- /dev/null
@@ -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;
+   }
+}
\ No newline at end of file
diff --git a/src/unison/physfs-1.1.1/extras/PhysFS.NET/PhysFS_DLL.cs b/src/unison/physfs-1.1.1/extras/PhysFS.NET/PhysFS_DLL.cs
new file mode 100755 (executable)
index 0000000..6d7d9dc
--- /dev/null
@@ -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);
+   }
+}
diff --git a/src/unison/physfs-1.1.1/extras/PhysFS.NET/README.txt b/src/unison/physfs-1.1.1/extras/PhysFS.NET/README.txt
new file mode 100755 (executable)
index 0000000..aa1874c
--- /dev/null
@@ -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.    
\ No newline at end of file
diff --git a/src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/App.ico b/src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/App.ico
new file mode 100755 (executable)
index 0000000..3a5525f
Binary files /dev/null and b/src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/App.ico differ
diff --git a/src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/AssemblyInfo.cs b/src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/AssemblyInfo.cs
new file mode 100755 (executable)
index 0000000..9f89a32
--- /dev/null
@@ -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("")]
diff --git a/src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/TestApp.csproj b/src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/TestApp.csproj
new file mode 100755 (executable)
index 0000000..45af063
--- /dev/null
@@ -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>
+
diff --git a/src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/TestApp.sln b/src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/TestApp.sln
new file mode 100755 (executable)
index 0000000..5c3463d
--- /dev/null
@@ -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
diff --git a/src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/TestAppForm.cs b/src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/TestAppForm.cs
new file mode 100755 (executable)
index 0000000..8688bff
--- /dev/null
@@ -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));
+      }
+       }
+}
diff --git a/src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/TestAppForm.resx b/src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/TestAppForm.resx
new file mode 100755 (executable)
index 0000000..daf6eab
--- /dev/null
@@ -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>
\ No newline at end of file
diff --git a/src/unison/physfs-1.1.1/extras/abs-file.h b/src/unison/physfs-1.1.1/extras/abs-file.h
new file mode 100644 (file)
index 0000000..c7e7b49
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * stdio/physfs abstraction layer 2003-04-02
+ *
+ * Adam D. Moss <adam@gimp.org> <aspirin@icculus.org>
+ *
+ * These wrapper macros and functions are designed to allow a program
+ * to perform file I/O with identical semantics and syntax regardless
+ * of whether PhysicsFS is being used or not.
+ */
+#ifndef _ABS_FILE_H
+#define _ABS_FILE_H
+/*
+PLEASE NOTE: This license applies to abs-file.h ONLY (to make it clear that
+you may embed this wrapper code within commercial software); PhysicsFS itself
+is (at the time of writing) released under a different license with
+additional restrictions.
+
+Copyright (C) 2002-2003 Adam D. Moss (the "Author").  All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is fur-
+nished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
+NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON-
+NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the Author of the
+Software shall not be used in advertising or otherwise to promote the sale,
+use or other dealings in this Software without prior written authorization
+from the Author.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+/*
+ * API:
+ *
+ * Macro/function       use like stdio equivalent...
+ * --------------       ----------------------------
+ * MY_FILETYPE          FILE
+ * MY_OPEN_FOR_READ     fopen(..., "rb")
+ * MY_READ              fread(...)
+ * MY_CLOSE             fclose(...)
+ * MY_GETC              fgetc(...)
+ * MY_GETS              fgets(...)
+ * MY_ATEOF             feof(...)
+ * MY_TELL              ftell(...)
+ * MY_SEEK              fseek(..., SEEK_SET)
+ * MY_REWIND            rewind(...)
+ * MY_SETBUFFER         (not a standard for stdio, does nothing there)
+ */
+
+/*
+ * Important DEFINEs:
+ *   It is important to define these consistantly across the various
+ *   compilation modules of your program if you wish to exchange file
+ *   handles between them.
+ *
+ *   USE_PHYSFS: Define USE_PHYSFS if PhysicsFS is being used; note that if
+ *     you do intend to use PhysicsFS then you will still need to initialize
+ *     PhysicsFS yourself and set up its search-paths.
+ *
+ * Optional DEFINEs:
+ *
+ *   PHYSFS_DEFAULT_READ_BUFFER <bytes>: If set then abs-file.h sets the
+ *     PhysicsFS buffer size to this value whenever you open a file.  You
+ *     may over-ride this on a per-filehandle basis by using the
+ *     MY_SETBUFFER() macro (which simply does nothing when not using
+ *     PhysicsFS).  If you have not defined this value explicitly then
+ *     abs-file.h will default to the same default buffer size as used by
+ *     stdio if it can be determined, or 8192 bytes otherwise.
+ */
+#ifndef PHYSFS_DEFAULT_READ_BUFFER
+#ifdef BUFSIZ
+#define PHYSFS_DEFAULT_READ_BUFFER BUFSIZ
+#else
+#define PHYSFS_DEFAULT_READ_BUFFER 8192
+#endif
+#endif
+
+#ifdef USE_PHYSFS
+
+#include <physfs.h>
+#define MY_FILETYPE PHYSFS_File
+#define MY_SETBUFFER(fp,size) PHYSFS_setBuffer(fp,size)
+#define MY_READ(p,s,n,fp) PHYSFS_read(fp,p,s,n)
+#if PHYSFS_DEFAULT_READ_BUFFER
+static MY_FILETYPE* MY_OPEN_FOR_READ(const char *const filename)
+{
+  MY_FILETYPE *const file = PHYSFS_openRead(filename);
+  if (file) {
+    MY_SETBUFFER(file, PHYSFS_DEFAULT_READ_BUFFER);
+  }
+  return file;
+}
+#else
+#define MY_OPEN_FOR_READ(fn) PHYSFS_openRead(fn)
+#endif
+static int MY_GETC(MY_FILETYPE *const fp) {
+  unsigned char c;
+  /*if (PHYSFS_eof(fp)) {
+    return EOF;
+  }
+  MY_READ(&c, 1, 1, fp);*/
+  if (MY_READ(&c, 1, 1, fp) != 1) {
+    return EOF;
+  }
+  return c;
+}
+static char * MY_GETS(char * const str, const int size, 
+                      MY_FILETYPE *const fp) {
+  int i = 0;
+  int c;
+  do {
+    if (i == size-1) {
+      break;
+    }
+    c = MY_GETC(fp);
+    if (c == EOF) {
+      break;
+    }
+    str[i++] = c;
+  } while (c != '\0' && 
+      c != -1 && 
+      c != '\n');
+  str[i] = '\0';
+  if (i == 0) {
+    return NULL;
+  }
+  return str;
+}
+#define MY_CLOSE(fp) PHYSFS_close(fp)
+#define MY_ATEOF(fp) PHYSFS_eof(fp)
+#define MY_TELL(fp) PHYSFS_tell(fp)
+#define MY_SEEK(fp,o) PHYSFS_seek(fp,o)
+#define MY_REWIND(fp) MY_SEEK(fp,0)
+
+#else
+
+#define MY_FILETYPE FILE
+#define MY_READ(p,s,n,fp) fread(p,s,n,fp)
+#define MY_OPEN_FOR_READ(n) fopen(n, "rb")
+#define MY_GETC(fp) fgetc(fp)
+#define MY_GETS(str,size,fp) fgets(str,size,fp)
+#define MY_CLOSE(fp) fclose(fp)
+#define MY_ATEOF(fp) feof(fp)
+#define MY_TELL(fp) ftell(fp)
+#define MY_SEEK(fp,o) fseek(fp,o, SEEK_SET)
+#define MY_REWIND(fp) rewind(fp)
+/*static void MY_SETBUFFER(const MY_FILETYPE *const file, const int num) { }*/
+#define MY_SETBUFFER(fp,size)
+#endif
+
+#endif
diff --git a/src/unison/physfs-1.1.1/extras/casefolding.txt b/src/unison/physfs-1.1.1/extras/casefolding.txt
new file mode 100644 (file)
index 0000000..f25d9bf
--- /dev/null
@@ -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
diff --git a/src/unison/physfs-1.1.1/extras/globbing.c b/src/unison/physfs-1.1.1/extras/globbing.c
new file mode 100644 (file)
index 0000000..bb83d6a
--- /dev/null
@@ -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 ... */
+
diff --git a/src/unison/physfs-1.1.1/extras/globbing.h b/src/unison/physfs-1.1.1/extras/globbing.h
new file mode 100644 (file)
index 0000000..3784413
--- /dev/null
@@ -0,0 +1,77 @@
+/** \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.
+ */
+
+
+/**
+ * \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);
+
+/* end of globbing.h ... */
+
diff --git a/src/unison/physfs-1.1.1/extras/ignorecase.c b/src/unison/physfs-1.1.1/extras/ignorecase.c
new file mode 100644 (file)
index 0000000..16e807d
--- /dev/null
@@ -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, '/'))
+    {
+        *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 ... */
+
diff --git a/src/unison/physfs-1.1.1/extras/ignorecase.h b/src/unison/physfs-1.1.1/extras/ignorecase.h
new file mode 100644 (file)
index 0000000..1d98355
--- /dev/null
@@ -0,0 +1,75 @@
+/** \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.
+ */
+
+
+/**
+ * \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);
+
+/* end of ignorecase.h ... */
+
diff --git a/src/unison/physfs-1.1.1/extras/makecasefoldhashtable.pl b/src/unison/physfs-1.1.1/extras/makecasefoldhashtable.pl
new file mode 100755 (executable)
index 0000000..7be2e93
--- /dev/null
@@ -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 ...
+
diff --git a/src/unison/physfs-1.1.1/extras/makedist.sh b/src/unison/physfs-1.1.1/extras/makedist.sh
new file mode 100755 (executable)
index 0000000..3f62f4d
--- /dev/null
@@ -0,0 +1,54 @@
+#!/bin/sh
+
+# This shell script is roughly equivalent to what "make dist" did in the
+#  autotools build system and is called from a custom CMake target.
+
+# !!! FIXME: This code sort of sucks. Consider using CPack instead...
+
+if [ ! -f ./CMakeLists.txt ]; then
+    echo "you are in the wrong place."
+    exit 1
+fi
+
+if [ -z "$1" ]; then
+    echo "Wrong arguments."
+    exit 2
+fi
+
+set -e
+
+VERSION="$1"
+BASENAME="physfs-$VERSION"
+TARBALL="$BASENAME.tar.gz"
+TMPCPDIR="../9sdkujy75jv932-physfstmp-$VERSION"
+CPDIR="$TMPCPDIR/$BASENAME"
+
+echo "Packing PhysicsFS $VERSION source tarball..."
+echo " + Setting up scratch dir..."
+rm -rf $TMPCPDIR
+mkdir $TMPCPDIR
+mkdir $CPDIR
+
+echo " + Making copy of source tree in scratch dir..."
+cp -R . $CPDIR/
+echo " + Deleting cruft..."
+pushd $CPDIR >/dev/null
+rm -rf `svn propget svn:ignore .`
+rm -rf `svn status |grep '?' |sed -s 's/\?//'`
+popd >/dev/null
+rm -rf `find $CPDIR -type d -name '.svn'`
+echo " + Deleting Subversion metadata..."
+rm -rf `find $CPDIR -type d -name '.svn'`
+echo " + Fixing up permissions..."
+chmod -R a+rw $CPDIR
+chmod a+x `find $CPDIR -type d`
+echo " + Building final tarball..."
+rm -f $TARBALL
+tar -czf $TARBALL -C $TMPCPDIR $BASENAME
+echo " + Cleaning up..."
+rm -rf $TMPCPDIR
+echo " + All done! Packed to '$TARBALL' ..."
+set +e
+
+exit 0
+
diff --git a/src/unison/physfs-1.1.1/extras/physfs_rb/installer.rb b/src/unison/physfs-1.1.1/extras/physfs_rb/installer.rb
new file mode 100644 (file)
index 0000000..687808d
--- /dev/null
@@ -0,0 +1,103 @@
+# $Id: installer.rb 585 2003-07-21 03:46:50Z icculus $
+
+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
diff --git a/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/extconf.rb b/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/extconf.rb
new file mode 100644 (file)
index 0000000..f344059
--- /dev/null
@@ -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"
diff --git a/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/install.rb b/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/install.rb
new file mode 100644 (file)
index 0000000..29bd454
--- /dev/null
@@ -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
diff --git a/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/make_install_test.sh b/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/make_install_test.sh
new file mode 100755 (executable)
index 0000000..ac616c8
--- /dev/null
@@ -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
\ No newline at end of file
diff --git a/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/physfs.rb b/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/physfs.rb
new file mode 100644 (file)
index 0000000..88da331
--- /dev/null
@@ -0,0 +1,121 @@
+#
+# PhysicsFS - ruby interface
+#
+# Author: Ed Sinjiashvili (slimb@vlinkmail.com)
+# 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 #
diff --git a/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/physfsrwops.c b/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/physfsrwops.c
new file mode 100644 (file)
index 0000000..8dd23bf
--- /dev/null
@@ -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. (icculus@icculus.org).
+ */
+
+#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 ... */
+
diff --git a/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/physfsrwops.h b/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/physfsrwops.h
new file mode 100644 (file)
index 0000000..5ff519a
--- /dev/null
@@ -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. (icculus@icculus.org).
+ */
+
+#ifndef _INCLUDE_PHYSFSRWOPS_H_
+#define _INCLUDE_PHYSFSRWOPS_H_
+
+#include "physfs.h"
+#include "SDL.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Open a platform-independent filename for reading, and make it accessible
+ *  via an SDL_RWops structure. The file will be closed in PhysicsFS when the
+ *  RWops is closed. PhysicsFS should be configured to your liking before
+ *  opening files through this method.
+ *
+ *   @param filename File to open in platform-independent notation.
+ *  @return A valid SDL_RWops structure on success, NULL on error. Specifics
+ *           of the error can be gleaned from PHYSFS_getLastError().
+ */
+__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 ... */
+
diff --git a/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_physfs.c b/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_physfs.c
new file mode 100644 (file)
index 0000000..043d911
--- /dev/null
@@ -0,0 +1,462 @@
+/*
+ * PhysicsFS - ruby interface
+ * 
+ * Author::  Ed Sinjiashvili (slimb@vlinkmail.com)
+ * 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:
+*/
diff --git a/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_physfs.h b/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_physfs.h
new file mode 100644 (file)
index 0000000..ca82036
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * PhysicsFS - ruby interface
+ * 
+ * Author::  Ed Sinjiashvili (slimb@vlinkmail.com)
+ * License:: LGPL
+ */
+
+#ifndef __RB__PHYSFS__H__
+#define __RB__PHYSFS__H__
+
+extern VALUE modulePhysfs;
+
+#endif
diff --git a/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_physfs_file.c b/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_physfs_file.c
new file mode 100644 (file)
index 0000000..3e50880
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * PhysicsFS File abstraction - ruby interface
+ * 
+ * Author::  Ed Sinjiashvili (slimb@vlinkmail.com)
+ * 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);
+}
diff --git a/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_physfs_file.h b/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_physfs_file.h
new file mode 100644 (file)
index 0000000..5cc1b21
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * PhysicsFS File abstraction - ruby interface
+ * 
+ * Author::  Ed Sinjiashvili (slimb@vlinkmail.com)
+ * 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
diff --git a/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_sdl_rwops.c b/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_sdl_rwops.c
new file mode 100644 (file)
index 0000000..6574906
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * SDL_RWops - ruby interface
+ *
+ * Author::    Ed Sinjiashvili (slimb@vlinkmail.com)
+ * 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);
+}
diff --git a/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_sdl_rwops.h b/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_sdl_rwops.h
new file mode 100644 (file)
index 0000000..05f51bc
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * SDL_RWops - ruby interface
+ *
+ * Author::    Ed Sinjiashvili (slimb@vlinkmail.com)
+ * 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
diff --git a/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/test/test_physfs.rb b/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/test/test_physfs.rb
new file mode 100644 (file)
index 0000000..3f194c1
--- /dev/null
@@ -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
+
+
+
+
diff --git a/src/unison/physfs-1.1.1/extras/physfshttpd.c b/src/unison/physfs-1.1.1/extras/physfshttpd.c
new file mode 100644 (file)
index 0000000..d092073
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * This is a quick and dirty HTTP server that uses PhysicsFS to retrieve
+ *  files. It is not robust at all, probably buggy, and definitely poorly
+ *  designed. It's just meant to show that it can be done.
+ *
+ * Basically, you compile this code, and run it:
+ *   ./physfshttpd archive1.zip archive2.zip /path/to/a/real/dir etc...
+ *
+ * The files are appended in order to the PhysicsFS search path, and when
+ *  a client request comes it, it looks for the file in said search path.
+ *
+ * My goal was to make this work in less than 300 lines of C, so again, it's
+ *  not to be used for any serious purpose. Patches to make this application
+ *  suck less will be readily and gratefully accepted.
+ *
+ * Command line I used to build this on Linux:
+ *  gcc -Wall -Werror -g -o bin/physfshttpd extras/physfshttpd.c -lphysfs
+ *
+ * License: this code is public domain. I make no warranty that it is useful,
+ *  correct, harmless, or environmentally safe.
+ *
+ * This particular file may be used however you like, including copying it
+ *  verbatim into a closed-source project, exploiting it commercially, and
+ *  removing any trace of my name from the source (although I hope you won't
+ *  do that). I welcome enhancements and corrections to this file, but I do
+ *  not require you to send me patches if you make changes. This code has
+ *  NO WARRANTY.
+ *
+ * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
+ *  Please see LICENSE.txt in the root of the source tree.
+ *
+ *  This file was written by Ryan C. Gordon. (icculus@icculus.org).
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#ifndef LACKING_SIGNALS
+#include <signal.h>
+#endif
+
+#ifndef LACKING_PROTOENT
+#include <netdb.h>
+#endif
+
+#include "physfs.h"
+
+
+#define DEFAULT_PORTNUM  6667
+
+typedef struct
+{
+    int sock;
+    struct sockaddr *addr;
+    socklen_t addrlen;
+} http_args;
+
+
+static char *txt404 =
+"HTTP/1.0 404 Not Found\n"
+"Connection: close\n"
+"Content-type: text/html\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 ... */
+
diff --git a/src/unison/physfs-1.1.1/extras/physfsrwops.c b/src/unison/physfs-1.1.1/extras/physfsrwops.c
new file mode 100644 (file)
index 0000000..a6c8815
--- /dev/null
@@ -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. (icculus@icculus.org).
+ */
+
+#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 ... */
+
diff --git a/src/unison/physfs-1.1.1/extras/physfsrwops.h b/src/unison/physfs-1.1.1/extras/physfsrwops.h
new file mode 100644 (file)
index 0000000..406fba6
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * This code provides a glue layer between PhysicsFS and Simple Directmedia
+ *  Layer's (SDL) RWops i/o abstraction.
+ *
+ * License: this code is public domain. I make no warranty that it is useful,
+ *  correct, harmless, or environmentally safe.
+ *
+ * This particular file may be used however you like, including copying it
+ *  verbatim into a closed-source project, exploiting it commercially, and
+ *  removing any trace of my name from the source (although I hope you won't
+ *  do that). I welcome enhancements and corrections to this file, but I do
+ *  not require you to send me patches if you make changes. This code has
+ *  NO WARRANTY.
+ *
+ * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
+ *  Please see LICENSE.txt in the root of the source tree.
+ *
+ * SDL falls under the LGPL license. You can get SDL at http://www.libsdl.org/
+ *
+ *  This file was written by Ryan C. Gordon. (icculus@icculus.org).
+ */
+
+#ifndef _INCLUDE_PHYSFSRWOPS_H_
+#define _INCLUDE_PHYSFSRWOPS_H_
+
+#include "physfs.h"
+#include "SDL.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Open a platform-independent filename for reading, and make it accessible
+ *  via an SDL_RWops structure. The file will be closed in PhysicsFS when the
+ *  RWops is closed. PhysicsFS should be configured to your liking before
+ *  opening files through this method.
+ *
+ *   @param filename File to open in platform-independent notation.
+ *  @return A valid SDL_RWops structure on success, NULL on error. Specifics
+ *           of the error can be gleaned from PHYSFS_getLastError().
+ */
+__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 ... */
+
diff --git a/src/unison/physfs-1.1.1/extras/physfsunpack.c b/src/unison/physfs-1.1.1/extras/physfsunpack.c
new file mode 100644 (file)
index 0000000..1d26502
--- /dev/null
@@ -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 ... */
+
diff --git a/src/unison/physfs-1.1.1/extras/selfextract.c b/src/unison/physfs-1.1.1/extras/selfextract.c
new file mode 100644 (file)
index 0000000..3568d01
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * This code shows how to read a zipfile included in an app's binary.
+ *
+ * License: this code is public domain. I make no warranty that it is useful,
+ *  correct, harmless, or environmentally safe.
+ *
+ * This particular file may be used however you like, including copying it
+ *  verbatim into a closed-source project, exploiting it commercially, and
+ *  removing any trace of my name from the source (although I hope you won't
+ *  do that). I welcome enhancements and corrections to this file, but I do
+ *  not require you to send me patches if you make changes. This code has
+ *  NO WARRANTY.
+ *
+ * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
+ *  Please see LICENSE.txt in the root of the source tree.
+ *
+ *  This file was written by Ryan C. Gordon. (icculus@icculus.org).
+ */
+
+/*
+ * Compile this program and then attach a .zip file to the end of the
+ *  compiled binary.
+ *
+ * On Linux, something like this will build the final binary:
+ *   gcc -o selfextract.tmp selfextract.c -lphysfs && \
+ *   cat selfextract.tmp myzipfile.zip >> selfextract && \
+ *   chmod a+x selfextract && \
+ *   rm -f selfextract.tmp
+ *
+ * This may not work on all platforms, and it probably only works with
+ *  .zip files, since they are designed to be appended to another file.
+ */
+
+#include <stdio.h>
+#include "physfs.h"
+
+int main(int argc, char **argv)
+{
+    int rc = 0;
+
+    if (!PHYSFS_init(argv[0]))
+    {
+        printf("PHYSFS_init() failed: %s\n", PHYSFS_getLastError());
+        return(42);
+    } /* if */
+
+    rc = PHYSFS_addToSearchPath(argv[0], 0);
+    if (!rc)
+    {
+        printf("Couldn't find self-extract data: %s\n", PHYSFS_getLastError());
+        printf("This might mean you didn't append a zipfile to the binary.\n");
+        return(42);
+    } /* if */
+
+    char **files = PHYSFS_enumerateFiles("/");
+    char **i;
+    for (i = files; *i != NULL; i++)
+    {
+        const char *dirorfile = PHYSFS_isDirectory(*i) ? "Directory" : "File";
+        printf(" * %s '%s' is in root of attached data.\n", dirorfile, *i);
+    } /* for */
+    PHYSFS_freeList(files);
+
+    return(0);
+} /* main */
+
diff --git a/src/unison/physfs-1.1.1/lzma/7zAlloc.h b/src/unison/physfs-1.1.1/lzma/7zAlloc.h
new file mode 100644 (file)
index 0000000..4ca4170
--- /dev/null
@@ -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
diff --git a/src/unison/physfs-1.1.1/lzma/7zBuffer.c b/src/unison/physfs-1.1.1/lzma/7zBuffer.c
new file mode 100644 (file)
index 0000000..3c4b71e
--- /dev/null
@@ -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;
+}
diff --git a/src/unison/physfs-1.1.1/lzma/7zBuffer.h b/src/unison/physfs-1.1.1/lzma/7zBuffer.h
new file mode 100644 (file)
index 0000000..17e5906
--- /dev/null
@@ -0,0 +1,19 @@
+/* 7zBuffer.h */
+
+#ifndef __7Z_BUFFER_H
+#define __7Z_BUFFER_H
+
+#include <stddef.h>
+#include "7zTypes.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
diff --git a/src/unison/physfs-1.1.1/lzma/7zCrc.c b/src/unison/physfs-1.1.1/lzma/7zCrc.c
new file mode 100644 (file)
index 0000000..9773840
--- /dev/null
@@ -0,0 +1,76 @@
+/* 7zCrc.c */
+
+#include "7zCrc.h"
+
+#define kCrcPoly 0xEDB88320
+
+UInt32 g_CrcTable[256];
+
+void InitCrcTable()
+{
+  UInt32 i;
+  for (i = 0; i < 256; i++)
+  {
+    UInt32 r = i;
+    int j;
+    for (j = 0; j < 8; j++)
+      if (r & 1) 
+        r = (r >> 1) ^ kCrcPoly;
+      else     
+        r >>= 1;
+    g_CrcTable[i] = r;
+  }
+}
+
+void CrcInit(UInt32 *crc) { *crc = 0xFFFFFFFF; }
+UInt32 CrcGetDigest(UInt32 *crc) { return *crc ^ 0xFFFFFFFF; } 
+
+void CrcUpdateByte(UInt32 *crc, Byte b)
+{
+  *crc = g_CrcTable[((Byte)(*crc)) ^ b] ^ (*crc >> 8);
+}
+
+void CrcUpdateUInt16(UInt32 *crc, UInt16 v)
+{
+  CrcUpdateByte(crc, (Byte)v);
+  CrcUpdateByte(crc, (Byte)(v >> 8));
+}
+
+void CrcUpdateUInt32(UInt32 *crc, UInt32 v)
+{
+  int i;
+  for (i = 0; i < 4; i++)
+    CrcUpdateByte(crc, (Byte)(v >> (8 * i)));
+}
+
+void CrcUpdateUInt64(UInt32 *crc, UInt64 v)
+{
+  int i;
+  for (i = 0; i < 8; i++)
+  {
+    CrcUpdateByte(crc, (Byte)(v));
+    v >>= 8;
+  }
+}
+
+void CrcUpdate(UInt32 *crc, const void *data, size_t size)
+{
+  UInt32 v = *crc;
+  const Byte *p = (const Byte *)data;
+  for (; size > 0 ; size--, p++)
+    v = g_CrcTable[((Byte)(v)) ^ *p] ^ (v >> 8);
+  *crc = v;
+}
+
+UInt32 CrcCalculateDigest(const void *data, size_t size)
+{
+  UInt32 crc;
+  CrcInit(&crc);
+  CrcUpdate(&crc, data, size);
+  return CrcGetDigest(&crc);
+}
+
+int CrcVerifyDigest(UInt32 digest, const void *data, size_t size)
+{
+  return (CrcCalculateDigest(data, size) == digest);
+}
diff --git a/src/unison/physfs-1.1.1/lzma/7zCrc.h b/src/unison/physfs-1.1.1/lzma/7zCrc.h
new file mode 100644 (file)
index 0000000..adcc563
--- /dev/null
@@ -0,0 +1,24 @@
+/* 7zCrc.h */
+
+#ifndef __7Z_CRC_H
+#define __7Z_CRC_H
+
+#include <stddef.h>
+
+#include "7zTypes.h"
+
+extern UInt32 g_CrcTable[256];
+void InitCrcTable();
+
+void CrcInit(UInt32 *crc);
+UInt32 CrcGetDigest(UInt32 *crc);
+void CrcUpdateByte(UInt32 *crc, Byte v);
+void CrcUpdateUInt16(UInt32 *crc, UInt16 v);
+void CrcUpdateUInt32(UInt32 *crc, UInt32 v);
+void CrcUpdateUInt64(UInt32 *crc, UInt64 v);
+void CrcUpdate(UInt32 *crc, const void *data, size_t size);
+UInt32 CrcCalculateDigest(const void *data, size_t size);
+int CrcVerifyDigest(UInt32 digest, const void *data, size_t size);
+
+#endif
diff --git a/src/unison/physfs-1.1.1/lzma/7zDecode.c b/src/unison/physfs-1.1.1/lzma/7zDecode.c
new file mode 100644 (file)
index 0000000..bda09cb
--- /dev/null
@@ -0,0 +1,150 @@
+/* 7zDecode.c */
+
+#include "7zDecode.h"
+#ifdef _SZ_ONE_DIRECTORY
+#include "LzmaDecode.h"
+#else
+#include "../../Compress/LZMA_C/LzmaDecode.h"
+#endif
+
+CMethodID k_Copy = { { 0x0 }, 1 };
+CMethodID k_LZMA = { { 0x3, 0x1, 0x1 }, 3 };
+
+#ifdef _LZMA_IN_CB
+
+typedef struct _CLzmaInCallbackImp
+{
+  ILzmaInCallback InCallback;
+  ISzInStream *InStream;
+  size_t Size;
+} CLzmaInCallbackImp;
+
+int LzmaReadImp(void *object, const unsigned char **buffer, SizeT *size)
+{
+  CLzmaInCallbackImp *cb = (CLzmaInCallbackImp *)object;
+  size_t processedSize;
+  SZ_RESULT res;
+  *size = 0;
+  res = cb->InStream->Read((void *)cb->InStream, (void **)buffer, cb->Size, &processedSize);
+  *size = (SizeT)processedSize;
+  if (processedSize > cb->Size)
+    return (int)SZE_FAIL;
+  cb->Size -= processedSize;
+  if (res == SZ_OK)
+    return 0;
+  return (int)res;
+}
+
+#endif
+
+SZ_RESULT SzDecode(const CFileSize *packSizes, const CFolder *folder,
+    #ifdef _LZMA_IN_CB
+    ISzInStream *inStream,
+    #else
+    const Byte *inBuffer,
+    #endif
+    Byte *outBuffer, size_t outSize,
+    size_t *outSizeProcessed, ISzAlloc *allocMain)
+{
+  UInt32 si;
+  size_t inSize = 0;
+  CCoderInfo *coder;
+  if (folder->NumPackStreams != 1)
+    return SZE_NOTIMPL;
+  if (folder->NumCoders != 1)
+    return SZE_NOTIMPL;
+  coder = folder->Coders;
+  *outSizeProcessed = 0;
+
+  for (si = 0; si < folder->NumPackStreams; si++)
+    inSize += (size_t)packSizes[si];
+
+  if (AreMethodsEqual(&coder->MethodID, &k_Copy))
+  {
+    size_t i;
+    if (inSize != outSize)
+      return SZE_DATA_ERROR;
+    #ifdef _LZMA_IN_CB
+    for (i = 0; i < inSize;)
+    {
+      size_t j;
+      void *inBuffer;
+      size_t bufferSize;
+      RINOK(inStream->Read((void *)inStream,  (void **)&inBuffer, inSize - i, &bufferSize));
+      if (bufferSize == 0)
+        return SZE_DATA_ERROR;
+      if (bufferSize > inSize - i)
+        return SZE_FAIL;
+      *outSizeProcessed += bufferSize;
+      for (j = 0; j < bufferSize && i < inSize; j++, i++)
+        outBuffer[i] = ((Byte*)inBuffer)[j];
+    }
+    #else
+    for (i = 0; i < inSize; i++)
+      outBuffer[i] = inBuffer[i];
+    *outSizeProcessed = inSize;
+    #endif
+    return SZ_OK;
+  }
+
+  if (AreMethodsEqual(&coder->MethodID, &k_LZMA))
+  {
+    #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,
+        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);
+    *outSizeProcessed = (size_t)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 SZ_OK;
+  }
+  return SZE_NOTIMPL;
+}
diff --git a/src/unison/physfs-1.1.1/lzma/7zDecode.h b/src/unison/physfs-1.1.1/lzma/7zDecode.h
new file mode 100644 (file)
index 0000000..74bb180
--- /dev/null
@@ -0,0 +1,21 @@
+/* 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,
+    #else
+    const Byte *inBuffer,
+    #endif
+    Byte *outBuffer, size_t outSize, 
+    size_t *outSizeProcessed, ISzAlloc *allocMain);
+
+#endif
diff --git a/src/unison/physfs-1.1.1/lzma/7zExtract.c b/src/unison/physfs-1.1.1/lzma/7zExtract.c
new file mode 100644 (file)
index 0000000..6ef872c
--- /dev/null
@@ -0,0 +1,116 @@
+/* 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 unPackSize = SzFolderGetUnPackSize(folder);
+    #ifndef _LZMA_IN_CB
+    CFileSize packSize = SzArDbGetFolderFullPackSize(db, folderIndex);
+    Byte *inBuffer = 0;
+    size_t processedSize;
+    #endif
+    *blockIndex = folderIndex;
+    allocMain->Free(*outBuffer);
+    *outBuffer = 0;
+    
+    RINOK(inStream->Seek(inStream, SzArDbGetFolderStreamPos(db, folderIndex, 0)));
+    
+    #ifndef _LZMA_IN_CB
+    if (packSize != 0)
+    {
+      inBuffer = (Byte *)allocTemp->Alloc((size_t)packSize);
+      if (inBuffer == 0)
+        return SZE_OUTOFMEMORY;
+    }
+    res = inStream->Read(inStream, inBuffer, (size_t)packSize, &processedSize);
+    if (res == SZ_OK && processedSize != (size_t)packSize)
+      res = SZE_FAIL;
+    #endif
+    if (res == SZ_OK)
+    {
+      *outBufferSize = (size_t)unPackSize;
+      if (unPackSize != 0)
+      {
+        *outBuffer = (Byte *)allocMain->Alloc((size_t)unPackSize);
+        if (*outBuffer == 0)
+          res = SZE_OUTOFMEMORY;
+      }
+      if (res == SZ_OK)
+      {
+        size_t outRealSize;
+        res = SzDecode(db->Database.PackSizes + 
+          db->FolderStartPackStreamIndex[folderIndex], folder, 
+          #ifdef _LZMA_IN_CB
+          inStream,
+          #else
+          inBuffer, 
+          #endif
+          *outBuffer, (size_t)unPackSize, &outRealSize, allocTemp);
+        if (res == SZ_OK)
+        {
+          if (outRealSize == (size_t)unPackSize)
+          {
+            if (folder->UnPackCRCDefined)
+            {
+              if (!CrcVerifyDigest(folder->UnPackCRC, *outBuffer, (size_t)unPackSize))
+                res = SZE_FAIL;
+            }
+          }
+          else
+            res = SZE_FAIL;
+        }
+      }
+    }
+    #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 (!CrcVerifyDigest(fileItem->FileCRC, *outBuffer + *offset, *outSizeProcessed))
+          res = SZE_FAIL;
+      }
+    }
+  }
+  return res;
+}
diff --git a/src/unison/physfs-1.1.1/lzma/7zExtract.h b/src/unison/physfs-1.1.1/lzma/7zExtract.h
new file mode 100644 (file)
index 0000000..e9a4fb4
--- /dev/null
@@ -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
diff --git a/src/unison/physfs-1.1.1/lzma/7zHeader.c b/src/unison/physfs-1.1.1/lzma/7zHeader.c
new file mode 100644 (file)
index 0000000..3be4bc2
--- /dev/null
@@ -0,0 +1,5 @@
+/*  7zHeader.c */
+
+#include "7zHeader.h"
+
+Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
diff --git a/src/unison/physfs-1.1.1/lzma/7zHeader.h b/src/unison/physfs-1.1.1/lzma/7zHeader.h
new file mode 100644 (file)
index 0000000..0356aaa
--- /dev/null
@@ -0,0 +1,55 @@
+/* 7zHeader.h */
+
+#ifndef __7Z_HEADER_H
+#define __7Z_HEADER_H
+
+#include "7zTypes.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
diff --git a/src/unison/physfs-1.1.1/lzma/7zIn.c b/src/unison/physfs-1.1.1/lzma/7zIn.c
new file mode 100644 (file)
index 0000000..ab32ea9
--- /dev/null
@@ -0,0 +1,1282 @@
+/* 7zIn.c */
+
+#include "7zIn.h"
+#include "7zCrc.h"
+#include "7zDecode.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
+      */
+      while(1)
+      {
+        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];
+}
+
+CFileSize SzArDbGetFolderFullPackSize(CArchiveDatabaseEx *db, UInt32 folderIndex)
+{
+  UInt32 packStreamIndex = db->FolderStartPackStreamIndex[folderIndex];
+  CFolder *folder = db->Database.Folders + folderIndex;
+  CFileSize size = 0;
+  UInt32 i;
+  for (i = 0; i < folder->NumPackStreams; i++)
+    size += db->Database.PackSizes[packStreamIndex + i];
+  return size;
+}
+
+
+/*
+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 *inBuffer; // Dennis Schridde: Make this compile with -Wall -Werror. Was Byte* before.
+    size_t processedSize;
+    RINOK(inStream->Read(inStream, (void **)&inBuffer, size, &processedSize));
+    if (processedSize == 0 || processedSize > size)
+      return SZE_FAIL;
+    size -= processedSize;
+    do
+    {
+      *(data++) = *((Byte*)inBuffer);
+      inBuffer = ((Byte*) inBuffer) + 1;
+       }
+    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)
+{
+  int i;
+  *value = 0;
+  for (i = 0; i < 4; i++)
+  {
+    Byte b;
+    RINOK(SafeReadDirectByte(inStream, &b));
+    *value |= ((UInt32)b << (8 * i));
+  }
+  return SZ_OK;
+}
+
+SZ_RESULT SafeReadDirectUInt64(ISzInStream *inStream, UInt64 *value)
+{
+  int i;
+  *value = 0;
+  for (i = 0; i < 8; i++)
+  {
+    Byte b;
+    RINOK(SafeReadDirectByte(inStream, &b));
+    *value |= ((UInt32)b << (8 * i));
+  }
+  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)
+{
+  while(1)
+  {
+    UInt64 type;
+    RINOK(SzReadID(sd, &type));
+    if (type == k7zIdEnd)
+      break;
+    SzSkeepData(sd);
+  }
+  return SZ_OK;
+}
+
+SZ_RESULT SzWaitAttribute(CSzData *sd, UInt64 attribute)
+{
+  while(1)
+  {
+    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));
+  }
+
+  while(1)
+  {
+    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;
+    {
+      RINOK(SzReadByte(sd, &mainByte));
+      coder->MethodID.IDSize = (Byte)(mainByte & 0xF);
+      RINOK(SzReadBytes(sd, coder->MethodID.ID, coder->MethodID.IDSize));
+      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));
+    }
+  }
+
+  while(1)
+  {
+    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;
+
+  while(1)
+  {
+    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;
+  while(1)
+  {
+    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)
+{
+  while(1)
+  {
+    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 */
+    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);
+
+  while(1)
+  {
+    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;
+      }
+      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;
+  SZ_RESULT res = SzReadHeader2(sd, db,
+      &unPackSizes, &digestsDefined, &digests,
+      &emptyStreamVector, &emptyFileVector,
+      allocMain, allocTemp);
+  allocTemp->Free(unPackSizes);
+  allocTemp->Free(digestsDefined);
+  allocTemp->Free(digests);
+  allocTemp->Free(emptyStreamVector);
+  allocTemp->Free(emptyFileVector);
+  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;
+  size_t outRealSize;
+  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,
+          #else
+          *inBuffer,
+          #endif
+          outBuffer->Items, (size_t)unPackSize,
+          &outRealSize, allocTemp);
+  RINOK(res)
+  if (outRealSize != (UInt32)unPackSize)
+    return SZE_FAIL;
+  if (folder->UnPackCRCDefined)
+    if (!CrcVerifyDigest(folder->UnPackCRC, outBuffer->Items, (size_t)unPackSize))
+      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;
+  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));
+
+  CrcInit(&crc);
+  RINOK(SafeReadDirectUInt64(inStream, &nextHeaderOffset));
+  CrcUpdateUInt64(&crc, nextHeaderOffset);
+  RINOK(SafeReadDirectUInt64(inStream, &nextHeaderSize));
+  CrcUpdateUInt64(&crc, nextHeaderSize);
+  RINOK(SafeReadDirectUInt32(inStream, &nextHeaderCRC));
+  CrcUpdateUInt32(&crc, nextHeaderCRC);
+
+  pos = k7zStartHeaderSize;
+  db->ArchiveInfo.StartPositionAfterHeader = pos;
+
+  if (CrcGetDigest(&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)
+  {
+    if (CrcVerifyDigest(nextHeaderCRC, buffer.Items, (UInt32)nextHeaderSize))
+    {
+      while (1)
+      {
+        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;
+}
diff --git a/src/unison/physfs-1.1.1/lzma/7zIn.h b/src/unison/physfs-1.1.1/lzma/7zIn.h
new file mode 100644 (file)
index 0000000..6bfa2a7
--- /dev/null
@@ -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);
+CFileSize SzArDbGetFolderFullPackSize(CArchiveDatabaseEx *db, UInt32 folderIndex);
+
+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
diff --git a/src/unison/physfs-1.1.1/lzma/7zItem.c b/src/unison/physfs-1.1.1/lzma/7zItem.c
new file mode 100644 (file)
index 0000000..2a40805
--- /dev/null
@@ -0,0 +1,133 @@
+/* 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->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);
+}
diff --git a/src/unison/physfs-1.1.1/lzma/7zItem.h b/src/unison/physfs-1.1.1/lzma/7zItem.h
new file mode 100644 (file)
index 0000000..876539a
--- /dev/null
@@ -0,0 +1,90 @@
+/* 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);
+
+/* #define CArchiveFileTime UInt64 */
+
+typedef struct _CFileItem
+{
+  /*
+  CArchiveFileTime LastWriteTime;
+  CFileSize StartPos;
+  UInt32 Attributes; 
+  */
+  CFileSize Size;
+  UInt32 FileCRC;
+  char *Name;
+
+  Byte IsFileCRCDefined;
+  Byte HasStream;
+  Byte IsDirectory;
+  Byte IsAnti;
+  /*
+  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
diff --git a/src/unison/physfs-1.1.1/lzma/7zMethodID.c b/src/unison/physfs-1.1.1/lzma/7zMethodID.c
new file mode 100644 (file)
index 0000000..5047359
--- /dev/null
@@ -0,0 +1,14 @@
+/* 7zMethodID.c */
+
+#include "7zMethodID.h"
+
+int AreMethodsEqual(CMethodID *a1, CMethodID *a2)
+{
+  int i;
+  if (a1->IDSize != a2->IDSize)
+    return 0;
+  for (i = 0; i < a1->IDSize; i++)
+    if (a1->ID[i] != a2->ID[i])
+      return 0;
+  return 1;
+}
diff --git a/src/unison/physfs-1.1.1/lzma/7zMethodID.h b/src/unison/physfs-1.1.1/lzma/7zMethodID.h
new file mode 100644 (file)
index 0000000..162fcd1
--- /dev/null
@@ -0,0 +1,18 @@
+/* 7zMethodID.h */
+
+#ifndef __7Z_METHOD_ID_H
+#define __7Z_METHOD_ID_H
+
+#include "7zTypes.h"
+
+#define kMethodIDSize 15
+  
+typedef struct _CMethodID
+{
+  Byte ID[kMethodIDSize];
+  Byte IDSize;
+} CMethodID;
+
+int AreMethodsEqual(CMethodID *a1, CMethodID *a2);
+
+#endif
diff --git a/src/unison/physfs-1.1.1/lzma/7zTypes.h b/src/unison/physfs-1.1.1/lzma/7zTypes.h
new file mode 100644 (file)
index 0000000..60dd68c
--- /dev/null
@@ -0,0 +1,67 @@
+/* 7zTypes.h */
+
+#ifndef __COMMON_TYPES_H
+#define __COMMON_TYPES_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 
+
+/* #define _SZ_NO_INT_64 */
+/* define it your compiler doesn't support long long int */
+
+#ifndef _7ZIP_UINT64_DEFINED
+#define _7ZIP_UINT64_DEFINED
+#ifdef _SZ_NO_INT_64
+typedef unsigned long UInt64;
+#else
+#ifdef _MSC_VER
+typedef unsigned __int64 UInt64;
+#else
+typedef unsigned long long int UInt64;
+#endif
+#endif
+#endif
+
+
+/* #define _SZ_FILE_SIZE_64 */
+/* Use _SZ_FILE_SIZE_64 if you need support for files larger than 4 GB*/
+
+#ifndef CFileSize
+#ifdef _SZ_FILE_SIZE_64
+typedef UInt64 CFileSize; 
+#else
+typedef UInt32 CFileSize; 
+#endif
+#endif
+
+#define SZ_RESULT int
+
+#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)
+
+#define RINOK(x) { int __result_ = (x); if(__result_ != 0) return __result_; }
+
+#endif
diff --git a/src/unison/physfs-1.1.1/lzma/LZMA-LICENSE.txt b/src/unison/physfs-1.1.1/lzma/LZMA-LICENSE.txt
new file mode 100644 (file)
index 0000000..d4e0f9f
--- /dev/null
@@ -0,0 +1,94 @@
+(These are the licensing details for this directory, taken from lzma.txt in
+ the original source distribution. The basic gist is you can do what you want
+ with this code, including sell it in a closed-source app...changes to LZMA
+ itself must be released as source code, which in the case of PhysicsFS, you
+ can just point people to our source code repository unless you make further
+ changes yourself.  --ryan.)
+
+
+LZMA SDK 4.43
+-------------
+
+LZMA SDK   Copyright (C) 1999-2006 Igor Pavlov
+
+LZMA SDK provides the documentation, samples, header files, libraries, 
+and tools you need to develop applications that use LZMA compression.
+
+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.
+
+LZMA is an improved version of famous LZ77 compression algorithm. 
+It was improved in way of maximum increasing of compression ratio,
+keeping high decompression speed and low memory requirements for 
+decompressing.
+
+
+
+LICENSE
+-------
+
+LZMA SDK is available under any of the following licenses:
+
+1) GNU Lesser General Public License (GNU LGPL)
+2) Common Public License (CPL)
+3) Simplified license for unmodified code (read SPECIAL EXCEPTION) 
+4) Proprietary license 
+
+It means that you can select one of these four options and follow rules of that license.
+
+
+1,2) GNU LGPL and CPL licenses are pretty similar and both these
+licenses are classified as 
+ - "Free software licenses" at http://www.gnu.org/ 
+ - "OSI-approved" at http://www.opensource.org/
+
+
+3) SPECIAL EXCEPTION
+
+Igor Pavlov, as the author of this code, expressly permits you 
+to statically or dynamically link your code (or bind by name) 
+to the files from LZMA SDK without subjecting your linked 
+code to the terms of the CPL or GNU LGPL. 
+Any modifications or additions to files from LZMA SDK, however, 
+are subject to the GNU LGPL or CPL terms.
+
+SPECIAL EXCEPTION allows you to use LZMA SDK in applications with closed code, 
+while you keep LZMA SDK code unmodified.
+
+
+SPECIAL EXCEPTION #2: Igor Pavlov, as the author of this code, expressly permits 
+you to use this code under the same terms and conditions contained in the License 
+Agreement you have for any previous version of LZMA SDK developed by Igor Pavlov.
+
+SPECIAL EXCEPTION #2 allows owners of proprietary licenses to use latest version 
+of LZMA SDK as update for previous versions.
+
+
+SPECIAL EXCEPTION #3: Igor Pavlov, as the author of this code, expressly permits 
+you to use code of the following files: 
+BranchTypes.h, LzmaTypes.h, LzmaTest.c, LzmaStateTest.c, LzmaAlone.cpp, 
+LzmaAlone.cs, LzmaAlone.java
+as public domain code. 
+
+
+4) Proprietary license
+
+LZMA SDK also can be available under a proprietary license which 
+can include:
+
+1) Right to modify code without subjecting modified code to the 
+terms of the CPL or GNU LGPL
+2) Technical support for code
+
+To request such proprietary license or any additional consultations,
+send email message from that page:
+http://www.7-zip.org/support.html
+
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+You should have received a copy of the Common Public License
+along with this library.
diff --git a/src/unison/physfs-1.1.1/lzma/LzmaDecode.c b/src/unison/physfs-1.1.1/lzma/LzmaDecode.c
new file mode 100644 (file)
index 0000000..cb83453
--- /dev/null
@@ -0,0 +1,584 @@
+/*
+  LzmaDecode.c
+  LZMA Decoder (optimized for Speed version)
+  
+  LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
+  http://www.7-zip.org/
+
+  LZMA SDK is licensed under two licenses:
+  1) GNU Lesser General Public License (GNU LGPL)
+  2) Common Public License (CPL)
+  It means that you can select one of these two licenses and 
+  follow rules of that license.
+
+  SPECIAL EXCEPTION:
+  Igor Pavlov, as the author of this Code, expressly permits you to 
+  statically or dynamically link your Code (or bind by name) to the 
+  interfaces of this file without subjecting your linked Code to the 
+  terms of the CPL or GNU LGPL. Any modifications or additions 
+  to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#include "LzmaDecode.h"
+
+#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; }}
+
+#ifdef _LZMA_IN_CB
+
+#define RC_TEST { if (Buffer == BufferLim) \
+  { SizeT size; int result = InCallback->Read(InCallback, &Buffer, &size); if (result != LZMA_RESULT_OK) return result; \
+  BufferLim = Buffer + size; if (size == 0) return LZMA_RESULT_DATA_ERROR; }}
+
+#define RC_INIT Buffer = BufferLim = 0; RC_INIT2
+
+#else
+
+#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; }
+
+#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2
+#endif
+
+#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 RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \
+  { UpdateBit0(p); mi <<= 1; A0; } else \
+  { UpdateBit1(p); mi = (mi + mi) + 1; A1; } 
+  
+#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;)               
+
+#define RangeDecoderBitTreeDecode(probs, numLevels, res) \
+  { int i = numLevels; res = 1; \
+  do { CProb *p = probs + res; RC_GET_BIT(p, res) } while(--i != 0); \
+  res -= (1 << numLevels); }
+
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols) 
+
+
+#define kNumStates 12
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size)
+{
+  unsigned char prop0;
+  if (size < LZMA_PROPERTIES_SIZE)
+    return LZMA_RESULT_DATA_ERROR;
+  prop0 = propsData[0];
+  if (prop0 >= (9 * 5 * 5))
+    return LZMA_RESULT_DATA_ERROR;
+  {
+    for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5));
+    for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9);
+    propsRes->lc = prop0;
+    /*
+    unsigned char remainder = (unsigned char)(prop0 / 9);
+    propsRes->lc = prop0 % 9;
+    propsRes->pb = remainder / 5;
+    propsRes->lp = remainder % 5;
+    */
+  }
+
+  #ifdef _LZMA_OUT_READ
+  {
+    int i;
+    propsRes->DictionarySize = 0;
+    for (i = 0; i < 4; i++)
+      propsRes->DictionarySize += (UInt32)(propsData[1 + i]) << (i * 8);
+    if (propsRes->DictionarySize == 0)
+      propsRes->DictionarySize = 1;
+  }
+  #endif
+  return LZMA_RESULT_OK;
+}
+
+#define kLzmaStreamWasFinishedId (-1)
+
+int LzmaDecode(CLzmaDecoderState *vs,
+    #ifdef _LZMA_IN_CB
+    ILzmaInCallback *InCallback,
+    #else
+    const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+    #endif
+    unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed)
+{
+  CProb *p = vs->Probs;
+  SizeT nowPos = 0;
+  Byte previousByte = 0;
+  UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1;
+  UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1;
+  int lc = vs->Properties.lc;
+
+  #ifdef _LZMA_OUT_READ
+  
+  UInt32 Range = vs->Range;
+  UInt32 Code = vs->Code;
+  #ifdef _LZMA_IN_CB
+  const Byte *Buffer = vs->Buffer;
+  const Byte *BufferLim = vs->BufferLim;
+  #else
+  const Byte *Buffer = inStream;
+  const Byte *BufferLim = inStream + inSize;
+  #endif
+  int state = vs->State;
+  UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3];
+  int len = vs->RemainLen;
+  UInt32 globalPos = vs->GlobalPos;
+  UInt32 distanceLimit = vs->DistanceLimit;
+
+  Byte *dictionary = vs->Dictionary;
+  UInt32 dictionarySize = vs->Properties.DictionarySize;
+  UInt32 dictionaryPos = vs->DictionaryPos;
+
+  Byte tempDictionary[4];
+
+  #ifndef _LZMA_IN_CB
+  *inSizeProcessed = 0;
+  #endif
+  *outSizeProcessed = 0;
+  if (len == kLzmaStreamWasFinishedId)
+    return LZMA_RESULT_OK;
+
+  if (dictionarySize == 0)
+  {
+    dictionary = tempDictionary;
+    dictionarySize = 1;
+    tempDictionary[0] = vs->TempDictionary[0];
+  }
+
+  if (len == kLzmaNeedInitId)
+  {
+    {
+      UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+      UInt32 i;
+      for (i = 0; i < numProbs; i++)
+        p[i] = kBitModelTotal >> 1; 
+      rep0 = rep1 = rep2 = rep3 = 1;
+      state = 0;
+      globalPos = 0;
+      distanceLimit = 0;
+      dictionaryPos = 0;
+      dictionary[dictionarySize - 1] = 0;
+      #ifdef _LZMA_IN_CB
+      RC_INIT;
+      #else
+      RC_INIT(inStream, inSize);
+      #endif
+    }
+    len = 0;
+  }
+  while(len != 0 && nowPos < outSize)
+  {
+    UInt32 pos = dictionaryPos - rep0;
+    if (pos >= dictionarySize)
+      pos += dictionarySize;
+    outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos];
+    if (++dictionaryPos == dictionarySize)
+      dictionaryPos = 0;
+    len--;
+  }
+  if (dictionaryPos == 0)
+    previousByte = dictionary[dictionarySize - 1];
+  else
+    previousByte = dictionary[dictionaryPos - 1];
+
+  #else /* if !_LZMA_OUT_READ */
+
+  int state = 0;
+  UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
+  int len = 0;
+  const Byte *Buffer;
+  const Byte *BufferLim;
+  UInt32 Range;
+  UInt32 Code;
+
+  #ifndef _LZMA_IN_CB
+  *inSizeProcessed = 0;
+  #endif
+  *outSizeProcessed = 0;
+
+  {
+    UInt32 i;
+    UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+    for (i = 0; i < numProbs; i++)
+      p[i] = kBitModelTotal >> 1;
+  }
+  
+  #ifdef _LZMA_IN_CB
+  RC_INIT;
+  #else
+  RC_INIT(inStream, inSize);
+  #endif
+
+  #endif /* _LZMA_OUT_READ */
+
+  while(nowPos < outSize)
+  {
+    CProb *prob;
+    UInt32 bound;
+    int posState = (int)(
+        (nowPos 
+        #ifdef _LZMA_OUT_READ
+        + globalPos
+        #endif
+        )
+        & posStateMask);
+
+    prob = p + IsMatch + (state << kNumPosBitsMax) + posState;
+    IfBit0(prob)
+    {
+      int symbol = 1;
+      UpdateBit0(prob)
+      prob = p + Literal + (LZMA_LIT_SIZE * 
+        (((
+        (nowPos 
+        #ifdef _LZMA_OUT_READ
+        + globalPos
+        #endif
+        )
+        & literalPosMask) << lc) + (previousByte >> (8 - lc))));
+
+      if (state >= kNumLitStates)
+      {
+        int matchByte;
+        #ifdef _LZMA_OUT_READ
+        UInt32 pos = dictionaryPos - rep0;
+        if (pos >= dictionarySize)
+          pos += dictionarySize;
+        matchByte = dictionary[pos];
+        #else
+        matchByte = outStream[nowPos - rep0];
+        #endif
+        do
+        {
+          int bit;
+          CProb *probLit;
+          matchByte <<= 1;
+          bit = (matchByte & 0x100);
+          probLit = prob + 0x100 + bit + symbol;
+          RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break)
+        }
+        while (symbol < 0x100);
+      }
+      while (symbol < 0x100)
+      {
+        CProb *probLit = prob + symbol;
+        RC_GET_BIT(probLit, symbol)
+      }
+      previousByte = (Byte)symbol;
+
+      outStream[nowPos++] = previousByte;
+      #ifdef _LZMA_OUT_READ
+      if (distanceLimit < dictionarySize)
+        distanceLimit++;
+
+      dictionary[dictionaryPos] = previousByte;
+      if (++dictionaryPos == dictionarySize)
+        dictionaryPos = 0;
+      #endif
+      if (state < 4) state = 0;
+      else if (state < 10) state -= 3;
+      else state -= 6;
+    }
+    else             
+    {
+      UpdateBit1(prob);
+      prob = p + IsRep + state;
+      IfBit0(prob)
+      {
+        UpdateBit0(prob);
+        rep3 = rep2;
+        rep2 = rep1;
+        rep1 = rep0;
+        state = state < kNumLitStates ? 0 : 3;
+        prob = p + LenCoder;
+      }
+      else
+      {
+        UpdateBit1(prob);
+        prob = p + IsRepG0 + state;
+        IfBit0(prob)
+        {
+          UpdateBit0(prob);
+          prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState;
+          IfBit0(prob)
+          {
+            #ifdef _LZMA_OUT_READ
+            UInt32 pos;
+            #endif
+            UpdateBit0(prob);
+            
+            #ifdef _LZMA_OUT_READ
+            if (distanceLimit == 0)
+            #else
+            if (nowPos == 0)
+            #endif
+              return LZMA_RESULT_DATA_ERROR;
+            
+            state = state < kNumLitStates ? 9 : 11;
+            #ifdef _LZMA_OUT_READ
+            pos = dictionaryPos - rep0;
+            if (pos >= dictionarySize)
+              pos += dictionarySize;
+            previousByte = dictionary[pos];
+            dictionary[dictionaryPos] = previousByte;
+            if (++dictionaryPos == dictionarySize)
+              dictionaryPos = 0;
+            #else
+            previousByte = outStream[nowPos - rep0];
+            #endif
+            outStream[nowPos++] = previousByte;
+            #ifdef _LZMA_OUT_READ
+            if (distanceLimit < dictionarySize)
+              distanceLimit++;
+            #endif
+
+            continue;
+          }
+          else
+          {
+            UpdateBit1(prob);
+          }
+        }
+        else
+        {
+          UInt32 distance;
+          UpdateBit1(prob);
+          prob = p + IsRepG1 + state;
+          IfBit0(prob)
+          {
+            UpdateBit0(prob);
+            distance = rep1;
+          }
+          else 
+          {
+            UpdateBit1(prob);
+            prob = p + IsRepG2 + state;
+            IfBit0(prob)
+            {
+              UpdateBit0(prob);
+              distance = rep2;
+            }
+            else
+            {
+              UpdateBit1(prob);
+              distance = rep3;
+              rep3 = rep2;
+            }
+            rep2 = rep1;
+          }
+          rep1 = rep0;
+          rep0 = distance;
+        }
+        state = state < kNumLitStates ? 8 : 11;
+        prob = p + RepLenCoder;
+      }
+      {
+        int numBits, offset;
+        CProb *probLen = prob + LenChoice;
+        IfBit0(probLen)
+        {
+          UpdateBit0(probLen);
+          probLen = prob + LenLow + (posState << kLenNumLowBits);
+          offset = 0;
+          numBits = kLenNumLowBits;
+        }
+        else
+        {
+          UpdateBit1(probLen);
+          probLen = prob + LenChoice2;
+          IfBit0(probLen)
+          {
+            UpdateBit0(probLen);
+            probLen = prob + LenMid + (posState << kLenNumMidBits);
+            offset = kLenNumLowSymbols;
+            numBits = kLenNumMidBits;
+          }
+          else
+          {
+            UpdateBit1(probLen);
+            probLen = prob + LenHigh;
+            offset = kLenNumLowSymbols + kLenNumMidSymbols;
+            numBits = kLenNumHighBits;
+          }
+        }
+        RangeDecoderBitTreeDecode(probLen, numBits, len);
+        len += offset;
+      }
+
+      if (state < 4)
+      {
+        int posSlot;
+        state += kNumLitStates;
+        prob = p + PosSlot +
+            ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << 
+            kNumPosSlotBits);
+        RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot);
+        if (posSlot >= kStartPosModelIndex)
+        {
+          int numDirectBits = ((posSlot >> 1) - 1);
+          rep0 = (2 | ((UInt32)posSlot & 1));
+          if (posSlot < kEndPosModelIndex)
+          {
+            rep0 <<= numDirectBits;
+            prob = p + SpecPos + rep0 - posSlot - 1;
+          }
+          else
+          {
+            numDirectBits -= kNumAlignBits;
+            do
+            {
+              RC_NORMALIZE
+              Range >>= 1;
+              rep0 <<= 1;
+              if (Code >= Range)
+              {
+                Code -= Range;
+                rep0 |= 1;
+              }
+            }
+            while (--numDirectBits != 0);
+            prob = p + Align;
+            rep0 <<= kNumAlignBits;
+            numDirectBits = kNumAlignBits;
+          }
+          {
+            int i = 1;
+            int mi = 1;
+            do
+            {
+              CProb *prob3 = prob + mi;
+              RC_GET_BIT2(prob3, mi, ; , rep0 |= i);
+              i <<= 1;
+            }
+            while(--numDirectBits != 0);
+          }
+        }
+        else
+          rep0 = posSlot;
+        if (++rep0 == (UInt32)(0))
+        {
+          /* it's for stream version */
+          len = kLzmaStreamWasFinishedId;
+          break;
+        }
+      }
+
+      len += kMatchMinLen;
+      #ifdef _LZMA_OUT_READ
+      if (rep0 > distanceLimit) 
+      #else
+      if (rep0 > nowPos)
+      #endif
+        return LZMA_RESULT_DATA_ERROR;
+
+      #ifdef _LZMA_OUT_READ
+      if (dictionarySize - distanceLimit > (UInt32)len)
+        distanceLimit += len;
+      else
+        distanceLimit = dictionarySize;
+      #endif
+
+      do
+      {
+        #ifdef _LZMA_OUT_READ
+        UInt32 pos = dictionaryPos - rep0;
+        if (pos >= dictionarySize)
+          pos += dictionarySize;
+        previousByte = dictionary[pos];
+        dictionary[dictionaryPos] = previousByte;
+        if (++dictionaryPos == dictionarySize)
+          dictionaryPos = 0;
+        #else
+        previousByte = outStream[nowPos - rep0];
+        #endif
+        len--;
+        outStream[nowPos++] = previousByte;
+      }
+      while(len != 0 && nowPos < outSize);
+    }
+  }
+  RC_NORMALIZE;
+
+  #ifdef _LZMA_OUT_READ
+  vs->Range = Range;
+  vs->Code = Code;
+  vs->DictionaryPos = dictionaryPos;
+  vs->GlobalPos = globalPos + (UInt32)nowPos;
+  vs->DistanceLimit = distanceLimit;
+  vs->Reps[0] = rep0;
+  vs->Reps[1] = rep1;
+  vs->Reps[2] = rep2;
+  vs->Reps[3] = rep3;
+  vs->State = state;
+  vs->RemainLen = len;
+  vs->TempDictionary[0] = tempDictionary[0];
+  #endif
+
+  #ifdef _LZMA_IN_CB
+  vs->Buffer = Buffer;
+  vs->BufferLim = BufferLim;
+  #else
+  *inSizeProcessed = (SizeT)(Buffer - inStream);
+  #endif
+  *outSizeProcessed = nowPos;
+  return LZMA_RESULT_OK;
+}
diff --git a/src/unison/physfs-1.1.1/lzma/LzmaDecode.h b/src/unison/physfs-1.1.1/lzma/LzmaDecode.h
new file mode 100644 (file)
index 0000000..2870eeb
--- /dev/null
@@ -0,0 +1,113 @@
+/* 
+  LzmaDecode.h
+  LZMA Decoder interface
+
+  LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
+  http://www.7-zip.org/
+
+  LZMA SDK is licensed under two licenses:
+  1) GNU Lesser General Public License (GNU LGPL)
+  2) Common Public License (CPL)
+  It means that you can select one of these two licenses and 
+  follow rules of that license.
+
+  SPECIAL EXCEPTION:
+  Igor Pavlov, as the author of this code, expressly permits you to 
+  statically or dynamically link your code (or bind by name) to the 
+  interfaces of this file without subjecting your linked code to the 
+  terms of the CPL or GNU LGPL. Any modifications or additions 
+  to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#ifndef __LZMADECODE_H
+#define __LZMADECODE_H
+
+#include "LzmaTypes.h"
+
+/* #define _LZMA_IN_CB */
+/* Use callback for input data */
+
+/* #define _LZMA_OUT_READ */
+/* Use read function for output data */
+
+/* #define _LZMA_PROB32 */
+/* It can increase speed on some 32-bit CPUs, 
+   but memory usage will be doubled in that case */
+
+/* #define _LZMA_LOC_OPT */
+/* Enable local speed optimizations inside code */
+
+#ifdef _LZMA_PROB32
+#define CProb UInt32
+#else
+#define CProb UInt16
+#endif
+
+#define LZMA_RESULT_OK 0
+#define LZMA_RESULT_DATA_ERROR 1
+
+#ifdef _LZMA_IN_CB
+typedef struct _ILzmaInCallback
+{
+  int (*Read)(void *object, const unsigned char **buffer, SizeT *bufferSize);
+} ILzmaInCallback;
+#endif
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+#define LZMA_PROPERTIES_SIZE 5
+
+typedef struct _CLzmaProperties
+{
+  int lc;
+  int lp;
+  int pb;
+  #ifdef _LZMA_OUT_READ
+  UInt32 DictionarySize;
+  #endif
+}CLzmaProperties;
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size);
+
+#define LzmaGetNumProbs(Properties) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((Properties)->lc + (Properties)->lp)))
+
+#define kLzmaNeedInitId (-2)
+
+typedef struct _CLzmaDecoderState
+{
+  CLzmaProperties Properties;
+  CProb *Probs;
+
+  #ifdef _LZMA_IN_CB
+  const unsigned char *Buffer;
+  const unsigned char *BufferLim;
+  #endif
+
+  #ifdef _LZMA_OUT_READ
+  unsigned char *Dictionary;
+  UInt32 Range;
+  UInt32 Code;
+  UInt32 DictionaryPos;
+  UInt32 GlobalPos;
+  UInt32 DistanceLimit;
+  UInt32 Reps[4];
+  int State;
+  int RemainLen;
+  unsigned char TempDictionary[4];
+  #endif
+} CLzmaDecoderState;
+
+#ifdef _LZMA_OUT_READ
+#define LzmaDecoderInit(vs) { (vs)->RemainLen = kLzmaNeedInitId; }
+#endif
+
+int LzmaDecode(CLzmaDecoderState *vs,
+    #ifdef _LZMA_IN_CB
+    ILzmaInCallback *inCallback,
+    #else
+    const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+    #endif
+    unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed);
+
+#endif
diff --git a/src/unison/physfs-1.1.1/lzma/LzmaStateDecode.c b/src/unison/physfs-1.1.1/lzma/LzmaStateDecode.c
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/unison/physfs-1.1.1/lzma/LzmaStateDecode.h b/src/unison/physfs-1.1.1/lzma/LzmaStateDecode.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/unison/physfs-1.1.1/lzma/LzmaTypes.h b/src/unison/physfs-1.1.1/lzma/LzmaTypes.h
new file mode 100644 (file)
index 0000000..288c5e4
--- /dev/null
@@ -0,0 +1,45 @@
+/* 
+LzmaTypes.h 
+
+Types for LZMA Decoder
+
+This file written and distributed to public domain by Igor Pavlov.
+This file is part of LZMA SDK 4.40 (2006-05-01)
+*/
+
+#ifndef __LZMATYPES_H
+#define __LZMATYPES_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 
+
+/* #define _LZMA_SYSTEM_SIZE_T */
+/* Use system's size_t. You can use it to enable 64-bit sizes supporting */
+
+#ifndef _7ZIP_SIZET_DEFINED
+#define _7ZIP_SIZET_DEFINED
+#ifdef _LZMA_SYSTEM_SIZE_T
+#include <stddef.h>
+typedef size_t SizeT;
+#else
+typedef UInt32 SizeT;
+#endif
+#endif
+
+#endif
diff --git a/src/unison/physfs-1.1.1/makeos2.cmd b/src/unison/physfs-1.1.1/makeos2.cmd
new file mode 100644 (file)
index 0000000..b1fb4c0
--- /dev/null
@@ -0,0 +1,181 @@
+@echo off
+rem this is a simple batch file to build PhysicsFS on OS/2. You need to have
+rem  the Innotek libc and GCC (or "kLIBC") installed for this to work:
+rem
+rem     http://svn.netlabs.org/libc
+rem
+rem This script (and, indeed, our OS/2 support) could use some tweaking.
+rem  Patches go to icculus@icculus.org ...
+
+set PHYSFSLANG=PHYSFS_LANG_ENGLISH
+set DEBUGFLAGS=-D_NDEBUG -O2 -s
+rem set CFLAGS=%DEBUGFLAGS% -Wall -Werror -Zomf -Zmt -Zmtd -I. -Izlib123 -c -D__ST_MT_ERRNO__ -DOS2 -DZ_PREFIX -DPHYSFS_SUPPORTS_ZIP -DPHYSFS_SUPPORTS_7Z -DPHYSFS_SUPPORTS_GRP -DPHYSFS_SUPPORTS_WAD -DPHYSFS_SUPPORTS_QPAK -DPHYSFS_SUPPORTS_HOG -DPHYSFS_SUPPORTS_MVL -DPHYSFS_LANG=%PHYSFSLANG% -DHAVE_ASSERT_H
+set CFLAGS=%DEBUGFLAGS% -Wall -Werror -Zomf -I. -Iz -c -D__ST_MT_ERRNO__ -DOS2 -DZ_PREFIX -DPHYSFS_SUPPORTS_ZIP -DPHYSFS_SUPPORTS_7Z -DPHYSFS_SUPPORTS_GRP -DPHYSFS_SUPPORTS_WAD -DPHYSFS_SUPPORTS_QPAK -DPHYSFS_SUPPORTS_HOG -DPHYSFS_SUPPORTS_MVL -DHAVE_ASSERT_H
+
+rem goto :dolinking
+
+@echo cleaning up any previous build...
+@mkdir bin 2>NUL
+@erase /N bin\*.* 2>NUL
+
+@echo Building export definitions...
+@echo ;don't edit this directly! It is rewritten by makeos2.cmd! > bin\test_physfs.def
+@echo NAME TESTPHYSFS WINDOWCOMPAT >> bin\test_physfs.def
+@echo DESCRIPTION 'PhysicsFS: http://icculus.org/physfs/' >> bin\test_physfs.def
+@echo STACKSIZE 0x10000 >> bin\test_physfs.def
+@echo BASE=0x10000 >> bin\test_physfs.def
+@echo PROTMODE >> bin\test_physfs.def
+
+@echo ;don't edit this directly! It is rewritten by makeos2.cmd! > bin\physfs.def
+@echo LIBRARY 'physfs' INITINSTANCE TERMINSTANCE >> bin\physfs.def
+@echo STACKSIZE 0x10000 >> bin\physfs.def
+@echo CODE LOADONCALL >> bin\physfs.def
+@echo DATA LOADONCALL NONSHARED MULTIPLE >> bin\physfs.def
+@echo DESCRIPTION 'PhysicsFS: http://icculus.org/physfs/' >> bin\physfs.def
+@echo EXPORTS >> bin\physfs.def
+@echo "_PHYSFS_getLinkedVersion" >> bin\physfs.def
+@echo "_PHYSFS_init" >> bin\physfs.def
+@echo "_PHYSFS_deinit" >> bin\physfs.def
+@echo "_PHYSFS_isInit" >> bin\physfs.def
+@echo "_PHYSFS_supportedArchiveTypes" >> bin\physfs.def
+@echo "_PHYSFS_freeList" >> bin\physfs.def
+@echo "_PHYSFS_getLastError" >> bin\physfs.def
+@echo "_PHYSFS_getDirSeparator" >> bin\physfs.def
+@echo "_PHYSFS_permitSymbolicLinks" >> bin\physfs.def
+@echo "_PHYSFS_symbolicLinksPermitted" >> bin\physfs.def
+@echo "_PHYSFS_getCdRomDirs" >> bin\physfs.def
+@echo "_PHYSFS_getBaseDir" >> bin\physfs.def
+@echo "_PHYSFS_getUserDir" >> bin\physfs.def
+@echo "_PHYSFS_getWriteDir" >> bin\physfs.def
+@echo "_PHYSFS_setWriteDir" >> bin\physfs.def
+@echo "_PHYSFS_addToSearchPath" >> bin\physfs.def
+@echo "_PHYSFS_removeFromSearchPath" >> bin\physfs.def
+@echo "_PHYSFS_getSearchPath" >> bin\physfs.def
+@echo "_PHYSFS_setSaneConfig" >> bin\physfs.def
+@echo "_PHYSFS_mkdir" >> bin\physfs.def
+@echo "_PHYSFS_delete" >> bin\physfs.def
+@echo "_PHYSFS_getRealDir" >> bin\physfs.def
+@echo "_PHYSFS_enumerateFiles" >> bin\physfs.def
+@echo "_PHYSFS_exists" >> bin\physfs.def
+@echo "_PHYSFS_isDirectory" >> bin\physfs.def
+@echo "_PHYSFS_isSymbolicLink" >> bin\physfs.def
+@echo "_PHYSFS_openWrite" >> bin\physfs.def
+@echo "_PHYSFS_openAppend" >> bin\physfs.def
+@echo "_PHYSFS_openRead" >> bin\physfs.def
+@echo "_PHYSFS_close" >> bin\physfs.def
+@echo "_PHYSFS_read" >> bin\physfs.def
+@echo "_PHYSFS_write" >> bin\physfs.def
+@echo "_PHYSFS_eof" >> bin\physfs.def
+@echo "_PHYSFS_tell" >> bin\physfs.def
+@echo "_PHYSFS_seek" >> bin\physfs.def
+@echo "_PHYSFS_fileLength" >> bin\physfs.def
+@echo "_PHYSFS_swapSLE16" >> bin\physfs.def
+@echo "_PHYSFS_swapULE16" >> bin\physfs.def
+@echo "_PHYSFS_swapSLE32" >> bin\physfs.def
+@echo "_PHYSFS_swapULE32" >> bin\physfs.def
+@echo "_PHYSFS_swapSLE64" >> bin\physfs.def
+@echo "_PHYSFS_swapULE64" >> bin\physfs.def
+@echo "_PHYSFS_swapSBE16" >> bin\physfs.def
+@echo "_PHYSFS_swapUBE16" >> bin\physfs.def
+@echo "_PHYSFS_swapSBE32" >> bin\physfs.def
+@echo "_PHYSFS_swapUBE32" >> bin\physfs.def
+@echo "_PHYSFS_swapSBE64" >> bin\physfs.def
+@echo "_PHYSFS_swapUBE64" >> bin\physfs.def
+@echo "_PHYSFS_getLastModTime" >> bin\physfs.def
+@echo "_PHYSFS_readSLE16" >> bin\physfs.def
+@echo "_PHYSFS_readULE16" >> bin\physfs.def
+@echo "_PHYSFS_readSLE32" >> bin\physfs.def
+@echo "_PHYSFS_readULE32" >> bin\physfs.def
+@echo "_PHYSFS_readSLE64" >> bin\physfs.def
+@echo "_PHYSFS_readULE64" >> bin\physfs.def
+@echo "_PHYSFS_readSBE16" >> bin\physfs.def
+@echo "_PHYSFS_readUBE16" >> bin\physfs.def
+@echo "_PHYSFS_readSBE32" >> bin\physfs.def
+@echo "_PHYSFS_readUBE32" >> bin\physfs.def
+@echo "_PHYSFS_readSBE64" >> bin\physfs.def
+@echo "_PHYSFS_readUBE64" >> bin\physfs.def
+@echo "_PHYSFS_writeSLE16" >> bin\physfs.def
+@echo "_PHYSFS_writeULE16" >> bin\physfs.def
+@echo "_PHYSFS_writeSLE32" >> bin\physfs.def
+@echo "_PHYSFS_writeULE32" >> bin\physfs.def
+@echo "_PHYSFS_writeSLE64" >> bin\physfs.def
+@echo "_PHYSFS_writeULE64" >> bin\physfs.def
+@echo "_PHYSFS_writeSBE16" >> bin\physfs.def
+@echo "_PHYSFS_writeUBE16" >> bin\physfs.def
+@echo "_PHYSFS_writeSBE32" >> bin\physfs.def
+@echo "_PHYSFS_writeUBE32" >> bin\physfs.def
+@echo "_PHYSFS_writeSBE64" >> bin\physfs.def
+@echo "_PHYSFS_writeUBE64" >> bin\physfs.def
+@echo "_PHYSFS_setBuffer" >> bin\physfs.def
+@echo "_PHYSFS_flush" >> bin\physfs.def
+@echo "_PHYSFS_mount" >> bin\physfs.def
+@echo "_PHYSFS_getMountPoint" >> bin\physfs.def
+@echo "_PHYSFS_setAllocator" >> bin\physfs.def
+@echo "_PHYSFS_getCdRomDirsCallback" >> bin\physfs.def
+@echo "_PHYSFS_getSearchPathCallback" >> bin\physfs.def
+@echo "_PHYSFS_enumerateFilesCallback" >> bin\physfs.def
+@echo "_PHYSFS_utf8ToUcs2" >> bin\physfs.def
+@echo "_PHYSFS_utf8FromUcs2" >> bin\physfs.def
+@echo "_PHYSFS_utf8ToUcs4" >> bin\physfs.def
+@echo "_PHYSFS_utf8FromUcs4" >> bin\physfs.def
+@echo "_PHYSFS_utf8FromLatin1" >> bin\physfs.def
+
+@echo Building export library...
+emximp -o bin/physfs.lib bin/physfs.def
+emximp -o bin/physfs.a bin/physfs.def
+
+@echo Compiling PhysicsFS library...
+@echo on
+gcc %CFLAGS% -o bin/physfs.obj physfs.c
+gcc %CFLAGS% -o bin/physfs_byteorder.obj physfs_byteorder.c
+gcc %CFLAGS% -o bin/physfs_unicode.obj physfs_unicode.c
+gcc %CFLAGS% -o bin/os2.obj platform/os2.c
+gcc %CFLAGS% -o bin/dir.obj archivers/dir.c
+gcc %CFLAGS% -o bin/grp.obj archivers/grp.c
+gcc %CFLAGS% -o bin/wad.obj archivers/wad.c
+gcc %CFLAGS% -o bin/lzma.obj archivers/lzma.c
+gcc %CFLAGS% -o bin/zip.obj archivers/zip.c
+gcc %CFLAGS% -o bin/qpak.obj archivers/qpak.c
+gcc %CFLAGS% -o bin/hog.obj archivers/hog.c
+gcc %CFLAGS% -o bin/mvl.obj archivers/mvl.c
+gcc %CFLAGS% -o bin/adler32.obj zlib123/adler32.c
+gcc %CFLAGS% -o bin/compress.obj zlib123/compress.c
+gcc %CFLAGS% -o bin/crc32.obj zlib123/crc32.c
+gcc %CFLAGS% -o bin/deflate.obj zlib123/deflate.c
+gcc %CFLAGS% -o bin/gzio.obj zlib123/gzio.c
+gcc %CFLAGS% -o bin/infback.obj zlib123/infback.c
+gcc %CFLAGS% -o bin/inffast.obj zlib123/inffast.c
+gcc %CFLAGS% -o bin/inflate.obj zlib123/inflate.c
+gcc %CFLAGS% -o bin/inftrees.obj zlib123/inftrees.c
+gcc %CFLAGS% -o bin/trees.obj zlib123/trees.c
+gcc %CFLAGS% -o bin/uncompr.obj zlib123/uncompr.c
+gcc %CFLAGS% -o bin/zutil.obj zlib123/zutil.c
+gcc %CFLAGS% -o bin/7zBuffer.obj lzma/7zBuffer.c
+gcc %CFLAGS% -o bin/7zCrc.obj lzma/7zCrc.c
+gcc %CFLAGS% -o bin/7zDecode.obj lzma/7zDecode.c
+gcc %CFLAGS% -o bin/7zExtract.obj lzma/7zExtract.c
+gcc %CFLAGS% -o bin/7zHeader.obj lzma/7zHeader.c
+gcc %CFLAGS% -o bin/7zIn.obj lzma/7zIn.c
+gcc %CFLAGS% -o bin/7zItem.obj lzma/7zItem.c
+gcc %CFLAGS% -o bin/7zMethodID.obj lzma/7zMethodID.c
+gcc %CFLAGS% -o bin/LzmaDecode.obj lzma/LzmaDecode.c
+gcc %CFLAGS% -o bin/LzmaStateDecode.obj lzma/LzmaStateDecode.c
+@echo off
+
+:dolinking
+@echo Linking PhysicsFS library...
+gcc %DEBUGFLAGS% -Zdll -Zcrtdll -Zomf -o bin/physfs.dll bin/*.obj bin/physfs.def
+
+rem goto :builddone
+
+@echo Compiling test program...
+gcc %CFLAGS% -o bin/test_physfs.obj test/test_physfs.c
+@echo Linking test program...
+gcc %DEBUGFLAGS% -Zomf -Zcrtdll -o bin/test_physfs.exe bin/test_physfs.obj bin/physfs.lib bin/test_physfs.def
+
+:builddone
+
+@echo "All done!"
+
+rem end of makeos2.cmd ...
+
diff --git a/src/unison/physfs-1.1.1/physfs-1.1.1/CMakeFiles/CMakeError.log b/src/unison/physfs-1.1.1/physfs-1.1.1/CMakeFiles/CMakeError.log
new file mode 100644 (file)
index 0000000..243088e
--- /dev/null
@@ -0,0 +1,31 @@
+Performing C SOURCE FILE Test PHYSFS_IS_GCC4 failed with the following output:
+
+Source file was:
+
+        #if ((defined(__GNUC__)) && (__GNUC__ >= 4))
+        int main(int argc, char **argv) { int is_gcc4 = 1; return 0; }
+        #else
+        #error This is not gcc4.
+        #endif
+    
+Determining if the include file sys/ucred.h exists failed with the following output:
+
+
+Determining if the include file mntent.h exists failed with the following output:
+
+
+Determining if the include file pthread.h exists failed with the following output:
+
+
+Determining if the include file assert.h exists failed with the following output:
+
+
+Determining if the include file zlib.h exists failed with the following output:
+
+
+Determining if the include file readline/readline.h exists failed with the following output:
+
+
+Determining if the include file readline/history.h exists failed with the following output:
+
+
diff --git a/src/unison/physfs-1.1.1/physfs-1.1.1/CMakeFiles/CMakeTmp/src.c b/src/unison/physfs-1.1.1/physfs-1.1.1/CMakeFiles/CMakeTmp/src.c
new file mode 100644 (file)
index 0000000..65674d0
--- /dev/null
@@ -0,0 +1,7 @@
+
+        #if ((defined(__GNUC__)) && (__GNUC__ >= 4))
+        int main(int argc, char **argv) { int is_gcc4 = 1; return 0; }
+        #else
+        #error This is not gcc4.
+        #endif
+    
diff --git a/src/unison/physfs-1.1.1/physfs.c b/src/unison/physfs-1.1.1/physfs.c
new file mode 100644 (file)
index 0000000..aeb0fc4
--- /dev/null
@@ -0,0 +1,2220 @@
+/**
+ * PhysicsFS; a portable, flexible file i/o abstraction.
+ *
+ * Documentation is in physfs.h. It's verbose, honest.  :)
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "physfs.h"
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+
+typedef struct __PHYSFS_DIRHANDLE__
+{
+    void *opaque;  /* Instance data unique to the archiver. */
+    char *dirName;  /* Path to archive in platform-dependent notation. */
+    char *mountPoint; /* Mountpoint in virtual file tree. */
+    const PHYSFS_Archiver *funcs;  /* Ptr to archiver info for this handle. */
+    struct __PHYSFS_DIRHANDLE__ *next;  /* linked list stuff. */
+} DirHandle;
+
+
+typedef struct __PHYSFS_FILEHANDLE__
+{
+    void *opaque;  /* Instance data unique to the archiver for this file. */
+    PHYSFS_uint8 forReading; /* Non-zero if reading, zero if write/append */
+    const DirHandle *dirHandle;  /* Archiver instance that created this */
+    const PHYSFS_Archiver *funcs;  /* Ptr to archiver info for this handle. */
+    PHYSFS_uint8 *buffer;  /* Buffer, if set (NULL otherwise). Don't touch! */
+    PHYSFS_uint32 bufsize;  /* Bufsize, if set (0 otherwise). Don't touch! */
+    PHYSFS_uint32 buffill;  /* Buffer fill size. Don't touch! */
+    PHYSFS_uint32 bufpos;  /* Buffer position. Don't touch! */
+    struct __PHYSFS_FILEHANDLE__ *next;  /* linked list stuff. */
+} FileHandle;
+
+
+typedef struct __PHYSFS_ERRMSGTYPE__
+{
+    PHYSFS_uint64 tid;
+    int errorAvailable;
+    char errorString[80];
+    struct __PHYSFS_ERRMSGTYPE__ *next;
+} ErrMsg;
+
+
+/* The various i/o drivers...some of these may not be compiled in. */
+extern const PHYSFS_ArchiveInfo    __PHYSFS_ArchiveInfo_ZIP;
+extern const PHYSFS_Archiver       __PHYSFS_Archiver_ZIP;
+extern const PHYSFS_ArchiveInfo    __PHYSFS_ArchiveInfo_LZMA;
+extern const PHYSFS_Archiver       __PHYSFS_Archiver_LZMA;
+extern const PHYSFS_ArchiveInfo    __PHYSFS_ArchiveInfo_GRP;
+extern const PHYSFS_Archiver       __PHYSFS_Archiver_GRP;
+extern const PHYSFS_ArchiveInfo    __PHYSFS_ArchiveInfo_QPAK;
+extern const PHYSFS_Archiver       __PHYSFS_Archiver_QPAK;
+extern const PHYSFS_ArchiveInfo    __PHYSFS_ArchiveInfo_HOG;
+extern const PHYSFS_Archiver       __PHYSFS_Archiver_HOG;
+extern const PHYSFS_ArchiveInfo    __PHYSFS_ArchiveInfo_MVL;
+extern const PHYSFS_Archiver       __PHYSFS_Archiver_MVL;
+extern const PHYSFS_ArchiveInfo    __PHYSFS_ArchiveInfo_WAD;
+extern const PHYSFS_Archiver       __PHYSFS_Archiver_WAD;
+extern const PHYSFS_Archiver       __PHYSFS_Archiver_DIR;
+
+
+static const PHYSFS_ArchiveInfo *supported_types[] =
+{
+#if (defined PHYSFS_SUPPORTS_ZIP)
+    &__PHYSFS_ArchiveInfo_ZIP,
+#endif
+#if (defined PHYSFS_SUPPORTS_7Z)
+    &__PHYSFS_ArchiveInfo_LZMA,
+#endif
+#if (defined PHYSFS_SUPPORTS_GRP)
+    &__PHYSFS_ArchiveInfo_GRP,
+#endif
+#if (defined PHYSFS_SUPPORTS_QPAK)
+    &__PHYSFS_ArchiveInfo_QPAK,
+#endif
+#if (defined PHYSFS_SUPPORTS_HOG)
+    &__PHYSFS_ArchiveInfo_HOG,
+#endif
+#if (defined PHYSFS_SUPPORTS_MVL)
+    &__PHYSFS_ArchiveInfo_MVL,
+#endif
+#if (defined PHYSFS_SUPPORTS_WAD)
+    &__PHYSFS_ArchiveInfo_WAD,
+#endif
+    NULL
+};
+
+static const PHYSFS_Archiver *archivers[] =
+{
+    &__PHYSFS_Archiver_DIR,
+#if (defined PHYSFS_SUPPORTS_ZIP)
+    &__PHYSFS_Archiver_ZIP,
+#endif
+#if (defined PHYSFS_SUPPORTS_7Z)
+    &__PHYSFS_Archiver_LZMA,
+#endif
+#if (defined PHYSFS_SUPPORTS_GRP)
+    &__PHYSFS_Archiver_GRP,
+#endif
+#if (defined PHYSFS_SUPPORTS_QPAK)
+    &__PHYSFS_Archiver_QPAK,
+#endif
+#if (defined PHYSFS_SUPPORTS_HOG)
+    &__PHYSFS_Archiver_HOG,
+#endif
+#if (defined PHYSFS_SUPPORTS_MVL)
+    &__PHYSFS_Archiver_MVL,
+#endif
+#if (defined PHYSFS_SUPPORTS_WAD)
+    &__PHYSFS_Archiver_WAD,
+#endif
+    NULL
+};
+
+
+
+/* General PhysicsFS state ... */
+static int initialized = 0;
+static ErrMsg *errorMessages = NULL;
+static DirHandle *searchPath = NULL;
+static DirHandle *writeDir = NULL;
+static FileHandle *openWriteList = NULL;
+static FileHandle *openReadList = NULL;
+static char *baseDir = NULL;
+static char *userDir = NULL;
+static int allowSymLinks = 0;
+
+/* mutexes ... */
+static void *errorLock = NULL;     /* protects error message list.        */
+static void *stateLock = NULL;     /* protects other PhysFS static state. */
+
+/* allocator ... */
+static int externalAllocator = 0;
+PHYSFS_Allocator allocator;
+
+
+/* functions ... */
+
+typedef struct
+{
+    char **list;
+    PHYSFS_uint32 size;
+    const char *errorstr;
+} EnumStringListCallbackData;
+
+static void enumStringListCallback(void *data, const char *str)
+{
+    void *ptr;
+    char *newstr;
+    EnumStringListCallbackData *pecd = (EnumStringListCallbackData *) data;
+
+    if (pecd->errorstr)
+        return;
+
+    ptr = allocator.Realloc(pecd->list, (pecd->size + 2) * sizeof (char *));
+    newstr = (char *) allocator.Malloc(strlen(str) + 1);
+    if (ptr != NULL)
+        pecd->list = (char **) ptr;
+
+    if ((ptr == NULL) || (newstr == NULL))
+    {
+        pecd->errorstr = ERR_OUT_OF_MEMORY;
+        pecd->list[pecd->size] = NULL;
+        PHYSFS_freeList(pecd->list);
+        return;
+    } /* if */
+
+    strcpy(newstr, str);
+    pecd->list[pecd->size] = newstr;
+    pecd->size++;
+} /* enumStringListCallback */
+
+
+static char **doEnumStringList(void (*func)(PHYSFS_StringCallback, void *))
+{
+    EnumStringListCallbackData ecd;
+    memset(&ecd, '\0', sizeof (ecd));
+    ecd.list = (char **) allocator.Malloc(sizeof (char *));
+    BAIL_IF_MACRO(ecd.list == NULL, ERR_OUT_OF_MEMORY, NULL);
+    func(enumStringListCallback, &ecd);
+    BAIL_IF_MACRO(ecd.errorstr != NULL, ecd.errorstr, NULL);
+    ecd.list[ecd.size] = NULL;
+    return(ecd.list);
+} /* doEnumStringList */
+
+
+static void __PHYSFS_bubble_sort(void *a, PHYSFS_uint32 lo, PHYSFS_uint32 hi,
+                         int (*cmpfn)(void *, PHYSFS_uint32, PHYSFS_uint32),
+                         void (*swapfn)(void *, PHYSFS_uint32, PHYSFS_uint32))
+{
+    PHYSFS_uint32 i;
+    int sorted;
+
+    do
+    {
+        sorted = 1;
+        for (i = lo; i < hi; i++)
+        {
+            if (cmpfn(a, i, i + 1) > 0)
+            {
+                swapfn(a, i, i + 1);
+                sorted = 0;
+            } /* if */
+        } /* for */
+    } while (!sorted);
+} /* __PHYSFS_bubble_sort */
+
+
+static void __PHYSFS_quick_sort(void *a, PHYSFS_uint32 lo, PHYSFS_uint32 hi,
+                         int (*cmpfn)(void *, PHYSFS_uint32, PHYSFS_uint32),
+                         void (*swapfn)(void *, PHYSFS_uint32, PHYSFS_uint32))
+{
+    PHYSFS_uint32 i;
+    PHYSFS_uint32 j;
+    PHYSFS_uint32 v;
+
+    if ((hi - lo) <= PHYSFS_QUICKSORT_THRESHOLD)
+        __PHYSFS_bubble_sort(a, lo, hi, cmpfn, swapfn);
+    else
+    {
+        i = (hi + lo) / 2;
+
+        if (cmpfn(a, lo, i) > 0) swapfn(a, lo, i);
+        if (cmpfn(a, lo, hi) > 0) swapfn(a, lo, hi);
+        if (cmpfn(a, i, hi) > 0) swapfn(a, i, hi);
+
+        j = hi - 1;
+        swapfn(a, i, j);
+        i = lo;
+        v = j;
+        while (1)
+        {
+            while(cmpfn(a, ++i, v) < 0) { /* do nothing */ }
+            while(cmpfn(a, --j, v) > 0) { /* do nothing */ }
+            if (j < i)
+                break;
+            swapfn(a, i, j);
+        } /* while */
+        swapfn(a, i, hi-1);
+        __PHYSFS_quick_sort(a, lo, j, cmpfn, swapfn);
+        __PHYSFS_quick_sort(a, i+1, hi, cmpfn, swapfn);
+    } /* else */
+} /* __PHYSFS_quick_sort */
+
+
+void __PHYSFS_sort(void *entries, PHYSFS_uint32 max,
+                   int (*cmpfn)(void *, PHYSFS_uint32, PHYSFS_uint32),
+                   void (*swapfn)(void *, PHYSFS_uint32, PHYSFS_uint32))
+{
+    /*
+     * Quicksort w/ Bubblesort fallback algorithm inspired by code from here:
+     *   http://www.cs.ubc.ca/spider/harrison/Java/sorting-demo.html
+     */
+    __PHYSFS_quick_sort(entries, 0, max - 1, cmpfn, swapfn);
+} /* __PHYSFS_sort */
+
+
+static ErrMsg *findErrorForCurrentThread(void)
+{
+    ErrMsg *i;
+    PHYSFS_uint64 tid;
+
+    if (errorLock != NULL)
+        __PHYSFS_platformGrabMutex(errorLock);
+
+    if (errorMessages != NULL)
+    {
+        tid = __PHYSFS_platformGetThreadID();
+
+        for (i = errorMessages; i != NULL; i = i->next)
+        {
+            if (i->tid == tid)
+            {
+                if (errorLock != NULL)
+                    __PHYSFS_platformReleaseMutex(errorLock);
+                return(i);
+            } /* if */
+        } /* for */
+    } /* if */
+
+    if (errorLock != NULL)
+        __PHYSFS_platformReleaseMutex(errorLock);
+
+    return(NULL);   /* no error available. */
+} /* findErrorForCurrentThread */
+
+
+void __PHYSFS_setError(const char *str)
+{
+    ErrMsg *err;
+
+    if (str == NULL)
+        return;
+
+    err = findErrorForCurrentThread();
+
+    if (err == NULL)
+    {
+        err = (ErrMsg *) allocator.Malloc(sizeof (ErrMsg));
+        if (err == NULL)
+            return;   /* uhh...? */
+
+        memset((void *) err, '\0', sizeof (ErrMsg));
+        err->tid = __PHYSFS_platformGetThreadID();
+
+        if (errorLock != NULL)
+            __PHYSFS_platformGrabMutex(errorLock);
+
+        err->next = errorMessages;
+        errorMessages = err;
+
+        if (errorLock != NULL)
+            __PHYSFS_platformReleaseMutex(errorLock);
+    } /* if */
+
+    err->errorAvailable = 1;
+    strncpy(err->errorString, str, sizeof (err->errorString));
+    err->errorString[sizeof (err->errorString) - 1] = '\0';
+} /* __PHYSFS_setError */
+
+
+const char *PHYSFS_getLastError(void)
+{
+    ErrMsg *err = findErrorForCurrentThread();
+
+    if ((err == NULL) || (!err->errorAvailable))
+        return(NULL);
+
+    err->errorAvailable = 0;
+    return(err->errorString);
+} /* PHYSFS_getLastError */
+
+
+/* MAKE SURE that errorLock is held before calling this! */
+static void freeErrorMessages(void)
+{
+    ErrMsg *i;
+    ErrMsg *next;
+
+    for (i = errorMessages; i != NULL; i = next)
+    {
+        next = i->next;
+        allocator.Free(i);
+    } /* for */
+
+    errorMessages = NULL;
+} /* freeErrorMessages */
+
+
+void PHYSFS_getLinkedVersion(PHYSFS_Version *ver)
+{
+    if (ver != NULL)
+    {
+        ver->major = PHYSFS_VER_MAJOR;
+        ver->minor = PHYSFS_VER_MINOR;
+        ver->patch = PHYSFS_VER_PATCH;
+    } /* if */
+} /* PHYSFS_getLinkedVersion */
+
+
+static const char *find_filename_extension(const char *fname)
+{
+    const char *retval = strchr(fname, '.');
+    const char *p = retval;
+
+    while (p != NULL)
+    {
+        p = strchr(p + 1, '.');
+        if (p != NULL)
+            retval = p;
+    } /* while */
+
+    if (retval != NULL)
+        retval++;  /* skip '.' */
+
+    return(retval);
+} /* find_filename_extension */
+
+
+static DirHandle *tryOpenDir(const PHYSFS_Archiver *funcs,
+                             const char *d, int forWriting)
+{
+    DirHandle *retval = NULL;
+    if (funcs->isArchive(d, forWriting))
+    {
+        void *opaque = funcs->openArchive(d, forWriting);
+        if (opaque != NULL)
+        {
+            retval = (DirHandle *) allocator.Malloc(sizeof (DirHandle));
+            if (retval == NULL)
+                funcs->dirClose(opaque);
+            else
+            {
+                memset(retval, '\0', sizeof (DirHandle));
+                retval->mountPoint = NULL;
+                retval->funcs = funcs;
+                retval->opaque = opaque;
+            } /* else */
+        } /* if */
+    } /* if */
+
+    return(retval);
+} /* tryOpenDir */
+
+
+static DirHandle *openDirectory(const char *d, int forWriting)
+{
+    DirHandle *retval = NULL;
+    const PHYSFS_Archiver **i;
+    const char *ext;
+
+    BAIL_IF_MACRO(!__PHYSFS_platformExists(d), ERR_NO_SUCH_FILE, NULL);
+
+    ext = find_filename_extension(d);
+    if (ext != NULL)
+    {
+        /* Look for archivers with matching file extensions first... */
+        for (i = archivers; (*i != NULL) && (retval == NULL); i++)
+        {
+            if (__PHYSFS_stricmpASCII(ext, (*i)->info->extension) == 0)
+                retval = tryOpenDir(*i, d, forWriting);
+        } /* for */
+
+        /* failing an exact file extension match, try all the others... */
+        for (i = archivers; (*i != NULL) && (retval == NULL); i++)
+        {
+            if (__PHYSFS_stricmpASCII(ext, (*i)->info->extension) != 0)
+                retval = tryOpenDir(*i, d, forWriting);
+        } /* for */
+    } /* if */
+
+    else  /* no extension? Try them all. */
+    {
+        for (i = archivers; (*i != NULL) && (retval == NULL); i++)
+            retval = tryOpenDir(*i, d, forWriting);
+    } /* else */
+
+    BAIL_IF_MACRO(retval == NULL, ERR_UNSUPPORTED_ARCHIVE, NULL);
+    return(retval);
+} /* openDirectory */
+
+
+/*
+ * Make a platform-independent path string sane. Doesn't actually check the
+ *  file hierarchy, it just cleans up the string.
+ *  (dst) must be a buffer at least as big as (src), as this is where the
+ *  cleaned up string is deposited.
+ * If there are illegal bits in the path (".." entries, etc) then we
+ *  return zero and (dst) is undefined. Non-zero if the path was sanitized.
+ */
+static int sanitizePlatformIndependentPath(const char *src, char *dst)
+{
+    char *prev;
+    char ch;
+
+    while (*src == '/')  /* skip initial '/' chars... */
+        src++;
+
+    prev = dst;
+    do
+    {
+        ch = *(src++);
+
+        if ((ch == ':') || (ch == '\\'))  /* illegal chars in a physfs path. */
+            BAIL_MACRO(ERR_INSECURE_FNAME, 0);
+
+        if (ch == '/')   /* path separator. */
+        {
+            *dst = '\0';  /* "." and ".." are illegal pathnames. */
+            if ((strcmp(prev, ".") == 0) || (strcmp(prev, "..") == 0))
+                BAIL_MACRO(ERR_INSECURE_FNAME, 0);
+
+            while (*src == '/')   /* chop out doubles... */
+                src++;
+
+            if (*src == '\0') /* ends with a pathsep? */
+                break;  /* we're done, don't add final pathsep to dst. */
+
+            prev = dst + 1;
+        } /* if */
+
+        *(dst++) = ch;
+    } while (ch != '\0');
+
+    return(1);
+} /* sanitizePlatformIndependentPath */
+
+
+/*
+ * Figure out if (fname) is part of (h)'s mountpoint. (fname) must be an
+ *  output from sanitizePlatformIndependentPath(), so that it is in a known
+ *  state.
+ *
+ * This only finds legitimate segments of a mountpoint. If the mountpoint is
+ *  "/a/b/c" and (fname) is "/a/b/c", "/", or "/a/b/c/d", then the results are
+ *  all zero. "/a/b" will succeed, though.
+ */
+static int partOfMountPoint(DirHandle *h, char *fname)
+{
+    /* !!! FIXME: This code feels gross. */
+    int rc;
+    size_t len, mntpntlen;
+
+    if (h->mountPoint == NULL)
+        return(0);
+    else if (*fname == '\0')
+        return(1);
+
+    len = strlen(fname);
+    mntpntlen = strlen(h->mountPoint);
+    if (len > mntpntlen)  /* can't be a subset of mountpoint. */
+        return(0);
+
+    /* if true, must be not a match or a complete match, but not a subset. */
+    if ((len + 1) == mntpntlen)
+        return(0);
+
+    rc = strncmp(fname, h->mountPoint, len); /* !!! FIXME: case insensitive? */
+    if (rc != 0)
+        return(0);  /* not a match. */
+
+    /* make sure /a/b matches /a/b/ and not /a/bc ... */
+    return(h->mountPoint[len] == '/');
+} /* partOfMountPoint */
+
+
+static DirHandle *createDirHandle(const char *newDir,
+                                  const char *mountPoint,
+                                  int forWriting)
+{
+    DirHandle *dirHandle = NULL;
+    char *tmpmntpnt = NULL;
+
+    GOTO_IF_MACRO(!newDir, ERR_INVALID_ARGUMENT, badDirHandle);
+    if (mountPoint != NULL)
+    {
+        const size_t len = strlen(mountPoint) + 1;
+        tmpmntpnt = (char *) __PHYSFS_smallAlloc(len);
+        GOTO_IF_MACRO(!tmpmntpnt, ERR_OUT_OF_MEMORY, badDirHandle);
+        if (!sanitizePlatformIndependentPath(mountPoint, tmpmntpnt))
+            goto badDirHandle;
+        mountPoint = tmpmntpnt;  /* sanitized version. */
+    } /* if */
+
+    dirHandle = openDirectory(newDir, forWriting);
+    GOTO_IF_MACRO(!dirHandle, NULL, badDirHandle);
+
+    dirHandle->dirName = (char *) allocator.Malloc(strlen(newDir) + 1);
+    GOTO_IF_MACRO(!dirHandle->dirName, ERR_OUT_OF_MEMORY, badDirHandle);
+    strcpy(dirHandle->dirName, newDir);
+
+    if ((mountPoint != NULL) && (*mountPoint != '\0'))
+    {
+        dirHandle->mountPoint = (char *)allocator.Malloc(strlen(mountPoint)+2);
+        GOTO_IF_MACRO(!dirHandle->mountPoint, ERR_OUT_OF_MEMORY, badDirHandle);
+        strcpy(dirHandle->mountPoint, mountPoint);
+        strcat(dirHandle->mountPoint, "/");
+    } /* if */
+
+    __PHYSFS_smallFree(tmpmntpnt);
+    return(dirHandle);
+
+badDirHandle:
+    if (dirHandle != NULL)
+    {
+        dirHandle->funcs->dirClose(dirHandle->opaque);
+        allocator.Free(dirHandle->dirName);
+        allocator.Free(dirHandle->mountPoint);
+        allocator.Free(dirHandle);
+    } /* if */
+
+    __PHYSFS_smallFree(tmpmntpnt);
+    return(NULL);
+} /* createDirHandle */
+
+
+/* MAKE SURE you've got the stateLock held before calling this! */
+static int freeDirHandle(DirHandle *dh, FileHandle *openList)
+{
+    FileHandle *i;
+
+    if (dh == NULL)
+        return(1);
+
+    for (i = openList; i != NULL; i = i->next)
+        BAIL_IF_MACRO(i->dirHandle == dh, ERR_FILES_STILL_OPEN, 0);
+
+    dh->funcs->dirClose(dh->opaque);
+    allocator.Free(dh->dirName);
+    allocator.Free(dh->mountPoint);
+    allocator.Free(dh);
+    return(1);
+} /* freeDirHandle */
+
+
+static char *calculateUserDir(void)
+{
+    char *retval = NULL;
+    const char *str = NULL;
+
+    str = __PHYSFS_platformGetUserDir();
+    if (str != NULL)
+        retval = (char *) str;
+    else
+    {
+        const char *dirsep = PHYSFS_getDirSeparator();
+        const char *uname = __PHYSFS_platformGetUserName();
+
+        str = (uname != NULL) ? uname : "default";
+        retval = (char *) allocator.Malloc(strlen(baseDir) + strlen(str) +
+                                           strlen(dirsep) + 6);
+
+        if (retval == NULL)
+            __PHYSFS_setError(ERR_OUT_OF_MEMORY);
+        else
+            sprintf(retval, "%susers%s%s", baseDir, dirsep, str);
+
+        allocator.Free((void *) uname);
+    } /* else */
+
+    return(retval);
+} /* calculateUserDir */
+
+
+static int appendDirSep(char **dir)
+{
+    const char *dirsep = PHYSFS_getDirSeparator();
+    char *ptr;
+
+    if (strcmp((*dir + strlen(*dir)) - strlen(dirsep), dirsep) == 0)
+        return(1);
+
+    ptr = (char *) allocator.Realloc(*dir, strlen(*dir) + strlen(dirsep) + 1);
+    if (!ptr)
+    {
+        allocator.Free(*dir);
+        return(0);
+    } /* if */
+
+    strcat(ptr, dirsep);
+    *dir = ptr;
+    return(1);
+} /* appendDirSep */
+
+
+static char *calculateBaseDir(const char *argv0)
+{
+    char *retval = NULL;
+    const char *dirsep = NULL;
+    char *ptr = NULL;
+
+    /* Give the platform layer first shot at this. */
+    retval = __PHYSFS_platformCalcBaseDir(argv0);
+    if (retval != NULL)
+        return(retval);
+
+    /* We need argv0 to go on. */
+    BAIL_IF_MACRO(argv0 == NULL, ERR_ARGV0_IS_NULL, NULL);
+
+    dirsep = PHYSFS_getDirSeparator();
+    if (strlen(dirsep) == 1)  /* fast path. */
+        ptr = strrchr(argv0, *dirsep);
+    else
+    {
+        ptr = strstr(argv0, dirsep);
+        if (ptr != NULL)
+        {
+            char *p = ptr;
+            while (p != NULL)
+            {
+                ptr = p;
+                p = strstr(p + 1, dirsep);
+            } /* while */
+        } /* if */
+    } /* else */
+
+    if (ptr != NULL)
+    {
+        size_t size = (size_t) (ptr - argv0);
+        retval = (char *) allocator.Malloc(size + 1);
+        BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+        memcpy(retval, argv0, size);
+        retval[size] = '\0';
+        return(retval);
+    } /* if */
+
+    /* argv0 wasn't helpful. */
+    BAIL_MACRO(ERR_INVALID_ARGUMENT, NULL);
+    return(NULL);
+} /* calculateBaseDir */
+
+
+static int initializeMutexes(void)
+{
+    errorLock = __PHYSFS_platformCreateMutex();
+    if (errorLock == NULL)
+        goto initializeMutexes_failed;
+
+    stateLock = __PHYSFS_platformCreateMutex();
+    if (stateLock == NULL)
+        goto initializeMutexes_failed;
+
+    return(1);  /* success. */
+
+initializeMutexes_failed:
+    if (errorLock != NULL)
+        __PHYSFS_platformDestroyMutex(errorLock);
+
+    if (stateLock != NULL)
+        __PHYSFS_platformDestroyMutex(stateLock);
+
+    errorLock = stateLock = NULL;
+    return(0);  /* failed. */
+} /* initializeMutexes */
+
+
+static void setDefaultAllocator(void);
+
+int PHYSFS_init(const char *argv0)
+{
+    char *ptr;
+
+    BAIL_IF_MACRO(initialized, ERR_IS_INITIALIZED, 0);
+
+    if (!externalAllocator)
+        setDefaultAllocator();
+
+    if (allocator.Init != NULL)
+        BAIL_IF_MACRO(!allocator.Init(), NULL, 0);
+
+    BAIL_IF_MACRO(!__PHYSFS_platformInit(), NULL, 0);
+
+    BAIL_IF_MACRO(!initializeMutexes(), NULL, 0);
+
+    baseDir = calculateBaseDir(argv0);
+    BAIL_IF_MACRO(baseDir == NULL, NULL, 0);
+
+    /* !!! FIXME: only call this if we got this from argv0 (unreliable). */
+    ptr = __PHYSFS_platformRealPath(baseDir);
+    allocator.Free(baseDir);
+    BAIL_IF_MACRO(ptr == NULL, NULL, 0);
+    baseDir = ptr;
+
+    BAIL_IF_MACRO(!appendDirSep(&baseDir), NULL, 0);
+
+    userDir = calculateUserDir();
+    if (userDir != NULL)
+    {
+        ptr = __PHYSFS_platformRealPath(userDir);
+        allocator.Free(userDir);
+        userDir = ptr;
+    } /* if */
+
+    if ((userDir == NULL) || (!appendDirSep(&userDir)))
+    {
+        allocator.Free(baseDir);
+        baseDir = NULL;
+        return(0);
+    } /* if */
+
+    initialized = 1;
+
+    /* This makes sure that the error subsystem is initialized. */
+    __PHYSFS_setError(PHYSFS_getLastError());
+
+    return(1);
+} /* PHYSFS_init */
+
+
+/* MAKE SURE you hold stateLock before calling this! */
+static int closeFileHandleList(FileHandle **list)
+{
+    FileHandle *i;
+    FileHandle *next = NULL;
+
+    for (i = *list; i != NULL; i = next)
+    {
+        next = i->next;
+        if (!i->funcs->fileClose(i->opaque))
+        {
+            *list = i;
+            return(0);
+        } /* if */
+
+        allocator.Free(i);
+    } /* for */
+
+    *list = NULL;
+    return(1);
+} /* closeFileHandleList */
+
+
+/* MAKE SURE you hold the stateLock before calling this! */
+static void freeSearchPath(void)
+{
+    DirHandle *i;
+    DirHandle *next = NULL;
+
+    closeFileHandleList(&openReadList);
+
+    if (searchPath != NULL)
+    {
+        for (i = searchPath; i != NULL; i = next)
+        {
+            next = i->next;
+            freeDirHandle(i, openReadList);
+        } /* for */
+        searchPath = NULL;
+    } /* if */
+} /* freeSearchPath */
+
+
+int PHYSFS_deinit(void)
+{
+    BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0);
+    BAIL_IF_MACRO(!__PHYSFS_platformDeinit(), NULL, 0);
+
+    closeFileHandleList(&openWriteList);
+    BAIL_IF_MACRO(!PHYSFS_setWriteDir(NULL), ERR_FILES_STILL_OPEN, 0);
+
+    freeSearchPath();
+    freeErrorMessages();
+
+    if (baseDir != NULL)
+    {
+        allocator.Free(baseDir);
+        baseDir = NULL;
+    } /* if */
+
+    if (userDir != NULL)
+    {
+        allocator.Free(userDir);
+        userDir = NULL;
+    } /* if */
+
+    allowSymLinks = 0;
+    initialized = 0;
+
+    __PHYSFS_platformDestroyMutex(errorLock);
+    __PHYSFS_platformDestroyMutex(stateLock);
+
+    if (allocator.Deinit != NULL)
+        allocator.Deinit();
+
+    errorLock = stateLock = NULL;
+    return(1);
+} /* PHYSFS_deinit */
+
+
+int PHYSFS_isInit(void)
+{
+    return(initialized);
+} /* PHYSFS_isInit */
+
+
+const PHYSFS_ArchiveInfo **PHYSFS_supportedArchiveTypes(void)
+{
+    return(supported_types);
+} /* PHYSFS_supportedArchiveTypes */
+
+
+void PHYSFS_freeList(void *list)
+{
+    void **i;
+    for (i = (void **) list; *i != NULL; i++)
+        allocator.Free(*i);
+
+    allocator.Free(list);
+} /* PHYSFS_freeList */
+
+
+const char *PHYSFS_getDirSeparator(void)
+{
+    return(__PHYSFS_platformDirSeparator);
+} /* PHYSFS_getDirSeparator */
+
+
+char **PHYSFS_getCdRomDirs(void)
+{
+    return(doEnumStringList(__PHYSFS_platformDetectAvailableCDs));
+} /* PHYSFS_getCdRomDirs */
+
+
+void PHYSFS_getCdRomDirsCallback(PHYSFS_StringCallback callback, void *data)
+{
+    __PHYSFS_platformDetectAvailableCDs(callback, data);
+} /* PHYSFS_getCdRomDirsCallback */
+
+
+const char *PHYSFS_getBaseDir(void)
+{
+    return(baseDir);   /* this is calculated in PHYSFS_init()... */
+} /* PHYSFS_getBaseDir */
+
+
+const char *PHYSFS_getUserDir(void)
+{
+    return(userDir);   /* this is calculated in PHYSFS_init()... */
+} /* PHYSFS_getUserDir */
+
+
+const char *PHYSFS_getWriteDir(void)
+{
+    const char *retval = NULL;
+
+    __PHYSFS_platformGrabMutex(stateLock);
+    if (writeDir != NULL)
+        retval = writeDir->dirName;
+    __PHYSFS_platformReleaseMutex(stateLock);
+
+    return(retval);
+} /* PHYSFS_getWriteDir */
+
+
+int PHYSFS_setWriteDir(const char *newDir)
+{
+    int retval = 1;
+
+    __PHYSFS_platformGrabMutex(stateLock);
+
+    if (writeDir != NULL)
+    {
+        BAIL_IF_MACRO_MUTEX(!freeDirHandle(writeDir, openWriteList), NULL,
+                            stateLock, 0);
+        writeDir = NULL;
+    } /* if */
+
+    if (newDir != NULL)
+    {
+        writeDir = createDirHandle(newDir, NULL, 1);
+        retval = (writeDir != NULL);
+    } /* if */
+
+    __PHYSFS_platformReleaseMutex(stateLock);
+
+    return(retval);
+} /* PHYSFS_setWriteDir */
+
+
+int PHYSFS_mount(const char *newDir, const char *mountPoint, int appendToPath)
+{
+    DirHandle *dh;
+    DirHandle *prev = NULL;
+    DirHandle *i;
+
+    BAIL_IF_MACRO(newDir == NULL, ERR_INVALID_ARGUMENT, 0);
+
+    if (mountPoint == NULL)
+        mountPoint = "/";
+
+    __PHYSFS_platformGrabMutex(stateLock);
+
+    for (i = searchPath; i != NULL; i = i->next)
+    {
+        /* already in search path? */
+        BAIL_IF_MACRO_MUTEX(strcmp(newDir, i->dirName)==0, NULL, stateLock, 1);
+        prev = i;
+    } /* for */
+
+    dh = createDirHandle(newDir, mountPoint, 0);
+    BAIL_IF_MACRO_MUTEX(dh == NULL, NULL, stateLock, 0);
+
+    if (appendToPath)
+    {
+        if (prev == NULL)
+            searchPath = dh;
+        else
+            prev->next = dh;
+    } /* if */
+    else
+    {
+        dh->next = searchPath;
+        searchPath = dh;
+    } /* else */
+
+    __PHYSFS_platformReleaseMutex(stateLock);
+    return(1);
+} /* PHYSFS_mount */
+
+
+int PHYSFS_addToSearchPath(const char *newDir, int appendToPath)
+{
+    return(PHYSFS_mount(newDir, NULL, appendToPath));
+} /* PHYSFS_addToSearchPath */
+
+
+int PHYSFS_removeFromSearchPath(const char *oldDir)
+{
+    DirHandle *i;
+    DirHandle *prev = NULL;
+    DirHandle *next = NULL;
+
+    BAIL_IF_MACRO(oldDir == NULL, ERR_INVALID_ARGUMENT, 0);
+
+    __PHYSFS_platformGrabMutex(stateLock);
+    for (i = searchPath; i != NULL; i = i->next)
+    {
+        if (strcmp(i->dirName, oldDir) == 0)
+        {
+            next = i->next;
+            BAIL_IF_MACRO_MUTEX(!freeDirHandle(i, openReadList), NULL,
+                                stateLock, 0);
+
+            if (prev == NULL)
+                searchPath = next;
+            else
+                prev->next = next;
+
+            BAIL_MACRO_MUTEX(NULL, stateLock, 1);
+        } /* if */
+        prev = i;
+    } /* for */
+
+    BAIL_MACRO_MUTEX(ERR_NOT_IN_SEARCH_PATH, stateLock, 0);
+} /* PHYSFS_removeFromSearchPath */
+
+
+char **PHYSFS_getSearchPath(void)
+{
+    return(doEnumStringList(PHYSFS_getSearchPathCallback));
+} /* PHYSFS_getSearchPath */
+
+
+const char *PHYSFS_getMountPoint(const char *dir)
+{
+    DirHandle *i;
+    __PHYSFS_platformGrabMutex(stateLock);
+    for (i = searchPath; i != NULL; i = i->next)
+    {
+        if (strcmp(i->dirName, dir) == 0)
+        {
+            const char *retval = ((i->mountPoint) ? i->mountPoint : "/");
+            __PHYSFS_platformReleaseMutex(stateLock);
+            return(retval);
+        } /* if */
+    } /* for */
+    __PHYSFS_platformReleaseMutex(stateLock);
+
+    BAIL_MACRO(ERR_NOT_IN_SEARCH_PATH, NULL);
+} /* PHYSFS_getMountPoint */
+
+
+void PHYSFS_getSearchPathCallback(PHYSFS_StringCallback callback, void *data)
+{
+    DirHandle *i;
+
+    __PHYSFS_platformGrabMutex(stateLock);
+
+    for (i = searchPath; i != NULL; i = i->next)
+        callback(data, i->dirName);
+
+    __PHYSFS_platformReleaseMutex(stateLock);
+} /* PHYSFS_getSearchPathCallback */
+
+
+/* Split out to avoid stack allocation in a loop. */
+static void setSaneCfgAddPath(const char *i, const size_t l, const char *dirsep,
+                              int archivesFirst)
+{
+    const char *d = PHYSFS_getRealDir(i);
+    const size_t allocsize = strlen(d) + strlen(dirsep) + l + 1;
+    char *str = (char *) __PHYSFS_smallAlloc(allocsize);
+    if (str != NULL)
+    {
+        sprintf(str, "%s%s%s", d, dirsep, i);
+        PHYSFS_addToSearchPath(str, archivesFirst == 0);
+        __PHYSFS_smallFree(str);
+    } /* if */
+} /* setSaneCfgAddPath */
+
+
+int PHYSFS_setSaneConfig(const char *organization, const char *appName,
+                         const char *archiveExt, int includeCdRoms,
+                         int archivesFirst)
+{
+    const char *basedir = PHYSFS_getBaseDir();
+    const char *userdir = PHYSFS_getUserDir();
+    const char *dirsep = PHYSFS_getDirSeparator();
+    PHYSFS_uint64 len = 0;
+    char *str = NULL;
+
+    BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0);
+
+    /* set write dir... */
+    len = (strlen(userdir) + (strlen(organization) * 2) +
+            (strlen(appName) * 2) + (strlen(dirsep) * 3) + 2);
+
+    str = (char *) __PHYSFS_smallAlloc(len);
+
+    BAIL_IF_MACRO(str == NULL, ERR_OUT_OF_MEMORY, 0);
+    sprintf(str, "%s.%s%s%s", userdir, organization, dirsep, appName);
+
+    if (!PHYSFS_setWriteDir(str))
+    {
+        int no_write = 0;
+        sprintf(str, ".%s/%s", organization, appName);
+        if ( (PHYSFS_setWriteDir(userdir)) &&
+             (PHYSFS_mkdir(str)) )
+        {
+            sprintf(str, "%s.%s%s%s", userdir, organization, dirsep, appName);
+            if (!PHYSFS_setWriteDir(str))
+                no_write = 1;
+        } /* if */
+        else
+        {
+            no_write = 1;
+        } /* else */
+
+        if (no_write)
+        {
+            PHYSFS_setWriteDir(NULL);   /* just in case. */
+            __PHYSFS_smallFree(str);
+            BAIL_MACRO(ERR_CANT_SET_WRITE_DIR, 0);
+        } /* if */
+    } /* if */
+
+    /* Put write dir first in search path... */
+    PHYSFS_addToSearchPath(str, 0);
+    __PHYSFS_smallFree(str);
+
+        /* Put base path on search path... */
+    PHYSFS_addToSearchPath(basedir, 1);
+
+        /* handle CD-ROMs... */
+    if (includeCdRoms)
+    {
+        char **cds = PHYSFS_getCdRomDirs();
+        char **i;
+        for (i = cds; *i != NULL; i++)
+            PHYSFS_addToSearchPath(*i, 1);
+
+        PHYSFS_freeList(cds);
+    } /* if */
+
+        /* Root out archives, and add them to search path... */
+    if (archiveExt != NULL)
+    {
+        char **rc = PHYSFS_enumerateFiles("/");
+        char **i;
+        size_t extlen = strlen(archiveExt);
+        char *ext;
+
+        for (i = rc; *i != NULL; i++)
+        {
+            size_t l = strlen(*i);
+            if ((l > extlen) && ((*i)[l - extlen - 1] == '.'))
+            {
+                ext = (*i) + (l - extlen);
+                if (__PHYSFS_stricmpASCII(ext, archiveExt) == 0)
+                    setSaneCfgAddPath(*i, l, dirsep, archivesFirst);
+            } /* if */
+        } /* for */
+
+        PHYSFS_freeList(rc);
+    } /* if */
+
+    return(1);
+} /* PHYSFS_setSaneConfig */
+
+
+void PHYSFS_permitSymbolicLinks(int allow)
+{
+    allowSymLinks = allow;
+} /* PHYSFS_permitSymbolicLinks */
+
+
+int PHYSFS_symbolicLinksPermitted(void)
+{
+    return(allowSymLinks);
+} /* PHYSFS_symbolicLinksPermitted */
+
+
+/* string manipulation in C makes my ass itch. */
+char *__PHYSFS_convertToDependent(const char *prepend,
+                                  const char *dirName,
+                                  const char *append)
+{
+    const char *dirsep = __PHYSFS_platformDirSeparator;
+    size_t sepsize = strlen(dirsep);
+    char *str;
+    char *i1;
+    char *i2;
+    size_t allocSize;
+
+    while (*dirName == '/')  /* !!! FIXME: pass through sanitize function. */
+        dirName++;
+
+    allocSize = strlen(dirName) + 1;
+    if (prepend != NULL)
+        allocSize += strlen(prepend) + sepsize;
+    if (append != NULL)
+        allocSize += strlen(append) + sepsize;
+
+    /* make sure there's enough space if the dir separator is bigger. */
+    if (sepsize > 1)
+    {
+        str = (char *) dirName;
+        do
+        {
+            str = strchr(str, '/');
+            if (str != NULL)
+            {
+                allocSize += (sepsize - 1);
+                str++;
+            } /* if */
+        } while (str != NULL);
+    } /* if */
+
+    str = (char *) allocator.Malloc(allocSize);
+    BAIL_IF_MACRO(str == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+    if (prepend == NULL)
+        *str = '\0';
+    else
+    {
+        strcpy(str, prepend);
+        strcat(str, dirsep);
+    } /* else */
+
+    for (i1 = (char *) dirName, i2 = str + strlen(str); *i1; i1++, i2++)
+    {
+        if (*i1 == '/')
+        {
+            strcpy(i2, dirsep);
+            i2 += sepsize;
+        } /* if */
+        else
+        {
+            *i2 = *i1;
+        } /* else */
+    } /* for */
+    *i2 = '\0';
+
+    if (append)
+    {
+        strcat(str, dirsep);
+        strcat(str, append);
+    } /* if */
+
+    return(str);
+} /* __PHYSFS_convertToDependent */
+
+
+/*
+ * Verify that (fname) (in platform-independent notation), in relation
+ *  to (h) is secure. That means that each element of fname is checked
+ *  for symlinks (if they aren't permitted). This also allows for quick
+ *  rejection of files that exist outside an archive's mountpoint.
+ *
+ * With some exceptions (like PHYSFS_mkdir(), which builds multiple subdirs
+ *  at a time), you should always pass zero for "allowMissing" for efficiency.
+ *
+ * (fname) must point to an output from sanitizePlatformIndependentPath(),
+ *  since it will make sure that path names are in the right format for
+ *  passing certain checks. It will also do checks for "insecure" pathnames
+ *  like ".." which should be done once instead of once per archive. This also
+ *  gives us license to treat (fname) as scratch space in this function.
+ *
+ * Returns non-zero if string is safe, zero if there's a security issue.
+ *  PHYSFS_getLastError() will specify what was wrong. (*fname) will be
+ *  updated to point past any mount point elements so it is prepared to
+ *  be used with the archiver directly.
+ */
+static int verifyPath(DirHandle *h, char **_fname, int allowMissing)
+{
+    char *fname = *_fname;
+    int retval = 1;
+    char *start;
+    char *end;
+
+    if (*fname == '\0')  /* quick rejection. */
+        return(1);
+
+    /* !!! FIXME: This codeblock sucks. */
+    if (h->mountPoint != NULL)  /* NULL mountpoint means "/". */
+    {
+        size_t mntpntlen = strlen(h->mountPoint);
+        size_t len = strlen(fname);
+        assert(mntpntlen > 1); /* root mount points should be NULL. */
+        /* not under the mountpoint, so skip this archive. */
+        BAIL_IF_MACRO(len < mntpntlen-1, ERR_NO_SUCH_PATH, 0);
+        /* !!! FIXME: Case insensitive? */
+        retval = strncmp(h->mountPoint, fname, mntpntlen-1);
+        BAIL_IF_MACRO(retval != 0, ERR_NO_SUCH_PATH, 0);
+        if (len > mntpntlen-1)  /* corner case... */
+            BAIL_IF_MACRO(fname[mntpntlen-1] != '/', ERR_NO_SUCH_PATH, 0);
+        fname += mntpntlen-1;  /* move to start of actual archive path. */
+        if (*fname == '/')
+            fname++;
+        *_fname = fname;  /* skip mountpoint for later use. */
+        retval = 1;  /* may be reset, below. */
+    } /* if */
+
+    start = fname;
+    if (!allowSymLinks)
+    {
+        while (1)
+        {
+            int rc = 0;
+            end = strchr(start, '/');
+
+            if (end != NULL) *end = '\0';
+            rc = h->funcs->isSymLink(h->opaque, fname, &retval);
+            if (end != NULL) *end = '/';
+
+            BAIL_IF_MACRO(rc, ERR_SYMLINK_DISALLOWED, 0);   /* insecure. */
+
+            /* break out early if path element is missing. */
+            if (!retval)
+            {
+                /*
+                 * We need to clear it if it's the last element of the path,
+                 *  since this might be a non-existant file we're opening
+                 *  for writing...
+                 */
+                if ((end == NULL) || (allowMissing))
+                    retval = 1;
+                break;
+            } /* if */
+
+            if (end == NULL)
+                break;
+
+            start = end + 1;
+        } /* while */
+    } /* if */
+
+    return(retval);
+} /* verifyPath */
+
+
+static int doMkdir(const char *_dname, char *dname)
+{
+    DirHandle *h;
+    char *start;
+    char *end;
+    int retval = 0;
+    int exists = 1;  /* force existance check on first path element. */
+
+    BAIL_IF_MACRO(!sanitizePlatformIndependentPath(_dname, dname), NULL, 0);
+
+    __PHYSFS_platformGrabMutex(stateLock);
+    BAIL_IF_MACRO_MUTEX(writeDir == NULL, ERR_NO_WRITE_DIR, stateLock, 0);
+    h = writeDir;
+    BAIL_IF_MACRO_MUTEX(!verifyPath(h, &dname, 1), NULL, stateLock, 0);
+
+    start = dname;
+    while (1)
+    {
+        end = strchr(start, '/');
+        if (end != NULL)
+            *end = '\0';
+
+        /* only check for existance if all parent dirs existed, too... */
+        if (exists)
+            retval = h->funcs->isDirectory(h->opaque, dname, &exists);
+
+        if (!exists)
+            retval = h->funcs->mkdir(h->opaque, dname);
+
+        if (!retval)
+            break;
+
+        if (end == NULL)
+            break;
+
+        *end = '/';
+        start = end + 1;
+    } /* while */
+
+    __PHYSFS_platformReleaseMutex(stateLock);
+    return(retval);
+} /* doMkdir */
+
+
+int PHYSFS_mkdir(const char *_dname)
+{
+    int retval = 0;
+    char *dname;
+    size_t len;
+
+    BAIL_IF_MACRO(_dname == NULL, ERR_INVALID_ARGUMENT, 0);
+    len = strlen(_dname) + 1;
+    dname = (char *) __PHYSFS_smallAlloc(len);
+    BAIL_IF_MACRO(dname == NULL, ERR_OUT_OF_MEMORY, 0);
+    retval = doMkdir(_dname, dname);
+    __PHYSFS_smallFree(dname);
+    return(retval);
+} /* PHYSFS_mkdir */
+
+
+static int doDelete(const char *_fname, char *fname)
+{
+    int retval;
+    DirHandle *h;
+    BAIL_IF_MACRO(!sanitizePlatformIndependentPath(_fname, fname), NULL, 0);
+
+    __PHYSFS_platformGrabMutex(stateLock);
+
+    BAIL_IF_MACRO_MUTEX(writeDir == NULL, ERR_NO_WRITE_DIR, stateLock, 0);
+    h = writeDir;
+    BAIL_IF_MACRO_MUTEX(!verifyPath(h, &fname, 0), NULL, stateLock, 0);
+    retval = h->funcs->remove(h->opaque, fname);
+
+    __PHYSFS_platformReleaseMutex(stateLock);
+    return(retval);
+} /* doDelete */
+
+
+int PHYSFS_delete(const char *_fname)
+{
+    int retval;
+    char *fname;
+    size_t len;
+
+    BAIL_IF_MACRO(_fname == NULL, ERR_INVALID_ARGUMENT, 0);
+    len = strlen(_fname) + 1;
+    fname = (char *) __PHYSFS_smallAlloc(len);
+    BAIL_IF_MACRO(fname == NULL, ERR_OUT_OF_MEMORY, 0);
+    retval = doDelete(_fname, fname);
+    __PHYSFS_smallFree(fname);
+    return(retval);
+} /* PHYSFS_delete */
+
+
+const char *PHYSFS_getRealDir(const char *_fname)
+{
+    const char *retval = NULL;
+    char *fname = NULL;
+    size_t len;
+
+    BAIL_IF_MACRO(_fname == NULL, ERR_INVALID_ARGUMENT, NULL);
+    len = strlen(_fname) + 1;
+    fname = __PHYSFS_smallAlloc(len);
+    BAIL_IF_MACRO(fname == NULL, ERR_OUT_OF_MEMORY, NULL);
+    if (sanitizePlatformIndependentPath(_fname, fname))
+    {
+        DirHandle *i;
+        __PHYSFS_platformGrabMutex(stateLock);
+        for (i = searchPath; ((i != NULL) && (retval == NULL)); i = i->next)
+        {
+            char *arcfname = fname;
+            if (partOfMountPoint(i, arcfname))
+                retval = i->dirName;
+            else if (verifyPath(i, &arcfname, 0))
+            {
+                if (i->funcs->exists(i->opaque, arcfname))
+                    retval = i->dirName;
+            } /* if */
+        } /* for */
+        __PHYSFS_platformReleaseMutex(stateLock);
+    } /* if */
+
+    __PHYSFS_smallFree(fname);
+    return(retval);
+} /* PHYSFS_getRealDir */
+
+
+static int locateInStringList(const char *str,
+                              char **list,
+                              PHYSFS_uint32 *pos)
+{
+    PHYSFS_uint32 len = *pos;
+    PHYSFS_uint32 half_len;
+    PHYSFS_uint32 lo = 0;
+    PHYSFS_uint32 middle;
+    int cmp;
+
+    while (len > 0)
+    {
+        half_len = len >> 1;
+        middle = lo + half_len;
+        cmp = strcmp(list[middle], str);
+
+        if (cmp == 0)  /* it's in the list already. */
+            return(1);
+        else if (cmp > 0)
+            len = half_len;
+        else
+        {
+            lo = middle + 1;
+            len -= half_len + 1;
+        } /* else */
+    } /* while */
+
+    *pos = lo;
+    return(0);
+} /* locateInStringList */
+
+
+static void enumFilesCallback(void *data, const char *origdir, const char *str)
+{
+    PHYSFS_uint32 pos;
+    void *ptr;
+    char *newstr;
+    EnumStringListCallbackData *pecd = (EnumStringListCallbackData *) data;
+
+    /*
+     * See if file is in the list already, and if not, insert it in there
+     *  alphabetically...
+     */
+    pos = pecd->size;
+    if (locateInStringList(str, pecd->list, &pos))
+        return;  /* already in the list. */
+
+    ptr = allocator.Realloc(pecd->list, (pecd->size + 2) * sizeof (char *));
+    newstr = (char *) allocator.Malloc(strlen(str) + 1);
+    if (ptr != NULL)
+        pecd->list = (char **) ptr;
+
+    if ((ptr == NULL) || (newstr == NULL))
+        return;  /* better luck next time. */
+
+    strcpy(newstr, str);
+
+    if (pos != pecd->size)
+    {
+        memmove(&pecd->list[pos+1], &pecd->list[pos],
+                 sizeof (char *) * ((pecd->size) - pos));
+    } /* if */
+
+    pecd->list[pos] = newstr;
+    pecd->size++;
+} /* enumFilesCallback */
+
+
+char **PHYSFS_enumerateFiles(const char *path)
+{
+    EnumStringListCallbackData ecd;
+    memset(&ecd, '\0', sizeof (ecd));
+    ecd.list = (char **) allocator.Malloc(sizeof (char *));
+    BAIL_IF_MACRO(ecd.list == NULL, ERR_OUT_OF_MEMORY, NULL);
+    PHYSFS_enumerateFilesCallback(path, enumFilesCallback, &ecd);
+    ecd.list[ecd.size] = NULL;
+    return(ecd.list);
+} /* PHYSFS_enumerateFiles */
+
+
+/*
+ * Broke out to seperate function so we can use stack allocation gratuitously.
+ */
+static void enumerateFromMountPoint(DirHandle *i, const char *arcfname,
+                                    PHYSFS_EnumFilesCallback callback,
+                                    const char *_fname, void *data)
+{
+    const size_t len = strlen(arcfname);
+    char *ptr = NULL;
+    char *end = NULL;
+    const size_t slen = strlen(i->mountPoint) + 1;
+    char *mountPoint = (char *) __PHYSFS_smallAlloc(slen);
+
+    if (mountPoint == NULL)
+        return;  /* oh well. */
+
+    strcpy(mountPoint, i->mountPoint);
+    ptr = mountPoint + ((len) ? len + 1 : 0);
+    end = strchr(ptr, '/');
+    assert(end);  /* should always find a terminating '/'. */
+    *end = '\0';
+    callback(data, _fname, ptr);
+    __PHYSFS_smallFree(mountPoint);
+} /* enumerateFromMountPoint */
+
+
+/* !!! FIXME: this should report error conditions. */
+void PHYSFS_enumerateFilesCallback(const char *_fname,
+                                   PHYSFS_EnumFilesCallback callback,
+                                   void *data)
+{
+    size_t len;
+    char *fname;
+
+    BAIL_IF_MACRO(_fname == NULL, ERR_INVALID_ARGUMENT, ) /*0*/;
+    BAIL_IF_MACRO(callback == NULL, ERR_INVALID_ARGUMENT, ) /*0*/;
+
+    len = strlen(_fname) + 1;
+    fname = (char *) __PHYSFS_smallAlloc(len);
+    BAIL_IF_MACRO(fname == NULL, ERR_OUT_OF_MEMORY, ) /*0*/;
+
+    if (sanitizePlatformIndependentPath(_fname, fname))
+    {
+        DirHandle *i;
+        int noSyms;
+
+        __PHYSFS_platformGrabMutex(stateLock);
+        noSyms = !allowSymLinks;
+        for (i = searchPath; i != NULL; i = i->next)
+        {
+            char *arcfname = fname;
+            if (partOfMountPoint(i, arcfname))
+                enumerateFromMountPoint(i, arcfname, callback, _fname, data);
+
+            else if (verifyPath(i, &arcfname, 0))
+            {
+                i->funcs->enumerateFiles(i->opaque, arcfname, noSyms,
+                                         callback, _fname, data);
+            } /* else if */
+        } /* for */
+        __PHYSFS_platformReleaseMutex(stateLock);
+    } /* if */
+
+    __PHYSFS_smallFree(fname);
+} /* PHYSFS_enumerateFilesCallback */
+
+
+int PHYSFS_exists(const char *fname)
+{
+    return(PHYSFS_getRealDir(fname) != NULL);
+} /* PHYSFS_exists */
+
+
+PHYSFS_sint64 PHYSFS_getLastModTime(const char *_fname)
+{
+    PHYSFS_sint64 retval = -1;
+    char *fname;
+    size_t len;
+
+    BAIL_IF_MACRO(_fname == NULL, ERR_INVALID_ARGUMENT, -1);
+    len = strlen(_fname) + 1;
+    fname = (char *) __PHYSFS_smallAlloc(len);
+    BAIL_IF_MACRO(fname == NULL, ERR_OUT_OF_MEMORY, -1);
+
+    if (sanitizePlatformIndependentPath(_fname, fname))
+    {
+        if (*fname == '\0')   /* eh...punt if it's the root dir. */
+            retval = 1;  /* !!! FIXME: Maybe this should be an error? */
+        else
+        {
+            DirHandle *i;
+            int exists = 0;
+            __PHYSFS_platformGrabMutex(stateLock);
+            for (i = searchPath; ((i != NULL) && (!exists)); i = i->next)
+            {
+                char *arcfname = fname;
+                exists = partOfMountPoint(i, arcfname);
+                if (exists)
+                    retval = 1; /* !!! FIXME: What's the right value? */
+                else if (verifyPath(i, &arcfname, 0))
+                {
+                    retval = i->funcs->getLastModTime(i->opaque, arcfname,
+                                                      &exists);
+                } /* else if */
+            } /* for */
+            __PHYSFS_platformReleaseMutex(stateLock);
+        } /* else */
+    } /* if */
+
+    __PHYSFS_smallFree(fname);
+    return(retval);
+} /* PHYSFS_getLastModTime */
+
+
+int PHYSFS_isDirectory(const char *_fname)
+{
+    int retval = 0;
+    size_t len;
+    char *fname;
+
+    BAIL_IF_MACRO(_fname == NULL, ERR_INVALID_ARGUMENT, 0);
+    len = strlen(_fname) + 1;
+    fname = (char *) __PHYSFS_smallAlloc(len);
+    BAIL_IF_MACRO(fname == NULL, ERR_OUT_OF_MEMORY, 0);
+
+    if (!sanitizePlatformIndependentPath(_fname, fname))
+        retval = 0;
+
+    else if (*fname == '\0')
+        retval = 1;  /* Root is always a dir.  :) */
+
+    else
+    {
+        DirHandle *i;
+        int exists = 0;
+
+        __PHYSFS_platformGrabMutex(stateLock);
+        for (i = searchPath; ((i != NULL) && (!exists)); i = i->next)
+        {
+            char *arcfname = fname;
+            if ((exists = partOfMountPoint(i, arcfname)) != 0)
+                retval = 1;
+            else if (verifyPath(i, &arcfname, 0))
+                retval = i->funcs->isDirectory(i->opaque, arcfname, &exists);
+        } /* for */
+        __PHYSFS_platformReleaseMutex(stateLock);
+    } /* else */
+
+    __PHYSFS_smallFree(fname);
+    return(retval);
+} /* PHYSFS_isDirectory */
+
+
+int PHYSFS_isSymbolicLink(const char *_fname)
+{
+    int retval = 0;
+    size_t len;
+    char *fname;
+
+    BAIL_IF_MACRO(!allowSymLinks, ERR_SYMLINK_DISALLOWED, 0);
+
+    BAIL_IF_MACRO(_fname == NULL, ERR_INVALID_ARGUMENT, 0);
+    len = strlen(_fname) + 1;
+    fname = (char *) __PHYSFS_smallAlloc(len);
+    BAIL_IF_MACRO(fname == NULL, ERR_OUT_OF_MEMORY, 0);
+
+    if (!sanitizePlatformIndependentPath(_fname, fname))
+        retval = 0;
+
+    else if (*fname == '\0')
+        retval = 1;  /* Root is never a symlink. */
+
+    else
+    {
+        DirHandle *i;
+        int fileExists = 0;
+
+        __PHYSFS_platformGrabMutex(stateLock);
+        for (i = searchPath; ((i != NULL) && (!fileExists)); i = i->next)
+        {
+            char *arcfname = fname;
+            if ((fileExists = partOfMountPoint(i, arcfname)) != 0)
+                retval = 0;  /* virtual dir...not a symlink. */
+            else if (verifyPath(i, &arcfname, 0))
+                retval = i->funcs->isSymLink(i->opaque, arcfname, &fileExists);
+        } /* for */
+        __PHYSFS_platformReleaseMutex(stateLock);
+    } /* else */
+
+    __PHYSFS_smallFree(fname);
+    return(retval);
+} /* PHYSFS_isSymbolicLink */
+
+
+static PHYSFS_File *doOpenWrite(const char *_fname, int appending)
+{
+    FileHandle *fh = NULL;
+    size_t len;
+    char *fname;
+
+    BAIL_IF_MACRO(_fname == NULL, ERR_INVALID_ARGUMENT, 0);
+    len = strlen(_fname) + 1;
+    fname = (char *) __PHYSFS_smallAlloc(len);
+    BAIL_IF_MACRO(fname == NULL, ERR_OUT_OF_MEMORY, 0);
+
+    if (sanitizePlatformIndependentPath(_fname, fname))
+    {
+        void *opaque = NULL;
+        DirHandle *h = NULL;
+        const PHYSFS_Archiver *f;
+
+        __PHYSFS_platformGrabMutex(stateLock);
+
+        GOTO_IF_MACRO(!writeDir, ERR_NO_WRITE_DIR, doOpenWriteEnd);
+
+        h = writeDir;
+        GOTO_IF_MACRO(!verifyPath(h, &fname, 0), NULL, doOpenWriteEnd);
+
+        f = h->funcs;
+        if (appending)
+            opaque = f->openAppend(h->opaque, fname);
+        else
+            opaque = f->openWrite(h->opaque, fname);
+
+        GOTO_IF_MACRO(opaque == NULL, NULL, doOpenWriteEnd);
+
+        fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle));
+        if (fh == NULL)
+        {
+            f->fileClose(opaque);
+            GOTO_MACRO(ERR_OUT_OF_MEMORY, doOpenWriteEnd);
+        } /* if */
+        else
+        {
+            memset(fh, '\0', sizeof (FileHandle));
+            fh->opaque = opaque;
+            fh->dirHandle = h;
+            fh->funcs = h->funcs;
+            fh->next = openWriteList;
+            openWriteList = fh;
+        } /* else */
+
+        doOpenWriteEnd:
+        __PHYSFS_platformReleaseMutex(stateLock);
+    } /* if */
+
+    __PHYSFS_smallFree(fname);
+    return((PHYSFS_File *) fh);
+} /* doOpenWrite */
+
+
+PHYSFS_File *PHYSFS_openWrite(const char *filename)
+{
+    return(doOpenWrite(filename, 0));
+} /* PHYSFS_openWrite */
+
+
+PHYSFS_File *PHYSFS_openAppend(const char *filename)
+{
+    return(doOpenWrite(filename, 1));
+} /* PHYSFS_openAppend */
+
+
+PHYSFS_File *PHYSFS_openRead(const char *_fname)
+{
+    FileHandle *fh = NULL;
+    char *fname;
+    size_t len;
+
+    BAIL_IF_MACRO(_fname == NULL, ERR_INVALID_ARGUMENT, 0);
+    len = strlen(_fname) + 1;
+    fname = (char *) __PHYSFS_smallAlloc(len);
+    BAIL_IF_MACRO(fname == NULL, ERR_OUT_OF_MEMORY, 0);
+
+    if (sanitizePlatformIndependentPath(_fname, fname))
+    {
+        int fileExists = 0;
+        DirHandle *i = NULL;
+        fvoid *opaque = NULL;
+
+        __PHYSFS_platformGrabMutex(stateLock);
+
+        GOTO_IF_MACRO(!searchPath, ERR_NO_SUCH_PATH, openReadEnd);
+
+        /* !!! FIXME: Why aren't we using a for loop here? */
+        i = searchPath;
+
+        do
+        {
+            char *arcfname = fname;
+            if (verifyPath(i, &arcfname, 0))
+            {
+                opaque = i->funcs->openRead(i->opaque, arcfname, &fileExists);
+                if (opaque)
+                    break;
+            } /* if */
+            i = i->next;
+        } while ((i != NULL) && (!fileExists));
+
+        /* !!! FIXME: may not set an error if openRead didn't fail. */
+        GOTO_IF_MACRO(opaque == NULL, NULL, openReadEnd);
+
+        fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle));
+        if (fh == NULL)
+        {
+            i->funcs->fileClose(opaque);
+            GOTO_MACRO(ERR_OUT_OF_MEMORY, openReadEnd);
+        } /* if */
+
+        memset(fh, '\0', sizeof (FileHandle));
+        fh->opaque = opaque;
+        fh->forReading = 1;
+        fh->dirHandle = i;
+        fh->funcs = i->funcs;
+        fh->next = openReadList;
+        openReadList = fh;
+
+        openReadEnd:
+        __PHYSFS_platformReleaseMutex(stateLock);
+    } /* if */
+
+    __PHYSFS_smallFree(fname);
+    return((PHYSFS_File *) fh);
+} /* PHYSFS_openRead */
+
+
+static int closeHandleInOpenList(FileHandle **list, FileHandle *handle)
+{
+    FileHandle *prev = NULL;
+    FileHandle *i;
+    int rc = 1;
+
+    for (i = *list; i != NULL; i = i->next)
+    {
+        if (i == handle)  /* handle is in this list? */
+        {
+            PHYSFS_uint8 *tmp = handle->buffer;
+            rc = PHYSFS_flush((PHYSFS_File *) handle);
+            if (rc)
+                rc = handle->funcs->fileClose(handle->opaque);
+            if (!rc)
+                return(-1);
+
+            if (tmp != NULL)  /* free any associated buffer. */
+                allocator.Free(tmp);
+
+            if (prev == NULL)
+                *list = handle->next;
+            else
+                prev->next = handle->next;
+
+            allocator.Free(handle);
+            return(1);
+        } /* if */
+        prev = i;
+    } /* for */
+
+    return(0);
+} /* closeHandleInOpenList */
+
+
+int PHYSFS_close(PHYSFS_File *_handle)
+{
+    FileHandle *handle = (FileHandle *) _handle;
+    int rc;
+
+    __PHYSFS_platformGrabMutex(stateLock);
+
+    /* -1 == close failure. 0 == not found. 1 == success. */
+    rc = closeHandleInOpenList(&openReadList, handle);
+    BAIL_IF_MACRO_MUTEX(rc == -1, NULL, stateLock, 0);
+    if (!rc)
+    {
+        rc = closeHandleInOpenList(&openWriteList, handle);
+        BAIL_IF_MACRO_MUTEX(rc == -1, NULL, stateLock, 0);
+    } /* if */
+
+    __PHYSFS_platformReleaseMutex(stateLock);
+    BAIL_IF_MACRO(!rc, ERR_NOT_A_HANDLE, 0);
+    return(1);
+} /* PHYSFS_close */
+
+
+static PHYSFS_sint64 doBufferedRead(FileHandle *fh, void *buffer,
+                                    PHYSFS_uint32 objSize,
+                                    PHYSFS_uint32 objCount)
+{
+    PHYSFS_sint64 retval = 0;
+    PHYSFS_uint32 remainder = 0;
+
+    while (objCount > 0)
+    {
+        PHYSFS_uint32 buffered = fh->buffill - fh->bufpos;
+        PHYSFS_uint64 mustread = (objSize * objCount) - remainder;
+        PHYSFS_uint32 copied;
+
+        if (buffered == 0) /* need to refill buffer? */
+        {
+            PHYSFS_sint64 rc = fh->funcs->read(fh->opaque, fh->buffer,
+                                                1, fh->bufsize);
+            if (rc <= 0)
+            {
+                fh->bufpos -= remainder;
+                return(((rc == -1) && (retval == 0)) ? -1 : retval);
+            } /* if */
+
+            buffered = fh->buffill = (PHYSFS_uint32) rc;
+            fh->bufpos = 0;
+        } /* if */
+
+        if (buffered > mustread)
+            buffered = (PHYSFS_uint32) mustread;
+
+        memcpy(buffer, fh->buffer + fh->bufpos, (size_t) buffered);
+        buffer = ((PHYSFS_uint8 *) buffer) + buffered;
+        fh->bufpos += buffered;
+        buffered += remainder;  /* take remainder into account. */
+        copied = (buffered / objSize);
+        remainder = (buffered % objSize);
+        retval += copied;
+        objCount -= copied;
+    } /* while */
+
+    return(retval);
+} /* doBufferedRead */
+
+
+PHYSFS_sint64 PHYSFS_read(PHYSFS_File *handle, void *buffer,
+                          PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    FileHandle *fh = (FileHandle *) handle;
+
+    BAIL_IF_MACRO(!fh->forReading, ERR_FILE_ALREADY_OPEN_W, -1);
+    if (fh->buffer != NULL)
+        return(doBufferedRead(fh, buffer, objSize, objCount));
+
+    return(fh->funcs->read(fh->opaque, buffer, objSize, objCount));
+} /* PHYSFS_read */
+
+
+static PHYSFS_sint64 doBufferedWrite(PHYSFS_File *handle, const void *buffer,
+                                     PHYSFS_uint32 objSize,
+                                     PHYSFS_uint32 objCount)
+{
+    FileHandle *fh = (FileHandle *) handle;
+
+    /* whole thing fits in the buffer? */
+    if (fh->buffill + (objSize * objCount) < fh->bufsize)
+    {
+        memcpy(fh->buffer + fh->buffill, buffer, objSize * objCount);
+        fh->buffill += (objSize * objCount);
+        return(objCount);
+    } /* if */
+
+    /* would overflow buffer. Flush and then write the new objects, too. */
+    BAIL_IF_MACRO(!PHYSFS_flush(handle), NULL, -1);
+    return(fh->funcs->write(fh->opaque, buffer, objSize, objCount));
+} /* doBufferedWrite */
+
+
+PHYSFS_sint64 PHYSFS_write(PHYSFS_File *handle, const void *buffer,
+                           PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+{
+    FileHandle *fh = (FileHandle *) handle;
+
+    BAIL_IF_MACRO(fh->forReading, ERR_FILE_ALREADY_OPEN_R, -1);
+    if (fh->buffer != NULL)
+        return(doBufferedWrite(handle, buffer, objSize, objCount));
+
+    return(fh->funcs->write(fh->opaque, buffer, objSize, objCount));
+} /* PHYSFS_write */
+
+
+int PHYSFS_eof(PHYSFS_File *handle)
+{
+    FileHandle *fh = (FileHandle *) handle;
+
+    if (!fh->forReading)  /* never EOF on files opened for write/append. */
+        return(0);
+
+    /* eof if buffer is empty and archiver says so. */
+    return((fh->bufpos == fh->buffill) && (fh->funcs->eof(fh->opaque)));
+} /* PHYSFS_eof */
+
+
+PHYSFS_sint64 PHYSFS_tell(PHYSFS_File *handle)
+{
+    FileHandle *fh = (FileHandle *) handle;
+    PHYSFS_sint64 pos = fh->funcs->tell(fh->opaque);
+    PHYSFS_sint64 retval = fh->forReading ?
+                            (pos - fh->buffill) + fh->bufpos :
+                            (pos + fh->buffill);
+    return(retval);
+} /* PHYSFS_tell */
+
+
+int PHYSFS_seek(PHYSFS_File *handle, PHYSFS_uint64 pos)
+{
+    FileHandle *fh = (FileHandle *) handle;
+    BAIL_IF_MACRO(!PHYSFS_flush(handle), NULL, 0);
+
+    if (fh->buffer && fh->forReading)
+    {
+        /* avoid throwing away our precious buffer if seeking within it. */
+        PHYSFS_sint64 offset = pos - PHYSFS_tell(handle);
+        if ( /* seeking within the already-buffered range? */
+            ((offset >= 0) && (offset <= fh->buffill - fh->bufpos)) /* fwd */
+            || ((offset < 0) && (-offset <= fh->bufpos)) /* backward */ )
+        {
+            fh->bufpos += (PHYSFS_uint32) offset;
+            return(1); /* successful seek */
+        } /* if */
+    } /* if */
+
+    /* we have to fall back to a 'raw' seek. */
+    fh->buffill = fh->bufpos = 0;
+    return(fh->funcs->seek(fh->opaque, pos));
+} /* PHYSFS_seek */
+
+
+PHYSFS_sint64 PHYSFS_fileLength(PHYSFS_File *handle)
+{
+    FileHandle *fh = (FileHandle *) handle;
+    return(fh->funcs->fileLength(fh->opaque));
+} /* PHYSFS_filelength */
+
+
+int PHYSFS_setBuffer(PHYSFS_File *handle, PHYSFS_uint64 _bufsize)
+{
+    FileHandle *fh = (FileHandle *) handle;
+    PHYSFS_uint32 bufsize;
+
+    /* !!! FIXME: Unlocalized string. */
+    BAIL_IF_MACRO(_bufsize > 0xFFFFFFFF, "buffer must fit in 32-bits", 0);
+    bufsize = (PHYSFS_uint32) _bufsize;
+
+    BAIL_IF_MACRO(!PHYSFS_flush(handle), NULL, 0);
+
+    /*
+     * For reads, we need to move the file pointer to where it would be
+     *  if we weren't buffering, so that the next read will get the
+     *  right chunk of stuff from the file. PHYSFS_flush() handles writes.
+     */
+    if ((fh->forReading) && (fh->buffill != fh->bufpos))
+    {
+        PHYSFS_uint64 pos;
+        PHYSFS_sint64 curpos = fh->funcs->tell(fh->opaque);
+        BAIL_IF_MACRO(curpos == -1, NULL, 0);
+        pos = ((curpos - fh->buffill) + fh->bufpos);
+        BAIL_IF_MACRO(!fh->funcs->seek(fh->opaque, pos), NULL, 0);
+    } /* if */
+
+    if (bufsize == 0)  /* delete existing buffer. */
+    {
+        if (fh->buffer != NULL)
+        {
+            allocator.Free(fh->buffer);
+            fh->buffer = NULL;
+        } /* if */
+    } /* if */
+
+    else
+    {
+        PHYSFS_uint8 *newbuf;
+        newbuf = (PHYSFS_uint8 *) allocator.Realloc(fh->buffer, bufsize);
+        BAIL_IF_MACRO(newbuf == NULL, ERR_OUT_OF_MEMORY, 0);
+        fh->buffer = newbuf;
+    } /* else */
+
+    fh->bufsize = bufsize;
+    fh->buffill = fh->bufpos = 0;
+    return(1);
+} /* PHYSFS_setBuffer */
+
+
+int PHYSFS_flush(PHYSFS_File *handle)
+{
+    FileHandle *fh = (FileHandle *) handle;
+    PHYSFS_sint64 rc;
+
+    if ((fh->forReading) || (fh->bufpos == fh->buffill))
+        return(1);  /* open for read or buffer empty are successful no-ops. */
+
+    /* dump buffer to disk. */
+    rc = fh->funcs->write(fh->opaque, fh->buffer + fh->bufpos,
+                          fh->buffill - fh->bufpos, 1);
+    BAIL_IF_MACRO(rc <= 0, NULL, 0);
+    fh->bufpos = fh->buffill = 0;
+    return(1);
+} /* PHYSFS_flush */
+
+
+int PHYSFS_setAllocator(const PHYSFS_Allocator *a)
+{
+    BAIL_IF_MACRO(initialized, ERR_IS_INITIALIZED, 0);
+    externalAllocator = (a != NULL);
+    if (externalAllocator)
+        memcpy(&allocator, a, sizeof (PHYSFS_Allocator));
+
+    return(1);
+} /* PHYSFS_setAllocator */
+
+
+static void *mallocAllocatorMalloc(PHYSFS_uint64 s)
+{
+    BAIL_IF_MACRO(__PHYSFS_ui64FitsAddressSpace(s), ERR_OUT_OF_MEMORY, NULL);
+    #undef malloc
+    return(malloc((size_t) s));
+} /* mallocAllocatorMalloc */
+
+
+static void *mallocAllocatorRealloc(void *ptr, PHYSFS_uint64 s)
+{
+    BAIL_IF_MACRO(__PHYSFS_ui64FitsAddressSpace(s), ERR_OUT_OF_MEMORY, NULL);
+    #undef realloc
+    return(realloc(ptr, (size_t) s));
+} /* mallocAllocatorRealloc */
+
+
+static void mallocAllocatorFree(void *ptr)
+{
+    #undef free
+    free(ptr);
+} /* mallocAllocatorFree */
+
+
+static void setDefaultAllocator(void)
+{
+    assert(!externalAllocator);
+    if (!__PHYSFS_platformSetDefaultAllocator(&allocator))
+    {
+        allocator.Init = NULL;
+        allocator.Deinit = NULL;
+        allocator.Malloc = mallocAllocatorMalloc;
+        allocator.Realloc = mallocAllocatorRealloc;
+        allocator.Free = mallocAllocatorFree;
+    } /* if */
+} /* setDefaultAllocator */
+
+
+void *__PHYSFS_initSmallAlloc(void *ptr, PHYSFS_uint64 len)
+{
+    const char useHeap = ((ptr == NULL) ? 1 : 0);
+    if (useHeap)  /* too large for stack allocation or alloca() failed. */
+        ptr = allocator.Malloc(len+1);
+
+    if (ptr != NULL)
+    {
+        char *retval = (char *) ptr;
+        /*printf("%s alloc'd (%d) bytes at (%p).\n",
+                useHeap ? "heap" : "stack", (int) len, ptr);*/
+        *retval = useHeap;
+        return(retval+1);
+    } /* if */
+
+    return(NULL);  /* allocation failed. */
+} /* __PHYSFS_initSmallAlloc */
+
+
+void __PHYSFS_smallFree(void *ptr)
+{
+    if (ptr != NULL)
+    {
+        char *block = ((char *) ptr) - 1;
+        const char useHeap = *block;
+        if (useHeap)
+            allocator.Free(block);
+        /*printf("%s free'd (%p).\n", useHeap ? "heap" : "stack", block);*/
+    } /* if */
+} /* __PHYSFS_smallFree */
+
+/* end of physfs.c ... */
+
diff --git a/src/unison/physfs-1.1.1/physfs.h b/src/unison/physfs-1.1.1/physfs.h
new file mode 100644 (file)
index 0000000..9038632
--- /dev/null
@@ -0,0 +1,2390 @@
+/** \file physfs.h */
+
+/**
+ * \mainpage PhysicsFS
+ *
+ * The latest version of PhysicsFS can be found at:
+ *     http://icculus.org/physfs/
+ *
+ * PhysicsFS; a portable, flexible file i/o abstraction.
+ *
+ * This API gives you access to a system file system in ways superior to the
+ *  stdio or system i/o calls. The brief benefits:
+ *
+ *   - It's portable.
+ *   - It's safe. No file access is permitted outside the specified dirs.
+ *   - It's flexible. Archives (.ZIP files) can be used transparently as
+ *      directory structures.
+ *
+ * This system is largely inspired by Quake 3's PK3 files and the related
+ *  fs_* cvars. If you've ever tinkered with these, then this API will be
+ *  familiar to you.
+ *
+ * With PhysicsFS, you have a single writing directory and multiple
+ *  directories (the "search path") for reading. You can think of this as a
+ *  filesystem within a filesystem. If (on Windows) you were to set the
+ *  writing directory to "C:\MyGame\MyWritingDirectory", then no PHYSFS calls
+ *  could touch anything above this directory, including the "C:\MyGame" and
+ *  "C:\" directories. This prevents an application's internal scripting
+ *  language from piddling over c:\\config.sys, for example. If you'd rather
+ *  give PHYSFS full access to the system's REAL file system, set the writing
+ *  dir to "C:\", but that's generally A Bad Thing for several reasons.
+ *
+ * Drive letters are hidden in PhysicsFS once you set up your initial paths.
+ *  The search path creates a single, hierarchical directory structure.
+ *  Not only does this lend itself well to general abstraction with archives,
+ *  it also gives better support to operating systems like MacOS and Unix.
+ *  Generally speaking, you shouldn't ever hardcode a drive letter; not only
+ *  does this hurt portability to non-Microsoft OSes, but it limits your win32
+ *  users to a single drive, too. Use the PhysicsFS abstraction functions and
+ *  allow user-defined configuration options, too. When opening a file, you
+ *  specify it like it was on a Unix filesystem: if you want to write to
+ *  "C:\MyGame\MyConfigFiles\game.cfg", then you might set the write dir to
+ *  "C:\MyGame" and then open "MyConfigFiles/game.cfg". This gives an
+ *  abstraction across all platforms. Specifying a file in this way is termed
+ *  "platform-independent notation" in this documentation. Specifying a
+ *  a filename in a form such as "C:\mydir\myfile" or
+ *  "MacOS hard drive:My Directory:My File" is termed "platform-dependent
+ *  notation". The only time you use platform-dependent notation is when
+ *  setting up your write directory and search path; after that, all file
+ *  access into those directories are done with platform-independent notation.
+ *
+ * All files opened for writing are opened in relation to the write directory,
+ *  which is the root of the writable filesystem. When opening a file for
+ *  reading, PhysicsFS goes through the search path. This is NOT the
+ *  same thing as the PATH environment variable. An application using
+ *  PhysicsFS specifies directories to be searched which may be actual
+ *  directories, or archive files that contain files and subdirectories of
+ *  their own. See the end of these docs for currently supported archive
+ *  formats.
+ *
+ * Once the search path is defined, you may open files for reading. If you've
+ *  got the following search path defined (to use a win32 example again):
+ *
+ *  - C:\\mygame
+ *  - C:\\mygame\\myuserfiles
+ *  - D:\\mygamescdromdatafiles
+ *  - C:\\mygame\\installeddatafiles.zip
+ *
+ * Then a call to PHYSFS_openRead("textfiles/myfile.txt") (note the directory
+ *  separator, lack of drive letter, and lack of dir separator at the start of
+ *  the string; this is platform-independent notation) will check for
+ *  C:\\mygame\\textfiles\\myfile.txt, then
+ *  C:\\mygame\\myuserfiles\\textfiles\\myfile.txt, then
+ *  D:\\mygamescdromdatafiles\\textfiles\\myfile.txt, then, finally, for
+ *  textfiles\\myfile.txt inside of C:\\mygame\\installeddatafiles.zip.
+ *  Remember that most archive types and platform filesystems store their
+ *  filenames in a case-sensitive manner, so you should be careful to specify
+ *  it correctly.
+ *
+ * Files opened through PhysicsFS may NOT contain "." or ".." or ":" as dir
+ *  elements. Not only are these meaningless on MacOS Classic and/or Unix,
+ *  they are a security hole. Also, symbolic links (which can be found in
+ *  some archive types and directly in the filesystem on Unix platforms) are
+ *  NOT followed until you call PHYSFS_permitSymbolicLinks(). That's left to
+ *  your own discretion, as following a symlink can allow for access outside
+ *  the write dir and search paths. For portability, there is no mechanism for
+ *  creating new symlinks in PhysicsFS.
+ *
+ * The write dir is not included in the search path unless you specifically
+ *  add it. While you CAN change the write dir as many times as you like,
+ *  you should probably set it once and stick to it. Remember that your
+ *  program will not have permission to write in every directory on Unix and
+ *  NT systems.
+ *
+ * All files are opened in binary mode; there is no endline conversion for
+ *  textfiles. Other than that, PhysicsFS has some convenience functions for
+ *  platform-independence. There is a function to tell you the current
+ *  platform's dir separator ("\\" on windows, "/" on Unix, ":" on MacOS),
+ *  which is needed only to set up your search/write paths. There is a
+ *  function to tell you what CD-ROM drives contain accessible discs, and a
+ *  function to recommend a good search path, etc.
+ *
+ * A recommended order for the search path is the write dir, then the base dir,
+ *  then the cdrom dir, then any archives discovered. Quake 3 does something
+ *  like this, but moves the archives to the start of the search path. Build
+ *  Engine games, like Duke Nukem 3D and Blood, place the archives last, and
+ *  use the base dir for both searching and writing. There is a helper
+ *  function (PHYSFS_setSaneConfig()) that puts together a basic configuration
+ *  for you, based on a few parameters. Also see the comments on
+ *  PHYSFS_getBaseDir(), and PHYSFS_getUserDir() for info on what those
+ *  are and how they can help you determine an optimal search path.
+ *
+ * PhysicsFS 2.0 adds the concept of "mounting" archives to arbitrary points
+ *  in the search path. If a zipfile contains "maps/level.map" and you mount
+ *  that archive at "mods/mymod", then you would have to open
+ *  "mods/mymod/maps/level.map" to access the file, even though "mods/mymod"
+ *  isn't actually specified in the .zip file. Unlike the Unix mentality of
+ *  mounting a filesystem, "mods/mymod" doesn't actually have to exist when
+ *  mounting the zipfile. It's a "virtual" directory. The mounting mechanism
+ *  allows the developer to seperate archives in the tree and avoid trampling
+ *  over files when added new archives, such as including mod support in a
+ *  game...keeping external content on a tight leash in this manner can be of
+ *  utmost importance to some applications.
+ *
+ * PhysicsFS is mostly thread safe. The error messages returned by
+ *  PHYSFS_getLastError are unique by thread, and library-state-setting
+ *  functions are mutex'd. For efficiency, individual file accesses are 
+ *  not locked, so you can not safely read/write/seek/close/etc the same 
+ *  file from two threads at the same time. Other race conditions are bugs 
+ *  that should be reported/patched.
+ *
+ * While you CAN use stdio/syscall file access in a program that has PHYSFS_*
+ *  calls, doing so is not recommended, and you can not use system
+ *  filehandles with PhysicsFS and vice versa.
+ *
+ * Note that archives need not be named as such: if you have a ZIP file and
+ *  rename it with a .PKG extension, the file will still be recognized as a
+ *  ZIP archive by PhysicsFS; the file's contents are used to determine its
+ *  type where possible.
+ *
+ * Currently supported archive types:
+ *   - .ZIP (pkZip/WinZip/Info-ZIP compatible)
+ *   - .GRP (Build Engine groupfile archives)
+ *   - .PAK (Quake I/II archive format)
+ *   - .HOG (Descent I/II HOG file archives)
+ *   - .MVL (Descent II movielib archives)
+ *   - .WAD (DOOM engine archives)
+ *
+ *
+ * String policy for PhysicsFS 2.0 and later:
+ *
+ * PhysicsFS 1.0 could only deal with null-terminated ASCII strings. All high
+ *  ASCII chars resulted in undefined behaviour, and there was no Unicode
+ *  support at all. PhysicsFS 2.0 supports Unicode without breaking binary
+ *  compatibility with the 1.0 API by using UTF-8 encoding of all strings
+ *  passed in and out of the library.
+ *
+ * All strings passed through PhysicsFS are in null-terminated UTF-8 format.
+ *  This means that if all you care about is English (ASCII characters <= 127)
+ *  then you just use regular C strings. If you care about Unicode (and you
+ *  should!) then you need to figure out what your platform wants, needs, and
+ *  offers. If you are on Windows and build with Unicode support, your TCHAR
+ *  strings are two bytes per character (this is called "UCS-2 encoding"). You
+ *  should convert them to UTF-8 before handing them to PhysicsFS with
+ *  PHYSFS_utf8FromUcs2(). If you're using Unix or Mac OS X, your wchar_t
+ *  strings are four bytes per character ("UCS-4 encoding"). Use
+ *  PHYSFS_utf8FromUcs4(). Mac OS X can give you UTF-8 directly from a
+ *  CFString, and many Unixes generally give you C strings in UTF-8 format
+ *  everywhere. If you have a single-byte high ASCII charset, like so-many
+ *  European "codepages" you may be out of luck. We'll convert from "Latin1"
+ *  to UTF-8 only, and never back to Latin1. If you're above ASCII 127, all
+ *  bets are off: move to Unicode or use your platform's facilities. Passing a
+ *  C string with high-ASCII data that isn't UTF-8 encoded will NOT do what
+ *  you expect!
+ *
+ * Naturally, there's also PHYSFS_utf8ToUcs2() and PHYSFS_utf8ToUcs4() to get
+ *  data back into a format you like. Behind the scenes, PhysicsFS will use
+ *  Unicode where possible: the UTF-8 strings on Windows will be converted
+ *  and used with the multibyte Windows APIs, for example.
+ *
+ * PhysicsFS offers basic encoding conversion support, but not a whole string
+ *  library. Get your stuff into whatever format you can work with.
+ *
+ * Some platforms and archivers don't offer full Unicode support behind the
+ *  scenes. For example, OS/2 only offers "codepages" and the filesystem
+ *  itself doesn't support multibyte encodings. We make an earnest effort to
+ *  convert to/from the current locale here, but all bets are off if
+ *  you want to hand an arbitrary Japanese character through to these systems.
+ *  Modern OSes (Mac OS X, Linux, Windows, PocketPC, etc) should all be fine.
+ *  Many game-specific archivers are seriously unprepared for Unicode (the
+ *  Descent HOG/MVL and Build Engine GRP archivers, for example, only offer a
+ *  DOS 8.3 filename, for example). Nothing can be done for these, but they
+ *  tend to be legacy formats for existing content that was all ASCII (and
+ *  thus, valid UTF-8) anyhow. Other formats, like .ZIP, don't explicitly
+ *  offer Unicode support, but unofficially expect filenames to be UTF-8
+ *  encoded, and thus Just Work. Most everything does the right thing without
+ *  bothering you, but it's good to be aware of these nuances in case they
+ *  don't.
+ *
+ *
+ * Other stuff:
+ *
+ * Please see the file LICENSE.txt in the source's root directory for licensing
+ *  and redistribution rights.
+ *
+ * Please see the file CREDITS.txt in the source's root directory for a more or
+ *  less complete list of who's responsible for this.
+ *
+ *  \author Ryan C. Gordon.
+ */
+
+#ifndef _INCLUDE_PHYSFS_H_
+#define _INCLUDE_PHYSFS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef DOXYGEN_SHOULD_IGNORE_THIS
+#if (defined _MSC_VER)
+#define __EXPORT__ __declspec(dllexport)
+#elif (__GNUC__ >= 3)
+#define __EXPORT__ __attribute__((visibility("default")))
+#else
+#define __EXPORT__
+#endif
+#endif  /* DOXYGEN_SHOULD_IGNORE_THIS */
+
+/**
+ * \typedef PHYSFS_uint8
+ * \brief An unsigned, 8-bit integer type.
+ */
+typedef unsigned char         PHYSFS_uint8;
+
+/**
+ * \typedef PHYSFS_sint8
+ * \brief A signed, 8-bit integer type.
+ */
+typedef signed char           PHYSFS_sint8;
+
+/**
+ * \typedef PHYSFS_uint16
+ * \brief An unsigned, 16-bit integer type.
+ */
+typedef unsigned short        PHYSFS_uint16;
+
+/**
+ * \typedef PHYSFS_sint16
+ * \brief A signed, 16-bit integer type.
+ */
+typedef signed short          PHYSFS_sint16;
+
+/**
+ * \typedef PHYSFS_uint32
+ * \brief An unsigned, 32-bit integer type.
+ */
+typedef unsigned int          PHYSFS_uint32;
+
+/**
+ * \typedef PHYSFS_sint32
+ * \brief A signed, 32-bit integer type.
+ */
+typedef signed int            PHYSFS_sint32;
+
+/**
+ * \typedef PHYSFS_uint64
+ * \brief An unsigned, 64-bit integer type.
+ * \warning on platforms without any sort of 64-bit datatype, this is
+ *           equivalent to PHYSFS_uint32!
+ */
+
+/**
+ * \typedef PHYSFS_sint64
+ * \brief A signed, 64-bit integer type.
+ * \warning on platforms without any sort of 64-bit datatype, this is
+ *           equivalent to PHYSFS_sint32!
+ */
+
+
+#if (defined PHYSFS_NO_64BIT_SUPPORT)  /* oh well. */
+typedef PHYSFS_uint32         PHYSFS_uint64;
+typedef PHYSFS_sint32         PHYSFS_sint64;
+#elif (defined _MSC_VER)
+typedef signed __int64        PHYSFS_sint64;
+typedef unsigned __int64      PHYSFS_uint64;
+#else
+typedef unsigned long long    PHYSFS_uint64;
+typedef signed long long      PHYSFS_sint64;
+#endif
+
+
+#ifndef DOXYGEN_SHOULD_IGNORE_THIS
+/* Make sure the types really have the right sizes */
+#define PHYSFS_COMPILE_TIME_ASSERT(name, x)               \
+       typedef int PHYSFS_dummy_ ## name[(x) * 2 - 1]
+
+PHYSFS_COMPILE_TIME_ASSERT(uint8, sizeof(PHYSFS_uint8) == 1);
+PHYSFS_COMPILE_TIME_ASSERT(sint8, sizeof(PHYSFS_sint8) == 1);
+PHYSFS_COMPILE_TIME_ASSERT(uint16, sizeof(PHYSFS_uint16) == 2);
+PHYSFS_COMPILE_TIME_ASSERT(sint16, sizeof(PHYSFS_sint16) == 2);
+PHYSFS_COMPILE_TIME_ASSERT(uint32, sizeof(PHYSFS_uint32) == 4);
+PHYSFS_COMPILE_TIME_ASSERT(sint32, sizeof(PHYSFS_sint32) == 4);
+
+#ifndef PHYSFS_NO_64BIT_SUPPORT
+PHYSFS_COMPILE_TIME_ASSERT(uint64, sizeof(PHYSFS_uint64) == 8);
+PHYSFS_COMPILE_TIME_ASSERT(sint64, sizeof(PHYSFS_sint64) == 8);
+#endif
+
+#undef PHYSFS_COMPILE_TIME_ASSERT
+
+#endif  /* DOXYGEN_SHOULD_IGNORE_THIS */
+
+
+/**
+ * \struct PHYSFS_File
+ * \brief A PhysicsFS file handle.
+ *
+ * You get a pointer to one of these when you open a file for reading,
+ *  writing, or appending via PhysicsFS.
+ *
+ * As you can see from the lack of meaningful fields, you should treat this
+ *  as opaque data. Don't try to manipulate the file handle, just pass the
+ *  pointer you got, unmolested, to various PhysicsFS APIs.
+ *
+ * \sa PHYSFS_openRead
+ * \sa PHYSFS_openWrite
+ * \sa PHYSFS_openAppend
+ * \sa PHYSFS_close
+ * \sa PHYSFS_read
+ * \sa PHYSFS_write
+ * \sa PHYSFS_seek
+ * \sa PHYSFS_tell
+ * \sa PHYSFS_eof
+ * \sa PHYSFS_setBuffer
+ * \sa PHYSFS_flush
+ */
+typedef struct
+{
+    void *opaque;  /**< That's all you get. Don't touch. */
+} PHYSFS_File;
+
+
+/**
+ * \def PHYSFS_file
+ * \brief 1.0 API compatibility define.
+ *
+ * PHYSFS_file is identical to PHYSFS_File. This #define is here for backwards
+ *  compatibility with the 1.0 API, which had an inconsistent capitalization
+ *  convention in this case. New code should use PHYSFS_File, as this #define
+ *  may go away someday.
+ *
+ * \sa PHYSFS_File
+ */
+#define PHYSFS_file PHYSFS_File
+
+
+/**
+ * \struct PHYSFS_ArchiveInfo
+ * \brief Information on various PhysicsFS-supported archives.
+ *
+ * This structure gives you details on what sort of archives are supported
+ *  by this implementation of PhysicsFS. Archives tend to be things like
+ *  ZIP files and such.
+ *
+ * \warning Not all binaries are created equal! PhysicsFS can be built with
+ *          or without support for various archives. You can check with
+ *          PHYSFS_supportedArchiveTypes() to see if your archive type is
+ *          supported.
+ *
+ * \sa PHYSFS_supportedArchiveTypes
+ */
+typedef struct
+{
+    const char *extension;   /**< Archive file extension: "ZIP", for example. */
+    const char *description; /**< Human-readable archive description. */
+    const char *author;      /**< Person who did support for this archive. */
+    const char *url;         /**< URL related to this archive */
+} PHYSFS_ArchiveInfo;
+
+
+/**
+ * \struct PHYSFS_Version
+ * \brief Information the version of PhysicsFS in use.
+ *
+ * Represents the library's version as three levels: major revision
+ *  (increments with massive changes, additions, and enhancements),
+ *  minor revision (increments with backwards-compatible changes to the
+ *  major revision), and patchlevel (increments with fixes to the minor
+ *  revision).
+ *
+ * \sa PHYSFS_VERSION
+ * \sa PHYSFS_getLinkedVersion
+ */
+typedef struct
+{
+    PHYSFS_uint8 major; /**< major revision */
+    PHYSFS_uint8 minor; /**< minor revision */
+    PHYSFS_uint8 patch; /**< patchlevel */
+} PHYSFS_Version;
+
+#ifndef DOXYGEN_SHOULD_IGNORE_THIS
+#define PHYSFS_VER_MAJOR 1
+#define PHYSFS_VER_MINOR 1
+#define PHYSFS_VER_PATCH 1
+#endif  /* DOXYGEN_SHOULD_IGNORE_THIS */
+
+
+/* PhysicsFS state stuff ... */
+
+/**
+ * \def PHYSFS_VERSION(x)
+ * \brief Macro to determine PhysicsFS version program was compiled against.
+ *
+ * This macro fills in a PHYSFS_Version structure with the version of the
+ *  library you compiled against. This is determined by what header the
+ *  compiler uses. Note that if you dynamically linked the library, you might
+ *  have a slightly newer or older version at runtime. That version can be
+ *  determined with PHYSFS_getLinkedVersion(), which, unlike PHYSFS_VERSION,
+ *  is not a macro.
+ *
+ * \param x A pointer to a PHYSFS_Version struct to initialize.
+ *
+ * \sa PHYSFS_Version
+ * \sa PHYSFS_getLinkedVersion
+ */
+#define PHYSFS_VERSION(x) \
+{ \
+    (x)->major = PHYSFS_VER_MAJOR; \
+    (x)->minor = PHYSFS_VER_MINOR; \
+    (x)->patch = PHYSFS_VER_PATCH; \
+}
+
+
+/**
+ * \fn void PHYSFS_getLinkedVersion(PHYSFS_Version *ver)
+ * \brief Get the version of PhysicsFS that is linked against your program.
+ *
+ * If you are using a shared library (DLL) version of PhysFS, then it is
+ *  possible that it will be different than the version you compiled against.
+ *
+ * This is a real function; the macro PHYSFS_VERSION tells you what version
+ *  of PhysFS you compiled against:
+ *
+ * \code
+ * PHYSFS_Version compiled;
+ * PHYSFS_Version linked;
+ *
+ * PHYSFS_VERSION(&compiled);
+ * PHYSFS_getLinkedVersion(&linked);
+ * printf("We compiled against PhysFS version %d.%d.%d ...\n",
+ *           compiled.major, compiled.minor, compiled.patch);
+ * printf("But we linked against PhysFS version %d.%d.%d.\n",
+ *           linked.major, linked.minor, linked.patch);
+ * \endcode
+ *
+ * This function may be called safely at any time, even before PHYSFS_init().
+ *
+ * \sa PHYSFS_VERSION
+ */
+__EXPORT__ void PHYSFS_getLinkedVersion(PHYSFS_Version *ver);
+
+
+/**
+ * \fn int PHYSFS_init(const char *argv0)
+ * \brief Initialize the PhysicsFS library.
+ *
+ * This must be called before any other PhysicsFS function.
+ *
+ * This should be called prior to any attempts to change your process's
+ *  current working directory.
+ *
+ *   \param argv0 the argv[0] string passed to your program's mainline.
+ *          This may be NULL on most platforms (such as ones without a
+ *          standard main() function), but you should always try to pass
+ *          something in here. Unix-like systems such as Linux _need_ to
+ *          pass argv[0] from main() in here.
+ *  \return nonzero on success, zero on error. Specifics of the error can be
+ *          gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_deinit
+ * \sa PHYSFS_isInit
+ */
+__EXPORT__ int PHYSFS_init(const char *argv0);
+
+
+/**
+ * \fn int PHYSFS_deinit(void)
+ * \brief Deinitialize the PhysicsFS library.
+ *
+ * This closes any files opened via PhysicsFS, blanks the search/write paths,
+ *  frees memory, and invalidates all of your file handles.
+ *
+ * Note that this call can FAIL if there's a file open for writing that
+ *  refuses to close (for example, the underlying operating system was
+ *  buffering writes to network filesystem, and the fileserver has crashed,
+ *  or a hard drive has failed, etc). It is usually best to close all write
+ *  handles yourself before calling this function, so that you can gracefully
+ *  handle a specific failure.
+ *
+ * Once successfully deinitialized, PHYSFS_init() can be called again to
+ *  restart the subsystem. All defaults API states are restored at this
+ *  point.
+ *
+ *  \return nonzero on success, zero on error. Specifics of the error can be
+ *          gleaned from PHYSFS_getLastError(). If failure, state of PhysFS is
+ *          undefined, and probably badly screwed up.
+ *
+ * \sa PHYSFS_init
+ * \sa PHYSFS_isInit
+ */
+__EXPORT__ int PHYSFS_deinit(void);
+
+
+/**
+ * \fn const PHYSFS_ArchiveInfo **PHYSFS_supportedArchiveTypes(void)
+ * \brief Get a list of supported archive types.
+ *
+ * Get a list of archive types supported by this implementation of PhysicFS.
+ *  These are the file formats usable for search path entries. This is for
+ *  informational purposes only. Note that the extension listed is merely
+ *  convention: if we list "ZIP", you can open a PkZip-compatible archive
+ *  with an extension of "XYZ", if you like.
+ *
+ * The returned value is an array of pointers to PHYSFS_ArchiveInfo structures,
+ *  with a NULL entry to signify the end of the list:
+ *
+ * \code
+ * PHYSFS_ArchiveInfo **i;
+ *
+ * for (i = PHYSFS_supportedArchiveTypes(); *i != NULL; i++)
+ * {
+ *     printf("Supported archive: [%s], which is [%s].\n",
+ *              i->extension, i->description);
+ * }
+ * \endcode
+ *
+ * The return values are pointers to static internal memory, and should
+ *  be considered READ ONLY, and never freed.
+ *
+ *   \return READ ONLY Null-terminated array of READ ONLY structures.
+ */
+__EXPORT__ const PHYSFS_ArchiveInfo **PHYSFS_supportedArchiveTypes(void);
+
+
+/**
+ * \fn void PHYSFS_freeList(void *listVar)
+ * \brief Deallocate resources of lists returned by PhysicsFS.
+ *
+ * Certain PhysicsFS functions return lists of information that are
+ *  dynamically allocated. Use this function to free those resources.
+ *
+ *   \param listVar List of information specified as freeable by this function.
+ *
+ * \sa PHYSFS_getCdRomDirs
+ * \sa PHYSFS_enumerateFiles
+ * \sa PHYSFS_getSearchPath
+ */
+__EXPORT__ void PHYSFS_freeList(void *listVar);
+
+
+/**
+ * \fn const char *PHYSFS_getLastError(void)
+ * \brief Get human-readable error information.
+ *
+ * Get the last PhysicsFS error message as a human-readable, null-terminated
+ *  string. This will be NULL if there's been no error since the last call to
+ *  this function. The pointer returned by this call points to an internal
+ *  buffer. Each thread has a unique error state associated with it, but each
+ *  time a new error message is set, it will overwrite the previous one
+ *  associated with that thread. It is safe to call this function at anytime,
+ *  even before PHYSFS_init().
+ *
+ * It is not wise to expect a specific string of characters here, since the
+ *  error message may be localized into an unfamiliar language. These strings
+ *  are meant to be passed on directly to the user.
+ *
+ *   \return READ ONLY string of last error message.
+ */
+__EXPORT__ const char *PHYSFS_getLastError(void);
+
+
+/**
+ * \fn const char *PHYSFS_getDirSeparator(void)
+ * \brief Get platform-dependent dir separator string.
+ *
+ * This returns "\\" on win32, "/" on Unix, and ":" on MacOS. It may be more
+ *  than one character, depending on the platform, and your code should take
+ *  that into account. Note that this is only useful for setting up the
+ *  search/write paths, since access into those dirs always use '/'
+ *  (platform-independent notation) to separate directories. This is also
+ *  handy for getting platform-independent access when using stdio calls.
+ *
+ *   \return READ ONLY null-terminated string of platform's dir separator.
+ */
+__EXPORT__ const char *PHYSFS_getDirSeparator(void);
+
+
+/**
+ * \fn void PHYSFS_permitSymbolicLinks(int allow)
+ * \brief Enable or disable following of symbolic links.
+ *
+ * Some physical filesystems and archives contain files that are just pointers
+ *  to other files. On the physical filesystem, opening such a link will
+ *  (transparently) open the file that is pointed to.
+ *
+ * By default, PhysicsFS will check if a file is really a symlink during open
+ *  calls and fail if it is. Otherwise, the link could take you outside the
+ *  write and search paths, and compromise security.
+ *
+ * If you want to take that risk, call this function with a non-zero parameter.
+ *  Note that this is more for sandboxing a program's scripting language, in
+ *  case untrusted scripts try to compromise the system. Generally speaking,
+ *  a user could very well have a legitimate reason to set up a symlink, so
+ *  unless you feel there's a specific danger in allowing them, you should
+ *  permit them.
+ *
+ * Symlinks are only explicitly checked when dealing with filenames
+ *  in platform-independent notation. That is, when setting up your
+ *  search and write paths, etc, symlinks are never checked for.
+ *
+ * Symbolic link permission can be enabled or disabled at any time after
+ *  you've called PHYSFS_init(), and is disabled by default.
+ *
+ *   \param allow nonzero to permit symlinks, zero to deny linking.
+ *
+ * \sa PHYSFS_symbolicLinksPermitted
+ */
+__EXPORT__ void PHYSFS_permitSymbolicLinks(int allow);
+
+
+/* !!! FIXME: const this? */
+/**
+ * \fn char **PHYSFS_getCdRomDirs(void)
+ * \brief Get an array of paths to available CD-ROM drives.
+ *
+ * The dirs returned are platform-dependent ("D:\" on Win32, "/cdrom" or
+ *  whatnot on Unix). Dirs are only returned if there is a disc ready and
+ *  accessible in the drive. So if you've got two drives (D: and E:), and only
+ *  E: has a disc in it, then that's all you get. If the user inserts a disc
+ *  in D: and you call this function again, you get both drives. If, on a
+ *  Unix box, the user unmounts a disc and remounts it elsewhere, the next
+ *  call to this function will reflect that change.
+ *
+ * This function refers to "CD-ROM" media, but it really means "inserted disc
+ *  media," such as DVD-ROM, HD-DVD, CDRW, and Blu-Ray discs. It looks for
+ *  filesystems, and as such won't report an audio CD, unless there's a
+ *  mounted filesystem track on it.
+ *
+ * The returned value is an array of strings, with a NULL entry to signify the
+ *  end of the list:
+ *
+ * \code
+ * char **cds = PHYSFS_getCdRomDirs();
+ * char **i;
+ *
+ * for (i = cds; *i != NULL; i++)
+ *     printf("cdrom dir [%s] is available.\n", *i);
+ *
+ * PHYSFS_freeList(cds);
+ * \endcode
+ *
+ * This call may block while drives spin up. Be forewarned.
+ *
+ * When you are done with the returned information, you may dispose of the
+ *  resources by calling PHYSFS_freeList() with the returned pointer.
+ *
+ *   \return Null-terminated array of null-terminated strings.
+ *
+ * \sa PHYSFS_getCdRomDirsCallback
+ */
+__EXPORT__ char **PHYSFS_getCdRomDirs(void);
+
+
+/**
+ * \fn const char *PHYSFS_getBaseDir(void)
+ * \brief Get the path where the application resides.
+ *
+ * Helper function.
+ *
+ * Get the "base dir". This is the directory where the application was run
+ *  from, which is probably the installation directory, and may or may not
+ *  be the process's current working directory.
+ *
+ * You should probably use the base dir in your search path.
+ *
+ *  \return READ ONLY string of base dir in platform-dependent notation.
+ *
+ * \sa PHYSFS_getUserDir
+ */
+__EXPORT__ const char *PHYSFS_getBaseDir(void);
+
+
+/**
+ * \fn const char *PHYSFS_getUserDir(void)
+ * \brief Get the path where user's home directory resides.
+ *
+ * Helper function.
+ *
+ * Get the "user dir". This is meant to be a suggestion of where a specific
+ *  user of the system can store files. On Unix, this is her home directory.
+ *  On systems with no concept of multiple home directories (MacOS, win95),
+ *  this will default to something like "C:\mybasedir\users\username"
+ *  where "username" will either be the login name, or "default" if the
+ *  platform doesn't support multiple users, either.
+ *
+ * You should probably use the user dir as the basis for your write dir, and
+ *  also put it near the beginning of your search path.
+ *
+ *  \return READ ONLY string of user dir in platform-dependent notation.
+ *
+ * \sa PHYSFS_getBaseDir
+ */
+__EXPORT__ const char *PHYSFS_getUserDir(void);
+
+
+/**
+ * \fn const char *PHYSFS_getWriteDir(void)
+ * \brief Get path where PhysicsFS will allow file writing.
+ *
+ * Get the current write dir. The default write dir is NULL.
+ *
+ *  \return READ ONLY string of write dir in platform-dependent notation,
+ *           OR NULL IF NO WRITE PATH IS CURRENTLY SET.
+ *
+ * \sa PHYSFS_setWriteDir
+ */
+__EXPORT__ const char *PHYSFS_getWriteDir(void);
+
+
+/**
+ * \fn int PHYSFS_setWriteDir(const char *newDir)
+ * \brief Tell PhysicsFS where it may write files.
+ *
+ * Set a new write dir. This will override the previous setting.
+ *
+ * This call will fail (and fail to change the write dir) if the current
+ *  write dir still has files open in it.
+ *
+ *   \param newDir The new directory to be the root of the write dir,
+ *                   specified in platform-dependent notation. Setting to NULL
+ *                   disables the write dir, so no files can be opened for
+ *                   writing via PhysicsFS.
+ *  \return non-zero on success, zero on failure. All attempts to open a file
+ *           for writing via PhysicsFS will fail until this call succeeds.
+ *           Specifics of the error can be gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_getWriteDir
+ */
+__EXPORT__ int PHYSFS_setWriteDir(const char *newDir);
+
+
+/**
+ * \fn int PHYSFS_addToSearchPath(const char *newDir, int appendToPath)
+ * \brief Add an archive or directory to the search path.
+ *
+ * This is a legacy call in PhysicsFS 2.0, equivalent to:
+ *     PHYSFS_mount(newDir, NULL, appendToPath);
+ *
+ * You must use this and not PHYSFS_mount if binary compatibility with
+ *  PhysicsFS 1.0 is important (which it may not be for many people).
+ *
+ * \sa PHYSFS_mount
+ * \sa PHYSFS_removeFromSearchPath
+ * \sa PHYSFS_getSearchPath
+ */
+__EXPORT__ int PHYSFS_addToSearchPath(const char *newDir, int appendToPath);
+
+
+/**
+ * \fn int PHYSFS_removeFromSearchPath(const char *oldDir)
+ * \brief Remove a directory or archive from the search path.
+ *
+ * This must be a (case-sensitive) match to a dir or archive already in the
+ *  search path, specified in platform-dependent notation.
+ *
+ * This call will fail (and fail to remove from the path) if the element still
+ *  has files open in it.
+ *
+ *    \param oldDir dir/archive to remove.
+ *   \return nonzero on success, zero on failure.
+ *            Specifics of the error can be gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_addToSearchPath
+ * \sa PHYSFS_getSearchPath
+ */
+__EXPORT__ int PHYSFS_removeFromSearchPath(const char *oldDir);
+
+
+/**
+ * \fn char **PHYSFS_getSearchPath(void)
+ * \brief Get the current search path.
+ *
+ * The default search path is an empty list.
+ *
+ * The returned value is an array of strings, with a NULL entry to signify the
+ *  end of the list:
+ *
+ * \code
+ * char **i;
+ *
+ * for (i = PHYSFS_getSearchPath(); *i != NULL; i++)
+ *     printf("[%s] is in the search path.\n", *i);
+ * \endcode
+ *
+ * When you are done with the returned information, you may dispose of the
+ *  resources by calling PHYSFS_freeList() with the returned pointer.
+ *
+ *   \return Null-terminated array of null-terminated strings. NULL if there
+ *            was a problem (read: OUT OF MEMORY).
+ *
+ * \sa PHYSFS_getSearchPathCallback
+ * \sa PHYSFS_addToSearchPath
+ * \sa PHYSFS_removeFromSearchPath
+ */
+__EXPORT__ char **PHYSFS_getSearchPath(void);
+
+
+/**
+ * \fn int PHYSFS_setSaneConfig(const char *organization, const char *appName, const char *archiveExt, int includeCdRoms, int archivesFirst)
+ * \brief Set up sane, default paths.
+ *
+ * Helper function.
+ *
+ * The write dir will be set to "userdir/.organization/appName", which is
+ *  created if it doesn't exist.
+ *
+ * The above is sufficient to make sure your program's configuration directory
+ *  is separated from other clutter, and platform-independent. The period
+ *  before "mygame" even hides the directory on Unix systems.
+ *
+ *  The search path will be:
+ *
+ *    - The Write Dir (created if it doesn't exist)
+ *    - The Base Dir (PHYSFS_getBaseDir())
+ *    - All found CD-ROM dirs (optionally)
+ *
+ * These directories are then searched for files ending with the extension
+ *  (archiveExt), which, if they are valid and supported archives, will also
+ *  be added to the search path. If you specified "PKG" for (archiveExt), and
+ *  there's a file named data.PKG in the base dir, it'll be checked. Archives
+ *  can either be appended or prepended to the search path in alphabetical
+ *  order, regardless of which directories they were found in.
+ *
+ * All of this can be accomplished from the application, but this just does it
+ *  all for you. Feel free to add more to the search path manually, too.
+ *
+ *    \param organization Name of your company/group/etc to be used as a
+ *                         dirname, so keep it small, and no-frills.
+ *
+ *    \param appName Program-specific name of your program, to separate it
+ *                   from other programs using PhysicsFS.
+ *
+ *    \param archiveExt File extension used by your program to specify an
+ *                      archive. For example, Quake 3 uses "pk3", even though
+ *                      they are just zipfiles. Specify NULL to not dig out
+ *                      archives automatically. Do not specify the '.' char;
+ *                      If you want to look for ZIP files, specify "ZIP" and
+ *                      not ".ZIP" ... the archive search is case-insensitive.
+ *
+ *    \param includeCdRoms Non-zero to include CD-ROMs in the search path, and
+ *                         (if (archiveExt) != NULL) search them for archives.
+ *                         This may cause a significant amount of blocking
+ *                         while discs are accessed, and if there are no discs
+ *                         in the drive (or even not mounted on Unix systems),
+ *                         then they may not be made available anyhow. You may
+ *                         want to specify zero and handle the disc setup
+ *                         yourself.
+ *
+ *    \param archivesFirst Non-zero to prepend the archives to the search path.
+ *                          Zero to append them. Ignored if !(archiveExt).
+ *
+ *  \return nonzero on success, zero on error. Specifics of the error can be
+ *          gleaned from PHYSFS_getLastError().
+ */
+__EXPORT__ int PHYSFS_setSaneConfig(const char *organization,
+                                    const char *appName,
+                                    const char *archiveExt,
+                                    int includeCdRoms,
+                                    int archivesFirst);
+
+
+/* Directory management stuff ... */
+
+/**
+ * \fn int PHYSFS_mkdir(const char *dirName)
+ * \brief Create a directory.
+ *
+ * This is specified in platform-independent notation in relation to the
+ *  write dir. All missing parent directories are also created if they
+ *  don't exist.
+ *
+ * So if you've got the write dir set to "C:\mygame\writedir" and call
+ *  PHYSFS_mkdir("downloads/maps") then the directories
+ *  "C:\mygame\writedir\downloads" and "C:\mygame\writedir\downloads\maps"
+ *  will be created if possible. If the creation of "maps" fails after we
+ *  have successfully created "downloads", then the function leaves the
+ *  created directory behind and reports failure.
+ *
+ *   \param dirName New dir to create.
+ *  \return nonzero on success, zero on error. Specifics of the error can be
+ *          gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_delete
+ */
+__EXPORT__ int PHYSFS_mkdir(const char *dirName);
+
+
+/**
+ * \fn int PHYSFS_delete(const char *filename)
+ * \brief Delete a file or directory.
+ *
+ * (filename) is specified in platform-independent notation in relation to the
+ *  write dir.
+ *
+ * A directory must be empty before this call can delete it.
+ *
+ * Deleting a symlink will remove the link, not what it points to, regardless
+ *  of whether you "permitSymLinks" or not.
+ *
+ * So if you've got the write dir set to "C:\mygame\writedir" and call
+ *  PHYSFS_delete("downloads/maps/level1.map") then the file
+ *  "C:\mygame\writedir\downloads\maps\level1.map" is removed from the
+ *  physical filesystem, if it exists and the operating system permits the
+ *  deletion.
+ *
+ * Note that on Unix systems, deleting a file may be successful, but the
+ *  actual file won't be removed until all processes that have an open
+ *  filehandle to it (including your program) close their handles.
+ *
+ * Chances are, the bits that make up the file still exist, they are just
+ *  made available to be written over at a later point. Don't consider this
+ *  a security method or anything.  :)
+ *
+ *   \param filename Filename to delete.
+ *  \return nonzero on success, zero on error. Specifics of the error can be
+ *          gleaned from PHYSFS_getLastError().
+ */
+__EXPORT__ int PHYSFS_delete(const char *filename);
+
+
+/**
+ * \fn const char *PHYSFS_getRealDir(const char *filename)
+ * \brief Figure out where in the search path a file resides.
+ *
+ * The file is specified in platform-independent notation. The returned
+ *  filename will be the element of the search path where the file was found,
+ *  which may be a directory, or an archive. Even if there are multiple
+ *  matches in different parts of the search path, only the first one found
+ *  is used, just like when opening a file.
+ *
+ * So, if you look for "maps/level1.map", and C:\\mygame is in your search
+ *  path and C:\\mygame\\maps\\level1.map exists, then "C:\mygame" is returned.
+ *
+ * If a any part of a match is a symbolic link, and you've not explicitly
+ *  permitted symlinks, then it will be ignored, and the search for a match
+ *  will continue.
+ *
+ * If you specify a fake directory that only exists as a mount point, it'll
+ *  be associated with the first archive mounted there, even though that
+ *  directory isn't necessarily contained in a real archive.
+ *
+ *     \param filename file to look for.
+ *    \return READ ONLY string of element of search path containing the
+ *             the file in question. NULL if not found.
+ */
+__EXPORT__ const char *PHYSFS_getRealDir(const char *filename);
+
+
+/**
+ * \fn char **PHYSFS_enumerateFiles(const char *dir)
+ * \brief Get a file listing of a search path's directory.
+ *
+ * Matching directories are interpolated. That is, if "C:\mydir" is in the
+ *  search path and contains a directory "savegames" that contains "x.sav",
+ *  "y.sav", and "z.sav", and there is also a "C:\userdir" in the search path
+ *  that has a "savegames" subdirectory with "w.sav", then the following code:
+ *
+ * \code
+ * char **rc = PHYSFS_enumerateFiles("savegames");
+ * char **i;
+ *
+ * for (i = rc; *i != NULL; i++)
+ *     printf(" * We've got [%s].\n", *i);
+ *
+ * PHYSFS_freeList(rc);
+ * \endcode
+ *
+ *  ...will print:
+ *
+ * \verbatim
+ * We've got [x.sav].
+ * We've got [y.sav].
+ * We've got [z.sav].
+ * We've got [w.sav].\endverbatim
+ *
+ * Feel free to sort the list however you like. We only promise there will
+ *  be no duplicates, but not what order the final list will come back in.
+ *
+ * Don't forget to call PHYSFS_freeList() with the return value from this
+ *  function when you are done with it.
+ *
+ *    \param dir directory in platform-independent notation to enumerate.
+ *   \return Null-terminated array of null-terminated strings.
+ *
+ * \sa PHYSFS_enumerateFilesCallback
+ */
+__EXPORT__ char **PHYSFS_enumerateFiles(const char *dir);
+
+
+/**
+ * \fn int PHYSFS_exists(const char *fname)
+ * \brief Determine if a file exists in the search path.
+ *
+ * Reports true if there is an entry anywhere in the search path by the
+ *  name of (fname).
+ *
+ * Note that entries that are symlinks are ignored if
+ *  PHYSFS_permitSymbolicLinks(1) hasn't been called, so you
+ *  might end up further down in the search path than expected.
+ *
+ *    \param fname filename in platform-independent notation.
+ *   \return non-zero if filename exists. zero otherwise.
+ *
+ * \sa PHYSFS_isDirectory
+ * \sa PHYSFS_isSymbolicLink
+ */
+__EXPORT__ int PHYSFS_exists(const char *fname);
+
+
+/**
+ * \fn int PHYSFS_isDirectory(const char *fname)
+ * \brief Determine if a file in the search path is really a directory.
+ *
+ * Determine if the first occurence of (fname) in the search path is
+ *  really a directory entry.
+ *
+ * Note that entries that are symlinks are ignored if
+ *  PHYSFS_permitSymbolicLinks(1) hasn't been called, so you
+ *  might end up further down in the search path than expected.
+ *
+ *    \param fname filename in platform-independent notation.
+ *   \return non-zero if filename exists and is a directory.  zero otherwise.
+ *
+ * \sa PHYSFS_exists
+ * \sa PHYSFS_isSymbolicLink
+ */
+__EXPORT__ int PHYSFS_isDirectory(const char *fname);
+
+
+/**
+ * \fn int PHYSFS_isSymbolicLink(const char *fname)
+ * \brief Determine if a file in the search path is really a symbolic link.
+ *
+ * Determine if the first occurence of (fname) in the search path is
+ *  really a symbolic link.
+ *
+ * Note that entries that are symlinks are ignored if
+ *  PHYSFS_permitSymbolicLinks(1) hasn't been called, and as such,
+ *  this function will always return 0 in that case.
+ *
+ *    \param fname filename in platform-independent notation.
+ *   \return non-zero if filename exists and is a symlink.  zero otherwise.
+ *
+ * \sa PHYSFS_exists
+ * \sa PHYSFS_isDirectory
+ */
+__EXPORT__ int PHYSFS_isSymbolicLink(const char *fname);
+
+
+/**
+ * \fn PHYSFS_sint64 PHYSFS_getLastModTime(const char *filename)
+ * \brief Get the last modification time of a file.
+ *
+ * The modtime is returned as a number of seconds since the epoch
+ *  (Jan 1, 1970). The exact derivation and accuracy of this time depends on
+ *  the particular archiver. If there is no reasonable way to obtain this
+ *  information for a particular archiver, or there was some sort of error,
+ *  this function returns (-1).
+ *
+ *   \param filename filename to check, in platform-independent notation.
+ *  \return last modified time of the file. -1 if it can't be determined.
+ */
+__EXPORT__ PHYSFS_sint64 PHYSFS_getLastModTime(const char *filename);
+
+
+/* i/o stuff... */
+
+/**
+ * \fn PHYSFS_File *PHYSFS_openWrite(const char *filename)
+ * \brief Open a file for writing.
+ *
+ * Open a file for writing, in platform-independent notation and in relation
+ *  to the write dir as the root of the writable filesystem. The specified
+ *  file is created if it doesn't exist. If it does exist, it is truncated to
+ *  zero bytes, and the writing offset is set to the start.
+ *
+ * Note that entries that are symlinks are ignored if
+ *  PHYSFS_permitSymbolicLinks(1) hasn't been called, and opening a
+ *  symlink with this function will fail in such a case.
+ *
+ *   \param filename File to open.
+ *  \return A valid PhysicsFS filehandle on success, NULL on error. Specifics
+ *           of the error can be gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_openRead
+ * \sa PHYSFS_openAppend
+ * \sa PHYSFS_write
+ * \sa PHYSFS_close
+ */
+__EXPORT__ PHYSFS_File *PHYSFS_openWrite(const char *filename);
+
+
+/**
+ * \fn PHYSFS_File *PHYSFS_openAppend(const char *filename)
+ * \brief Open a file for appending.
+ *
+ * Open a file for writing, in platform-independent notation and in relation
+ *  to the write dir as the root of the writable filesystem. The specified
+ *  file is created if it doesn't exist. If it does exist, the writing offset
+ *  is set to the end of the file, so the first write will be the byte after
+ *  the end.
+ *
+ * Note that entries that are symlinks are ignored if
+ *  PHYSFS_permitSymbolicLinks(1) hasn't been called, and opening a
+ *  symlink with this function will fail in such a case.
+ *
+ *   \param filename File to open.
+ *  \return A valid PhysicsFS filehandle on success, NULL on error. Specifics
+ *           of the error can be gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_openRead
+ * \sa PHYSFS_openWrite
+ * \sa PHYSFS_write
+ * \sa PHYSFS_close
+ */
+__EXPORT__ PHYSFS_File *PHYSFS_openAppend(const char *filename);
+
+
+/**
+ * \fn PHYSFS_File *PHYSFS_openRead(const char *filename)
+ * \brief Open a file for reading.
+ *
+ * Open a file for reading, in platform-independent notation. The search path
+ *  is checked one at a time until a matching file is found, in which case an
+ *  abstract filehandle is associated with it, and reading may be done.
+ *  The reading offset is set to the first byte of the file.
+ *
+ * Note that entries that are symlinks are ignored if
+ *  PHYSFS_permitSymbolicLinks(1) hasn't been called, and opening a
+ *  symlink with this function will fail in such a case.
+ *
+ *   \param filename File to open.
+ *  \return A valid PhysicsFS filehandle on success, NULL on error. Specifics
+ *           of the error can be gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_openWrite
+ * \sa PHYSFS_openAppend
+ * \sa PHYSFS_read
+ * \sa PHYSFS_close
+ */
+__EXPORT__ PHYSFS_File *PHYSFS_openRead(const char *filename);
+
+
+/**
+ * \fn int PHYSFS_close(PHYSFS_File *handle)
+ * \brief Close a PhysicsFS filehandle.
+ *
+ * This call is capable of failing if the operating system was buffering
+ *  writes to the physical media, and, now forced to write those changes to
+ *  physical media, can not store the data for some reason. In such a case,
+ *  the filehandle stays open. A well-written program should ALWAYS check the
+ *  return value from the close call in addition to every writing call!
+ *
+ *   \param handle handle returned from PHYSFS_open*().
+ *  \return nonzero on success, zero on error. Specifics of the error can be
+ *          gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_openRead
+ * \sa PHYSFS_openWrite
+ * \sa PHYSFS_openAppend
+ */
+__EXPORT__ int PHYSFS_close(PHYSFS_File *handle);
+
+
+/**
+ * \fn PHYSFS_sint64 PHYSFS_read(PHYSFS_File *handle, void *buffer, PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+ * \brief Read data from a PhysicsFS filehandle
+ *
+ * The file must be opened for reading.
+ *
+ *   \param handle handle returned from PHYSFS_openRead().
+ *   \param buffer buffer to store read data into.
+ *   \param objSize size in bytes of objects being read from (handle).
+ *   \param objCount number of (objSize) objects to read from (handle).
+ *  \return number of objects read. PHYSFS_getLastError() can shed light on
+ *           the reason this might be < (objCount), as can PHYSFS_eof().
+ *            -1 if complete failure.
+ *
+ * \sa PHYSFS_eof
+ */
+__EXPORT__ PHYSFS_sint64 PHYSFS_read(PHYSFS_File *handle,
+                                     void *buffer,
+                                     PHYSFS_uint32 objSize,
+                                     PHYSFS_uint32 objCount);
+
+/**
+ * \fn PHYSFS_sint64 PHYSFS_write(PHYSFS_File *handle, const void *buffer, PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+ * \brief Write data to a PhysicsFS filehandle
+ *
+ * The file must be opened for writing.
+ *
+ *   \param handle retval from PHYSFS_openWrite() or PHYSFS_openAppend().
+ *   \param buffer buffer to store read data into.
+ *   \param objSize size in bytes of objects being read from (handle).
+ *   \param objCount number of (objSize) objects to read from (handle).
+ *  \return number of objects written. PHYSFS_getLastError() can shed light on
+ *           the reason this might be < (objCount). -1 if complete failure.
+ */
+__EXPORT__ PHYSFS_sint64 PHYSFS_write(PHYSFS_File *handle,
+                                      const void *buffer,
+                                      PHYSFS_uint32 objSize,
+                                      PHYSFS_uint32 objCount);
+
+
+/* File position stuff... */
+
+/**
+ * \fn int PHYSFS_eof(PHYSFS_File *handle)
+ * \brief Check for end-of-file state on a PhysicsFS filehandle.
+ *
+ * Determine if the end of file has been reached in a PhysicsFS filehandle.
+ *
+ *   \param handle handle returned from PHYSFS_openRead().
+ *  \return nonzero if EOF, zero if not.
+ *
+ * \sa PHYSFS_read
+ * \sa PHYSFS_tell
+ */
+__EXPORT__ int PHYSFS_eof(PHYSFS_File *handle);
+
+
+/**
+ * \fn PHYSFS_sint64 PHYSFS_tell(PHYSFS_File *handle)
+ * \brief Determine current position within a PhysicsFS filehandle.
+ *
+ *   \param handle handle returned from PHYSFS_open*().
+ *  \return offset in bytes from start of file. -1 if error occurred.
+ *           Specifics of the error can be gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_seek
+ */
+__EXPORT__ PHYSFS_sint64 PHYSFS_tell(PHYSFS_File *handle);
+
+
+/**
+ * \fn int PHYSFS_seek(PHYSFS_File *handle, PHYSFS_uint64 pos)
+ * \brief Seek to a new position within a PhysicsFS filehandle.
+ *
+ * The next read or write will occur at that place. Seeking past the
+ *  beginning or end of the file is not allowed, and causes an error.
+ *
+ *   \param handle handle returned from PHYSFS_open*().
+ *   \param pos number of bytes from start of file to seek to.
+ *  \return nonzero on success, zero on error. Specifics of the error can be
+ *          gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_tell
+ */
+__EXPORT__ int PHYSFS_seek(PHYSFS_File *handle, PHYSFS_uint64 pos);
+
+
+/**
+ * \fn PHYSFS_sint64 PHYSFS_fileLength(PHYSFS_File *handle)
+ * \brief Get total length of a file in bytes.
+ *
+ * Note that if the file size can't be determined (since the archive is
+ *  "streamed" or whatnot) than this will report (-1). Also note that if
+ *  another process/thread is writing to this file at the same time, then
+ *  the information this function supplies could be incorrect before you
+ *  get it. Use with caution, or better yet, don't use at all.
+ *
+ *   \param handle handle returned from PHYSFS_open*().
+ *  \return size in bytes of the file. -1 if can't be determined.
+ *
+ * \sa PHYSFS_tell
+ * \sa PHYSFS_seek
+ */
+__EXPORT__ PHYSFS_sint64 PHYSFS_fileLength(PHYSFS_File *handle);
+
+
+/* Buffering stuff... */
+
+/**
+ * \fn int PHYSFS_setBuffer(PHYSFS_File *handle, PHYSFS_uint64 bufsize)
+ * \brief Set up buffering for a PhysicsFS file handle.
+ *
+ * Define an i/o buffer for a file handle. A memory block of (bufsize) bytes
+ *  will be allocated and associated with (handle).
+ *
+ * For files opened for reading, up to (bufsize) bytes are read from (handle)
+ *  and stored in the internal buffer. Calls to PHYSFS_read() will pull
+ *  from this buffer until it is empty, and then refill it for more reading.
+ *  Note that compressed files, like ZIP archives, will decompress while
+ *  buffering, so this can be handy for offsetting CPU-intensive operations.
+ *  The buffer isn't filled until you do your next read.
+ *
+ * For files opened for writing, data will be buffered to memory until the
+ *  buffer is full or the buffer is flushed. Closing a handle implicitly
+ *  causes a flush...check your return values!
+ *
+ * Seeking, etc transparently accounts for buffering.
+ *
+ * You can resize an existing buffer by calling this function more than once
+ *  on the same file. Setting the buffer size to zero will free an existing
+ *  buffer.
+ *
+ * PhysicsFS file handles are unbuffered by default.
+ *
+ * Please check the return value of this function! Failures can include
+ *  not being able to seek backwards in a read-only file when removing the
+ *  buffer, not being able to allocate the buffer, and not being able to
+ *  flush the buffer to disk, among other unexpected problems.
+ *
+ *   \param handle handle returned from PHYSFS_open*().
+ *   \param bufsize size, in bytes, of buffer to allocate.
+ *  \return nonzero if successful, zero on error.
+ *
+ * \sa PHYSFS_flush
+ * \sa PHYSFS_read
+ * \sa PHYSFS_write
+ * \sa PHYSFS_close
+ */
+__EXPORT__ int PHYSFS_setBuffer(PHYSFS_File *handle, PHYSFS_uint64 bufsize);
+
+
+/**
+ * \fn int PHYSFS_flush(PHYSFS_File *handle)
+ * \brief Flush a buffered PhysicsFS file handle.
+ *
+ * For buffered files opened for writing, this will put the current contents
+ *  of the buffer to disk and flag the buffer as empty if possible.
+ *
+ * For buffered files opened for reading or unbuffered files, this is a safe
+ *  no-op, and will report success.
+ *
+ *   \param handle handle returned from PHYSFS_open*().
+ *  \return nonzero if successful, zero on error.
+ *
+ * \sa PHYSFS_setBuffer
+ * \sa PHYSFS_close
+ */
+__EXPORT__ int PHYSFS_flush(PHYSFS_File *handle);
+
+
+/* Byteorder stuff... */
+
+/**
+ * \fn PHYSFS_sint16 PHYSFS_swapSLE16(PHYSFS_sint16 val)
+ * \brief Swap littleendian signed 16 to platform's native byte order.
+ *
+ * Take a 16-bit signed value in littleendian format and convert it to
+ *  the platform's native byte order.
+ *
+ *    \param val value to convert
+ *   \return converted value.
+ */
+__EXPORT__ PHYSFS_sint16 PHYSFS_swapSLE16(PHYSFS_sint16 val);
+
+
+/**
+ * \fn PHYSFS_uint16 PHYSFS_swapULE16(PHYSFS_uint16 val)
+ * \brief Swap littleendian unsigned 16 to platform's native byte order.
+ *
+ * Take a 16-bit unsigned value in littleendian format and convert it to
+ *  the platform's native byte order.
+ *
+ *    \param val value to convert
+ *   \return converted value.
+ */
+__EXPORT__ PHYSFS_uint16 PHYSFS_swapULE16(PHYSFS_uint16 val);
+
+/**
+ * \fn PHYSFS_sint32 PHYSFS_swapSLE32(PHYSFS_sint32 val)
+ * \brief Swap littleendian signed 32 to platform's native byte order.
+ *
+ * Take a 32-bit signed value in littleendian format and convert it to
+ *  the platform's native byte order.
+ *
+ *    \param val value to convert
+ *   \return converted value.
+ */
+__EXPORT__ PHYSFS_sint32 PHYSFS_swapSLE32(PHYSFS_sint32 val);
+
+
+/**
+ * \fn PHYSFS_uint32 PHYSFS_swapULE32(PHYSFS_uint32 val)
+ * \brief Swap littleendian unsigned 32 to platform's native byte order.
+ *
+ * Take a 32-bit unsigned value in littleendian format and convert it to
+ *  the platform's native byte order.
+ *
+ *    \param val value to convert
+ *   \return converted value.
+ */
+__EXPORT__ PHYSFS_uint32 PHYSFS_swapULE32(PHYSFS_uint32 val);
+
+/**
+ * \fn PHYSFS_sint64 PHYSFS_swapSLE64(PHYSFS_sint64 val)
+ * \brief Swap littleendian signed 64 to platform's native byte order.
+ *
+ * Take a 64-bit signed value in littleendian format and convert it to
+ *  the platform's native byte order.
+ *
+ *    \param val value to convert
+ *   \return converted value.
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ *          any sort of 64-bit support.
+ */
+__EXPORT__ PHYSFS_sint64 PHYSFS_swapSLE64(PHYSFS_sint64 val);
+
+
+/**
+ * \fn PHYSFS_uint64 PHYSFS_swapULE64(PHYSFS_uint64 val)
+ * \brief Swap littleendian unsigned 64 to platform's native byte order.
+ *
+ * Take a 64-bit unsigned value in littleendian format and convert it to
+ *  the platform's native byte order.
+ *
+ *    \param val value to convert
+ *   \return converted value.
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ *          any sort of 64-bit support.
+ */
+__EXPORT__ PHYSFS_uint64 PHYSFS_swapULE64(PHYSFS_uint64 val);
+
+
+/**
+ * \fn PHYSFS_sint16 PHYSFS_swapSBE16(PHYSFS_sint16 val)
+ * \brief Swap bigendian signed 16 to platform's native byte order.
+ *
+ * Take a 16-bit signed value in bigendian format and convert it to
+ *  the platform's native byte order.
+ *
+ *    \param val value to convert
+ *   \return converted value.
+ */
+__EXPORT__ PHYSFS_sint16 PHYSFS_swapSBE16(PHYSFS_sint16 val);
+
+
+/**
+ * \fn PHYSFS_uint16 PHYSFS_swapUBE16(PHYSFS_uint16 val)
+ * \brief Swap bigendian unsigned 16 to platform's native byte order.
+ *
+ * Take a 16-bit unsigned value in bigendian format and convert it to
+ *  the platform's native byte order.
+ *
+ *    \param val value to convert
+ *   \return converted value.
+ */
+__EXPORT__ PHYSFS_uint16 PHYSFS_swapUBE16(PHYSFS_uint16 val);
+
+/**
+ * \fn PHYSFS_sint32 PHYSFS_swapSBE32(PHYSFS_sint32 val)
+ * \brief Swap bigendian signed 32 to platform's native byte order.
+ *
+ * Take a 32-bit signed value in bigendian format and convert it to
+ *  the platform's native byte order.
+ *
+ *    \param val value to convert
+ *   \return converted value.
+ */
+__EXPORT__ PHYSFS_sint32 PHYSFS_swapSBE32(PHYSFS_sint32 val);
+
+
+/**
+ * \fn PHYSFS_uint32 PHYSFS_swapUBE32(PHYSFS_uint32 val)
+ * \brief Swap bigendian unsigned 32 to platform's native byte order.
+ *
+ * Take a 32-bit unsigned value in bigendian format and convert it to
+ *  the platform's native byte order.
+ *
+ *    \param val value to convert
+ *   \return converted value.
+ */
+__EXPORT__ PHYSFS_uint32 PHYSFS_swapUBE32(PHYSFS_uint32 val);
+
+
+/**
+ * \fn PHYSFS_sint64 PHYSFS_swapSBE64(PHYSFS_sint64 val)
+ * \brief Swap bigendian signed 64 to platform's native byte order.
+ *
+ * Take a 64-bit signed value in bigendian format and convert it to
+ *  the platform's native byte order.
+ *
+ *    \param val value to convert
+ *   \return converted value.
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ *          any sort of 64-bit support.
+ */
+__EXPORT__ PHYSFS_sint64 PHYSFS_swapSBE64(PHYSFS_sint64 val);
+
+
+/**
+ * \fn PHYSFS_uint64 PHYSFS_swapUBE64(PHYSFS_uint64 val)
+ * \brief Swap bigendian unsigned 64 to platform's native byte order.
+ *
+ * Take a 64-bit unsigned value in bigendian format and convert it to
+ *  the platform's native byte order.
+ *
+ *    \param val value to convert
+ *   \return converted value.
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ *          any sort of 64-bit support.
+ */
+__EXPORT__ PHYSFS_uint64 PHYSFS_swapUBE64(PHYSFS_uint64 val);
+
+
+/**
+ * \fn int PHYSFS_readSLE16(PHYSFS_File *file, PHYSFS_sint16 *val)
+ * \brief Read and convert a signed 16-bit littleendian value.
+ *
+ * Convenience function. Read a signed 16-bit littleendian value from a
+ *  file and convert it to the platform's native byte order.
+ *
+ *    \param file PhysicsFS file handle from which to read.
+ *    \param val pointer to where value should be stored.
+ *   \return zero on failure, non-zero on success. If successful, (*val) will
+ *           store the result. On failure, you can find out what went wrong
+ *           from PHYSFS_getLastError().
+ */
+__EXPORT__ int PHYSFS_readSLE16(PHYSFS_File *file, PHYSFS_sint16 *val);
+
+
+/**
+ * \fn int PHYSFS_readULE16(PHYSFS_File *file, PHYSFS_uint16 *val)
+ * \brief Read and convert an unsigned 16-bit littleendian value.
+ *
+ * Convenience function. Read an unsigned 16-bit littleendian value from a
+ *  file and convert it to the platform's native byte order.
+ *
+ *    \param file PhysicsFS file handle from which to read.
+ *    \param val pointer to where value should be stored.
+ *   \return zero on failure, non-zero on success. If successful, (*val) will
+ *           store the result. On failure, you can find out what went wrong
+ *           from PHYSFS_getLastError().
+ *
+ */
+__EXPORT__ int PHYSFS_readULE16(PHYSFS_File *file, PHYSFS_uint16 *val);
+
+
+/**
+ * \fn int PHYSFS_readSBE16(PHYSFS_File *file, PHYSFS_sint16 *val)
+ * \brief Read and convert a signed 16-bit bigendian value.
+ *
+ * Convenience function. Read a signed 16-bit bigendian value from a
+ *  file and convert it to the platform's native byte order.
+ *
+ *    \param file PhysicsFS file handle from which to read.
+ *    \param val pointer to where value should be stored.
+ *   \return zero on failure, non-zero on success. If successful, (*val) will
+ *           store the result. On failure, you can find out what went wrong
+ *           from PHYSFS_getLastError().
+ */
+__EXPORT__ int PHYSFS_readSBE16(PHYSFS_File *file, PHYSFS_sint16 *val);
+
+
+/**
+ * \fn int PHYSFS_readUBE16(PHYSFS_File *file, PHYSFS_uint16 *val)
+ * \brief Read and convert an unsigned 16-bit bigendian value.
+ *
+ * Convenience function. Read an unsigned 16-bit bigendian value from a
+ *  file and convert it to the platform's native byte order.
+ *
+ *    \param file PhysicsFS file handle from which to read.
+ *    \param val pointer to where value should be stored.
+ *   \return zero on failure, non-zero on success. If successful, (*val) will
+ *           store the result. On failure, you can find out what went wrong
+ *           from PHYSFS_getLastError().
+ *
+ */
+__EXPORT__ int PHYSFS_readUBE16(PHYSFS_File *file, PHYSFS_uint16 *val);
+
+
+/**
+ * \fn int PHYSFS_readSLE32(PHYSFS_File *file, PHYSFS_sint32 *val)
+ * \brief Read and convert a signed 32-bit littleendian value.
+ *
+ * Convenience function. Read a signed 32-bit littleendian value from a
+ *  file and convert it to the platform's native byte order.
+ *
+ *    \param file PhysicsFS file handle from which to read.
+ *    \param val pointer to where value should be stored.
+ *   \return zero on failure, non-zero on success. If successful, (*val) will
+ *           store the result. On failure, you can find out what went wrong
+ *           from PHYSFS_getLastError().
+ */
+__EXPORT__ int PHYSFS_readSLE32(PHYSFS_File *file, PHYSFS_sint32 *val);
+
+
+/**
+ * \fn int PHYSFS_readULE32(PHYSFS_File *file, PHYSFS_uint32 *val)
+ * \brief Read and convert an unsigned 32-bit littleendian value.
+ *
+ * Convenience function. Read an unsigned 32-bit littleendian value from a
+ *  file and convert it to the platform's native byte order.
+ *
+ *    \param file PhysicsFS file handle from which to read.
+ *    \param val pointer to where value should be stored.
+ *   \return zero on failure, non-zero on success. If successful, (*val) will
+ *           store the result. On failure, you can find out what went wrong
+ *           from PHYSFS_getLastError().
+ *
+ */
+__EXPORT__ int PHYSFS_readULE32(PHYSFS_File *file, PHYSFS_uint32 *val);
+
+
+/**
+ * \fn int PHYSFS_readSBE32(PHYSFS_File *file, PHYSFS_sint32 *val)
+ * \brief Read and convert a signed 32-bit bigendian value.
+ *
+ * Convenience function. Read a signed 32-bit bigendian value from a
+ *  file and convert it to the platform's native byte order.
+ *
+ *    \param file PhysicsFS file handle from which to read.
+ *    \param val pointer to where value should be stored.
+ *   \return zero on failure, non-zero on success. If successful, (*val) will
+ *           store the result. On failure, you can find out what went wrong
+ *           from PHYSFS_getLastError().
+ */
+__EXPORT__ int PHYSFS_readSBE32(PHYSFS_File *file, PHYSFS_sint32 *val);
+
+
+/**
+ * \fn int PHYSFS_readUBE32(PHYSFS_File *file, PHYSFS_uint32 *val)
+ * \brief Read and convert an unsigned 32-bit bigendian value.
+ *
+ * Convenience function. Read an unsigned 32-bit bigendian value from a
+ *  file and convert it to the platform's native byte order.
+ *
+ *    \param file PhysicsFS file handle from which to read.
+ *    \param val pointer to where value should be stored.
+ *   \return zero on failure, non-zero on success. If successful, (*val) will
+ *           store the result. On failure, you can find out what went wrong
+ *           from PHYSFS_getLastError().
+ *
+ */
+__EXPORT__ int PHYSFS_readUBE32(PHYSFS_File *file, PHYSFS_uint32 *val);
+
+
+/**
+ * \fn int PHYSFS_readSLE64(PHYSFS_File *file, PHYSFS_sint64 *val)
+ * \brief Read and convert a signed 64-bit littleendian value.
+ *
+ * Convenience function. Read a signed 64-bit littleendian value from a
+ *  file and convert it to the platform's native byte order.
+ *
+ *    \param file PhysicsFS file handle from which to read.
+ *    \param val pointer to where value should be stored.
+ *   \return zero on failure, non-zero on success. If successful, (*val) will
+ *           store the result. On failure, you can find out what went wrong
+ *           from PHYSFS_getLastError().
+ *
+ * \warning Remember, PHYSFS_sint64 is only 32 bits on platforms without
+ *          any sort of 64-bit support.
+ */
+__EXPORT__ int PHYSFS_readSLE64(PHYSFS_File *file, PHYSFS_sint64 *val);
+
+
+/**
+ * \fn int PHYSFS_readULE64(PHYSFS_File *file, PHYSFS_uint64 *val)
+ * \brief Read and convert an unsigned 64-bit littleendian value.
+ *
+ * Convenience function. Read an unsigned 64-bit littleendian value from a
+ *  file and convert it to the platform's native byte order.
+ *
+ *    \param file PhysicsFS file handle from which to read.
+ *    \param val pointer to where value should be stored.
+ *   \return zero on failure, non-zero on success. If successful, (*val) will
+ *           store the result. On failure, you can find out what went wrong
+ *           from PHYSFS_getLastError().
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ *          any sort of 64-bit support.
+ */
+__EXPORT__ int PHYSFS_readULE64(PHYSFS_File *file, PHYSFS_uint64 *val);
+
+
+/**
+ * \fn int PHYSFS_readSBE64(PHYSFS_File *file, PHYSFS_sint64 *val)
+ * \brief Read and convert a signed 64-bit bigendian value.
+ *
+ * Convenience function. Read a signed 64-bit bigendian value from a
+ *  file and convert it to the platform's native byte order.
+ *
+ *    \param file PhysicsFS file handle from which to read.
+ *    \param val pointer to where value should be stored.
+ *   \return zero on failure, non-zero on success. If successful, (*val) will
+ *           store the result. On failure, you can find out what went wrong
+ *           from PHYSFS_getLastError().
+ *
+ * \warning Remember, PHYSFS_sint64 is only 32 bits on platforms without
+ *          any sort of 64-bit support.
+ */
+__EXPORT__ int PHYSFS_readSBE64(PHYSFS_File *file, PHYSFS_sint64 *val);
+
+
+/**
+ * \fn int PHYSFS_readUBE64(PHYSFS_File *file, PHYSFS_uint64 *val)
+ * \brief Read and convert an unsigned 64-bit bigendian value.
+ *
+ * Convenience function. Read an unsigned 64-bit bigendian value from a
+ *  file and convert it to the platform's native byte order.
+ *
+ *    \param file PhysicsFS file handle from which to read.
+ *    \param val pointer to where value should be stored.
+ *   \return zero on failure, non-zero on success. If successful, (*val) will
+ *           store the result. On failure, you can find out what went wrong
+ *           from PHYSFS_getLastError().
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ *          any sort of 64-bit support.
+ */
+__EXPORT__ int PHYSFS_readUBE64(PHYSFS_File *file, PHYSFS_uint64 *val);
+
+
+/**
+ * \fn int PHYSFS_writeSLE16(PHYSFS_File *file, PHYSFS_sint16 val)
+ * \brief Convert and write a signed 16-bit littleendian value.
+ *
+ * Convenience function. Convert a signed 16-bit value from the platform's
+ *  native byte order to littleendian and write it to a file.
+ *
+ *    \param file PhysicsFS file handle to which to write.
+ *    \param val Value to convert and write.
+ *   \return zero on failure, non-zero on success. On failure, you can
+ *           find out what went wrong from PHYSFS_getLastError().
+ */
+__EXPORT__ int PHYSFS_writeSLE16(PHYSFS_File *file, PHYSFS_sint16 val);
+
+
+/**
+ * \fn int PHYSFS_writeULE16(PHYSFS_File *file, PHYSFS_uint16 val)
+ * \brief Convert and write an unsigned 16-bit littleendian value.
+ *
+ * Convenience function. Convert an unsigned 16-bit value from the platform's
+ *  native byte order to littleendian and write it to a file.
+ *
+ *    \param file PhysicsFS file handle to which to write.
+ *    \param val Value to convert and write.
+ *   \return zero on failure, non-zero on success. On failure, you can
+ *           find out what went wrong from PHYSFS_getLastError().
+ */
+__EXPORT__ int PHYSFS_writeULE16(PHYSFS_File *file, PHYSFS_uint16 val);
+
+
+/**
+ * \fn int PHYSFS_writeSBE16(PHYSFS_File *file, PHYSFS_sint16 val)
+ * \brief Convert and write a signed 16-bit bigendian value.
+ *
+ * Convenience function. Convert a signed 16-bit value from the platform's
+ *  native byte order to bigendian and write it to a file.
+ *
+ *    \param file PhysicsFS file handle to which to write.
+ *    \param val Value to convert and write.
+ *   \return zero on failure, non-zero on success. On failure, you can
+ *           find out what went wrong from PHYSFS_getLastError().
+ */
+__EXPORT__ int PHYSFS_writeSBE16(PHYSFS_File *file, PHYSFS_sint16 val);
+
+
+/**
+ * \fn int PHYSFS_writeUBE16(PHYSFS_File *file, PHYSFS_uint16 val)
+ * \brief Convert and write an unsigned 16-bit bigendian value.
+ *
+ * Convenience function. Convert an unsigned 16-bit value from the platform's
+ *  native byte order to bigendian and write it to a file.
+ *
+ *    \param file PhysicsFS file handle to which to write.
+ *    \param val Value to convert and write.
+ *   \return zero on failure, non-zero on success. On failure, you can
+ *           find out what went wrong from PHYSFS_getLastError().
+ */
+__EXPORT__ int PHYSFS_writeUBE16(PHYSFS_File *file, PHYSFS_uint16 val);
+
+
+/**
+ * \fn int PHYSFS_writeSLE32(PHYSFS_File *file, PHYSFS_sint32 val)
+ * \brief Convert and write a signed 32-bit littleendian value.
+ *
+ * Convenience function. Convert a signed 32-bit value from the platform's
+ *  native byte order to littleendian and write it to a file.
+ *
+ *    \param file PhysicsFS file handle to which to write.
+ *    \param val Value to convert and write.
+ *   \return zero on failure, non-zero on success. On failure, you can
+ *           find out what went wrong from PHYSFS_getLastError().
+ */
+__EXPORT__ int PHYSFS_writeSLE32(PHYSFS_File *file, PHYSFS_sint32 val);
+
+
+/**
+ * \fn int PHYSFS_writeULE32(PHYSFS_File *file, PHYSFS_uint32 val)
+ * \brief Convert and write an unsigned 32-bit littleendian value.
+ *
+ * Convenience function. Convert an unsigned 32-bit value from the platform's
+ *  native byte order to littleendian and write it to a file.
+ *
+ *    \param file PhysicsFS file handle to which to write.
+ *    \param val Value to convert and write.
+ *   \return zero on failure, non-zero on success. On failure, you can
+ *           find out what went wrong from PHYSFS_getLastError().
+ */
+__EXPORT__ int PHYSFS_writeULE32(PHYSFS_File *file, PHYSFS_uint32 val);
+
+
+/**
+ * \fn int PHYSFS_writeSBE32(PHYSFS_File *file, PHYSFS_sint32 val)
+ * \brief Convert and write a signed 32-bit bigendian value.
+ *
+ * Convenience function. Convert a signed 32-bit value from the platform's
+ *  native byte order to bigendian and write it to a file.
+ *
+ *    \param file PhysicsFS file handle to which to write.
+ *    \param val Value to convert and write.
+ *   \return zero on failure, non-zero on success. On failure, you can
+ *           find out what went wrong from PHYSFS_getLastError().
+ */
+__EXPORT__ int PHYSFS_writeSBE32(PHYSFS_File *file, PHYSFS_sint32 val);
+
+
+/**
+ * \fn int PHYSFS_writeUBE32(PHYSFS_File *file, PHYSFS_uint32 val)
+ * \brief Convert and write an unsigned 32-bit bigendian value.
+ *
+ * Convenience function. Convert an unsigned 32-bit value from the platform's
+ *  native byte order to bigendian and write it to a file.
+ *
+ *    \param file PhysicsFS file handle to which to write.
+ *    \param val Value to convert and write.
+ *   \return zero on failure, non-zero on success. On failure, you can
+ *           find out what went wrong from PHYSFS_getLastError().
+ */
+__EXPORT__ int PHYSFS_writeUBE32(PHYSFS_File *file, PHYSFS_uint32 val);
+
+
+/**
+ * \fn int PHYSFS_writeSLE64(PHYSFS_File *file, PHYSFS_sint64 val)
+ * \brief Convert and write a signed 64-bit littleendian value.
+ *
+ * Convenience function. Convert a signed 64-bit value from the platform's
+ *  native byte order to littleendian and write it to a file.
+ *
+ *    \param file PhysicsFS file handle to which to write.
+ *    \param val Value to convert and write.
+ *   \return zero on failure, non-zero on success. On failure, you can
+ *           find out what went wrong from PHYSFS_getLastError().
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ *          any sort of 64-bit support.
+ */
+__EXPORT__ int PHYSFS_writeSLE64(PHYSFS_File *file, PHYSFS_sint64 val);
+
+
+/**
+ * \fn int PHYSFS_writeULE64(PHYSFS_File *file, PHYSFS_uint64 val)
+ * \brief Convert and write an unsigned 64-bit littleendian value.
+ *
+ * Convenience function. Convert an unsigned 64-bit value from the platform's
+ *  native byte order to littleendian and write it to a file.
+ *
+ *    \param file PhysicsFS file handle to which to write.
+ *    \param val Value to convert and write.
+ *   \return zero on failure, non-zero on success. On failure, you can
+ *           find out what went wrong from PHYSFS_getLastError().
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ *          any sort of 64-bit support.
+ */
+__EXPORT__ int PHYSFS_writeULE64(PHYSFS_File *file, PHYSFS_uint64 val);
+
+
+/**
+ * \fn int PHYSFS_writeSBE64(PHYSFS_File *file, PHYSFS_sint64 val)
+ * \brief Convert and write a signed 64-bit bigending value.
+ *
+ * Convenience function. Convert a signed 64-bit value from the platform's
+ *  native byte order to bigendian and write it to a file.
+ *
+ *    \param file PhysicsFS file handle to which to write.
+ *    \param val Value to convert and write.
+ *   \return zero on failure, non-zero on success. On failure, you can
+ *           find out what went wrong from PHYSFS_getLastError().
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ *          any sort of 64-bit support.
+ */
+__EXPORT__ int PHYSFS_writeSBE64(PHYSFS_File *file, PHYSFS_sint64 val);
+
+
+/**
+ * \fn int PHYSFS_writeUBE64(PHYSFS_File *file, PHYSFS_uint64 val)
+ * \brief Convert and write an unsigned 64-bit bigendian value.
+ *
+ * Convenience function. Convert an unsigned 64-bit value from the platform's
+ *  native byte order to bigendian and write it to a file.
+ *
+ *    \param file PhysicsFS file handle to which to write.
+ *    \param val Value to convert and write.
+ *   \return zero on failure, non-zero on success. On failure, you can
+ *           find out what went wrong from PHYSFS_getLastError().
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ *          any sort of 64-bit support.
+ */
+__EXPORT__ int PHYSFS_writeUBE64(PHYSFS_File *file, PHYSFS_uint64 val);
+
+
+/* Everything above this line is part of the PhysicsFS 1.0 API. */
+
+/**
+ * \fn int PHYSFS_isInit(void)
+ * \brief Determine if the PhysicsFS library is initialized.
+ *
+ * Once PHYSFS_init() returns successfully, this will return non-zero.
+ *  Before a successful PHYSFS_init() and after PHYSFS_deinit() returns
+ *  successfully, this will return zero. This function is safe to call at
+ *  any time.
+ *
+ *  \return non-zero if library is initialized, zero if library is not.
+ *
+ * \sa PHYSFS_init
+ * \sa PHYSFS_deinit
+ */
+__EXPORT__ int PHYSFS_isInit(void);
+
+
+/**
+ * \fn int PHYSFS_symbolicLinksPermitted(void)
+ * \brief Determine if the symbolic links are permitted.
+ *
+ * This reports the setting from the last call to PHYSFS_permitSymbolicLinks().
+ *  If PHYSFS_permitSymbolicLinks() hasn't been called since the library was
+ *  last initialized, symbolic links are implicitly disabled.
+ *
+ *  \return non-zero if symlinks are permitted, zero if not.
+ *
+ * \sa PHYSFS_permitSymbolicLinks
+ */
+__EXPORT__ int PHYSFS_symbolicLinksPermitted(void);
+
+
+/**
+ * \struct PHYSFS_Allocator
+ * \brief PhysicsFS allocation function pointers.
+ *
+ * (This is for limited, hardcore use. If you don't immediately see a need
+ *  for it, you can probably ignore this forever.)
+ *
+ * You create one of these structures for use with PHYSFS_setAllocator.
+ *  Allocators are assumed to be reentrant by the caller; please mutex
+ *  accordingly.
+ *
+ * Allocations are always discussed in 64-bits, for future expansion...we're
+ *  on the cusp of a 64-bit transition, and we'll probably be allocating 6
+ *  gigabytes like it's nothing sooner or later, and I don't want to change
+ *  this again at that point. If you're on a 32-bit platform and have to
+ *  downcast, it's okay to return NULL if the allocation is greater than
+ *  4 gigabytes, since you'd have to do so anyhow.
+ *
+ * \sa PHYSFS_setAllocator
+ */
+typedef struct
+{
+    int (*Init)(void);   /**< Initialize. Can be NULL. Zero on failure. */
+    void (*Deinit)(void);  /**< Deinitialize your allocator. Can be NULL. */
+    void *(*Malloc)(PHYSFS_uint64);  /**< Allocate like malloc(). */
+    void *(*Realloc)(void *, PHYSFS_uint64); /**< Reallocate like realloc(). */
+    void (*Free)(void *); /**< Free memory from Malloc or Realloc. */
+} PHYSFS_Allocator;
+
+
+/**
+ * \fn int PHYSFS_setAllocator(const PHYSFS_Allocator *allocator)
+ * \brief Hook your own allocation routines into PhysicsFS.
+ *
+ * (This is for limited, hardcore use. If you don't immediately see a need
+ *  for it, you can probably ignore this forever.)
+ *
+ * By default, PhysicsFS will use whatever is reasonable for a platform
+ *  to manage dynamic memory (usually ANSI C malloc/realloc/calloc/free, but
+ *  some platforms might use something else), but in some uncommon cases, the
+ *  app might want more control over the library's memory management. This
+ *  lets you redirect PhysicsFS to use your own allocation routines instead.
+ *  You can only call this function before PHYSFS_init(); if the library is
+ *  initialized, it'll reject your efforts to change the allocator mid-stream.
+ *  You may call this function after PHYSFS_deinit() if you are willing to
+ *  shut down the library and restart it with a new allocator; this is a safe
+ *  and supported operation. The allocator remains intact between deinit/init
+ *  calls. If you want to return to the platform's default allocator, pass a
+ *  NULL in here.
+ *
+ * If you aren't immediately sure what to do with this function, you can
+ *  safely ignore it altogether.
+ *
+ *    \param allocator Structure containing your allocator's entry points.
+ *   \return zero on failure, non-zero on success. This call only fails
+ *           when used between PHYSFS_init() and PHYSFS_deinit() calls.
+ */
+__EXPORT__ int PHYSFS_setAllocator(const PHYSFS_Allocator *allocator);
+
+
+/**
+ * \fn int PHYSFS_mount(const char *newDir, const char *mountPoint, int appendToPath)
+ * \brief Add an archive or directory to the search path.
+ *
+ * If this is a duplicate, the entry is not added again, even though the
+ *  function succeeds. You may not add the same archive to two different
+ *  mountpoints: duplicate checking is done against the archive and not the
+ *  mountpoint.
+ *
+ * When you mount an archive, it is added to a virtual file system...all files
+ *  in all of the archives are interpolated into a single hierachical file
+ *  tree. Two archives mounted at the same place (or an archive with files
+ *  overlapping another mountpoint) may have overlapping files: in such a case,
+ *  the file earliest in the search path is selected, and the other files are
+ *  inaccessible to the application. This allows archives to be used to
+ *  override previous revisions; you can use the mounting mechanism to place
+ *  archives at a specific point in the file tree and prevent overlap; this
+ *  is useful for downloadable mods that might trample over application data
+ *  or each other, for example.
+ *
+ * The mountpoint does not need to exist prior to mounting, which is different
+ *  than those familiar with the Unix concept of "mounting" may not expect.
+ *  As well, more than one archive can be mounted to the same mountpoint, or
+ *  mountpoints and archive contents can overlap...the interpolation mechanism
+ *  still functions as usual.
+ *
+ *   \param newDir directory or archive to add to the path, in
+ *                   platform-dependent notation.
+ *   \param mountPoint Location in the interpolated tree that this archive
+ *                     will be "mounted", in platform-independent notation.
+ *                     NULL or "" is equivalent to "/".
+ *   \param appendToPath nonzero to append to search path, zero to prepend.
+ *  \return nonzero if added to path, zero on failure (bogus archive, dir
+ *                   missing, etc). Specifics of the error can be
+ *                   gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_removeFromSearchPath
+ * \sa PHYSFS_getSearchPath
+ * \sa PHYSFS_getMountPoint
+ */
+__EXPORT__ int PHYSFS_mount(const char *newDir, const char *mountPoint, int appendToPath);
+
+/**
+ * \fn int PHYSFS_getMountPoint(const char *dir)
+ * \brief Determine a mounted archive's mountpoint.
+ *
+ * You give this function the name of an archive or dir you successfully
+ *  added to the search path, and it reports the location in the interpolated
+ *  tree where it is mounted. Files mounted with a NULL mountpoint or through
+ *  PHYSFS_addToSearchPath() will report "/". The return value is READ ONLY
+ *  and valid until the archive is removed from the search path.
+ *
+ *   \param dir directory or archive previously added to the path, in
+ *              platform-dependent notation. This must match the string
+ *              used when adding, even if your string would also reference
+ *              the same file with a different string of characters.
+ *  \return READ-ONLY string of mount point if added to path, NULL on failure
+ *          (bogus archive, etc) Specifics of the error can be gleaned from
+ *          PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_removeFromSearchPath
+ * \sa PHYSFS_getSearchPath
+ * \sa PHYSFS_getMountPoint
+ */
+__EXPORT__ const char *PHYSFS_getMountPoint(const char *dir);
+
+
+/**
+ * \typedef PHYSFS_StringCallback
+ * \brief Function signature for callbacks that report strings.
+ *
+ * These are used to report a list of strings to an original caller, one
+ *  string per callback. All strings are UTF-8 encoded. Functions should not
+ *  try to modify or free the string's memory.
+ *
+ * These callbacks are used, starting in PhysicsFS 1.1, as an alternative to
+ *  functions that would return lists that need to be cleaned up with
+ *  PHYSFS_freeList(). The callback means that the library doesn't need to
+ *  allocate an entire list and all the strings up front.
+ *
+ * Be aware that promises data ordering in the list versions are not
+ *  necessarily so in the callback versions. Check the documentation on
+ *  specific APIs, but strings may not be sorted as you expect.
+ *
+ *    \param data User-defined data pointer, passed through from the API
+ *                that eventually called the callback.
+ *    \param str The string data about which the callback is meant to inform.
+ *
+ * \sa PHYSFS_getCdRomDirsCallback
+ * \sa PHYSFS_getSearchPathCallback
+ */
+typedef void (*PHYSFS_StringCallback)(void *data, const char *str);
+
+
+/**
+ * \typedef PHYSFS_EnumFilesCallback
+ * \brief Function signature for callbacks that enumerate files.
+ *
+ * These are used to report a list of directory entries to an original caller,
+ *  one file/dir/symlink per callback. All strings are UTF-8 encoded.
+ *  Functions should not try to modify or free any string's memory.
+ *
+ * These callbacks are used, starting in PhysicsFS 1.1, as an alternative to
+ *  functions that would return lists that need to be cleaned up with
+ *  PHYSFS_freeList(). The callback means that the library doesn't need to
+ *  allocate an entire list and all the strings up front.
+ *
+ * Be aware that promises data ordering in the list versions are not
+ *  necessarily so in the callback versions. Check the documentation on
+ *  specific APIs, but strings may not be sorted as you expect.
+ *
+ *    \param data User-defined data pointer, passed through from the API
+ *                that eventually called the callback.
+ *    \param origdir A string containing the full path, in platform-independent
+ *                   notation, of the directory containing this file. In most
+ *                   cases, this is the directory on which you requested
+ *                   enumeration, passed in the callback for your convenience.
+ *    \param fname The filename that is being enumerated. It may not be in
+ *                 alphabetical order compared to other callbacks that have
+ *                 fired, and it will not contain the full path. You can
+ *                 recreate the fullpath with $origdir/$fname ... The file
+ *                 can be a subdirectory, a file, a symlink, etc.
+ *
+ * \sa PHYSFS_enumerateFilesCallback
+ */
+typedef void (*PHYSFS_EnumFilesCallback)(void *data, const char *origdir,
+                                         const char *fname);
+
+
+/**
+ * \fn void PHYSFS_getCdRomDirsCallback(PHYSFS_StringCallback c, void *d)
+ * \brief Enumerate CD-ROM directories, using an application-defined callback.
+ *
+ * Internally, PHYSFS_getCdRomDirs() just calls this function and then builds
+ *  a list before returning to the application, so functionality is identical
+ *  except for how the information is represented to the application.
+ *
+ * Unlike PHYSFS_getCdRomDirs(), this function does not return an array.
+ *  Rather, it calls a function specified by the application once per
+ *  detected disc:
+ *
+ * \code
+ *
+ * static void foundDisc(void *data, const char *cddir)
+ * {
+ *     printf("cdrom dir [%s] is available.\n", cddir);
+ * }
+ *
+ * // ...
+ * PHYSFS_getCdRomDirsCallback(foundDisc, NULL);
+ * \endcode
+ *
+ * This call may block while drives spin up. Be forewarned.
+ *
+ *    \param c Callback function to notify about detected drives.
+ *    \param d Application-defined data passed to callback. Can be NULL.
+ *
+ * \sa PHYSFS_StringCallback
+ * \sa PHYSFS_getCdRomDirs
+ */
+__EXPORT__ void PHYSFS_getCdRomDirsCallback(PHYSFS_StringCallback c, void *d);
+
+
+/**
+ * \fn void PHYSFS_getSearchPathCallback(PHYSFS_StringCallback c, void *d)
+ * \brief Enumerate the search path, using an application-defined callback.
+ *
+ * Internally, PHYSFS_getSearchPath() just calls this function and then builds
+ *  a list before returning to the application, so functionality is identical
+ *  except for how the information is represented to the application.
+ *
+ * Unlike PHYSFS_getSearchPath(), this function does not return an array.
+ *  Rather, it calls a function specified by the application once per
+ *  element of the search path:
+ *
+ * \code
+ *
+ * static void printSearchPath(void *data, const char *pathItem)
+ * {
+ *     printf("[%s] is in the search path.\n", pathItem);
+ * }
+ *
+ * // ...
+ * PHYSFS_getSearchPathCallback(printSearchPath, NULL);
+ * \endcode
+ *
+ * Elements of the search path are reported in order search priority, so the
+ *  first archive/dir that would be examined when looking for a file is the
+ *  first element passed through the callback.
+ *
+ *    \param c Callback function to notify about search path elements.
+ *    \param d Application-defined data passed to callback. Can be NULL.
+ *
+ * \sa PHYSFS_StringCallback
+ * \sa PHYSFS_getSearchPath
+ */
+__EXPORT__ void PHYSFS_getSearchPathCallback(PHYSFS_StringCallback c, void *d);
+
+
+/**
+ * \fn void PHYSFS_enumerateFilesCallback(const char *dir, PHYSFS_EnumFilesCallback c, void *d)
+ * \brief Get a file listing of a search path's directory, using an application-defined callback.
+ *
+ * Internally, PHYSFS_enumerateFiles() just calls this function and then builds
+ *  a list before returning to the application, so functionality is identical
+ *  except for how the information is represented to the application.
+ *
+ * Unlike PHYSFS_enumerateFiles(), this function does not return an array.
+ *  Rather, it calls a function specified by the application once per
+ *  element of the search path:
+ *
+ * \code
+ *
+ * static void printDir(void *data, const char *origdir, const char *fname)
+ * {
+ *     printf(" * We've got [%s] in [%s].\n", fname, origdir);
+ * }
+ *
+ * // ...
+ * PHYSFS_enumerateFilesCallback("/some/path", printDir, NULL);
+ * \endcode
+ *
+ * Items sent to the callback are not guaranteed to be in any order whatsoever.
+ *  There is no sorting done at this level, and if you need that, you should
+ *  probably use PHYSFS_enumerateFiles() instead, which guarantees
+ *  alphabetical sorting. This form reports whatever is discovered in each
+ *  archive before moving on to the next. Even within one archive, we can't
+ *  guarantee what order it will discover data. <em>Any sorting you find in
+ *  these callbacks is just pure luck. Do not rely on it.</em>
+ *
+ *    \param dir Directory, in platform-independent notation, to enumerate.
+ *    \param c Callback function to notify about search path elements.
+ *    \param d Application-defined data passed to callback. Can be NULL.
+ *
+ * \sa PHYSFS_EnumFilesCallback
+ * \sa PHYSFS_enumerateFiles
+ */
+__EXPORT__ void PHYSFS_enumerateFilesCallback(const char *dir,
+                                              PHYSFS_EnumFilesCallback c,
+                                              void *d);
+
+/**
+ * \fn void PHYSFS_utf8FromUcs4(const PHYSFS_uint32 *src, char *dst, PHYSFS_uint64 len)
+ * \brief Convert a UCS-4 string to a UTF-8 string.
+ *
+ * UCS-4 strings are 32-bits per character: \c wchar_t on Unix.
+ *
+ * To ensure that the destination buffer is large enough for the conversion,
+ *  please allocate a buffer that is the same size as the source buffer. UTF-8
+ *  never uses more than 32-bits per character, so while it may shrink a UCS-4
+ *  string, it will never expand it.
+ *
+ * Strings that don't fit in the destination buffer will be truncated, but
+ *  will always be null-terminated and never have an incomplete UTF-8
+ *  sequence at the end.
+ *
+ *   \param src Null-terminated source string in UCS-4 format.
+ *   \param dst Buffer to store converted UTF-8 string.
+ *   \param len Size, in bytes, of destination buffer.
+ */
+__EXPORT__ void PHYSFS_utf8FromUcs4(const PHYSFS_uint32 *src, char *dst,
+                                    PHYSFS_uint64 len);
+
+/**
+ * \fn void PHYSFS_utf8ToUcs4(const char *src, PHYSFS_uint32 *dst, PHYSFS_uint64 len)
+ * \brief Convert a UTF-8 string to a UCS-4 string.
+ *
+ * UCS-4 strings are 32-bits per character: \c wchar_t on Unix.
+ *
+ * To ensure that the destination buffer is large enough for the conversion,
+ *  please allocate a buffer that is four times the size of the source buffer.
+ *  UTF-8 uses from one to four bytes per character, but UCS-4 always uses
+ *  four, so an entirely low-ASCII string will quadruple in size!
+ *
+ * Strings that don't fit in the destination buffer will be truncated, but
+ *  will always be null-terminated and never have an incomplete UCS-4
+ *  sequence at the end.
+ *
+ *   \param src Null-terminated source string in UTF-8 format.
+ *   \param dst Buffer to store converted UCS-4 string.
+ *   \param len Size, in bytes, of destination buffer.
+ */
+__EXPORT__ void PHYSFS_utf8ToUcs4(const char *src, PHYSFS_uint32 *dst,
+                                  PHYSFS_uint64 len);
+
+/**
+ * \fn void PHYSFS_utf8FromUcs2(const PHYSFS_uint16 *src, char *dst, PHYSFS_uint64 len)
+ * \brief Convert a UCS-2 string to a UTF-8 string.
+ *
+ * UCS-2 strings are 16-bits per character: \c TCHAR on Windows, when building
+ *  with Unicode support.
+ *
+ * To ensure that the destination buffer is large enough for the conversion,
+ *  please allocate a buffer that is double the size of the source buffer.
+ *  UTF-8 never uses more than 32-bits per character, so while it may shrink
+ *  a UCS-2 string, it may also expand it.
+ *
+ * Strings that don't fit in the destination buffer will be truncated, but
+ *  will always be null-terminated and never have an incomplete UTF-8
+ *  sequence at the end.
+ *
+ * Please note that UCS-2 is not UTF-16; we do not support the "surrogate"
+ *  values at this time.
+ *
+ *   \param src Null-terminated source string in UCS-2 format.
+ *   \param dst Buffer to store converted UTF-8 string.
+ *   \param len Size, in bytes, of destination buffer.
+ */
+__EXPORT__ void PHYSFS_utf8FromUcs2(const PHYSFS_uint16 *src, char *dst,
+                                    PHYSFS_uint64 len);
+
+/**
+ * \fn PHYSFS_utf8ToUcs2(const char *src, PHYSFS_uint16 *dst, PHYSFS_uint64 len)
+ * \brief Convert a UTF-8 string to a UCS-2 string.
+ *
+ * UCS-2 strings are 16-bits per character: \c TCHAR on Windows, when building
+ *  with Unicode support.
+ *
+ * To ensure that the destination buffer is large enough for the conversion,
+ *  please allocate a buffer that is double the size of the source buffer.
+ *  UTF-8 uses from one to four bytes per character, but UCS-2 always uses
+ *  two, so an entirely low-ASCII string will double in size!
+ *
+ * Strings that don't fit in the destination buffer will be truncated, but
+ *  will always be null-terminated and never have an incomplete UCS-2
+ *  sequence at the end.
+ *
+ * Please note that UCS-2 is not UTF-16; we do not support the "surrogate"
+ *  values at this time.
+ *
+ *   \param src Null-terminated source string in UTF-8 format.
+ *   \param dst Buffer to store converted UCS-2 string.
+ *   \param len Size, in bytes, of destination buffer.
+ */
+__EXPORT__ void PHYSFS_utf8ToUcs2(const char *src, PHYSFS_uint16 *dst,
+                                  PHYSFS_uint64 len);
+
+/**
+ * \fn void PHYSFS_utf8FromLatin1(const char *src, char *dst, PHYSFS_uint64 len)
+ * \brief Convert a UTF-8 string to a Latin1 string.
+ *
+ * Latin1 strings are 8-bits per character: a popular "high ASCII"
+ *  encoding.
+ *
+ * To ensure that the destination buffer is large enough for the conversion,
+ *  please allocate a buffer that is double the size of the source buffer.
+ *  UTF-8 expands latin1 codepoints over 127 from 1 to 2 bytes, so the string
+ *  may grow in some cases.
+ *
+ * Strings that don't fit in the destination buffer will be truncated, but
+ *  will always be null-terminated and never have an incomplete UTF-8
+ *  sequence at the end.
+ *
+ * Please note that we do not supply a UTF-8 to Latin1 converter, since Latin1
+ *  can't express most Unicode codepoints. It's a legacy encoding; you should
+ *  be converting away from it at all times.
+ *
+ *   \param src Null-terminated source string in Latin1 format.
+ *   \param dst Buffer to store converted UTF-8 string.
+ *   \param len Size, in bytes, of destination buffer.
+ */
+__EXPORT__ void PHYSFS_utf8FromLatin1(const char *src, char *dst,
+                                  PHYSFS_uint64 len);
+
+/* Everything above this line is part of the PhysicsFS 2.0 API. */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* !defined _INCLUDE_PHYSFS_H_ */
+
+/* end of physfs.h ... */
+
diff --git a/src/unison/physfs-1.1.1/physfs.spec.in b/src/unison/physfs-1.1.1/physfs.spec.in
new file mode 100644 (file)
index 0000000..020ac29
--- /dev/null
@@ -0,0 +1,99 @@
+%define version @VERSION@
+%define release 1
+%define name physfs
+%define        prefix  /usr
+
+Summary:       PhysicsFS file abstraction layer for games
+Name:          %{name}
+Version:       %{version}
+Release:       %{release}
+Prefix:                %{prefix}
+Copyright:     zlib license
+Group:         System Environment/Libraries
+URL:           http://www.icculus/physfs/
+Source:                physfs-%{version}.tar.gz
+BuildRoot:     %{_tmppath}/%{name}-%{version}
+BuildRequires: doxygen, readline-devel, ncurses-devel
+Requires: readline, ncurses, zlib
+
+%description
+PhysicsFS is a library to provide abstract access to various archives.
+It is intended for use in video games, and the design was somewhat inspired
+by Quake 3's file subsystem. The programmer defines a "write directory" on
+the physical filesystem. No file writing done through the PhysicsFS API can
+leave that write directory, for security. For example, an embedded scripting
+language cannot write outside of this path if it uses PhysFS for all of its
+I/O, which means that untrusted scripts can run more safely. Symbolic links
+can be disabled as well, for added safety. For file reading, the programmer
+lists directories and archives that form a "search path". Once the search
+path is defined, it becomes a single, transparent hierarchical filesystem.
+This makes for easy access to ZIP files in the same way as you access a file
+directly on the disk, and it makes it easy to ship a new archive that will
+override a previous archive on a per-file basis. Finally, PhysicsFS gives
+you platform-abstracted means to determine if CD-ROMs are available, the
+user's home directory, where in the real filesystem your program is running,
+etc. 
+
+%package devel
+Summary: Development headers, libraries, and documentation for PhysicsFS
+Group: Development/Libraries
+Requires: %{name} = %{version}
+
+%description devel
+PhysicsFS is a library to provide abstract access to various archives.
+This package contains the development headers, libraries, and documentaion to
+build programs using PhysicsFS.
+
+%prep
+%setup
+export CFLAGS="${RPM_OPT_FLAGS}" CXXFLAGS="${RPM_OPT_FLAGS}";
+./configure --prefix=/usr
+
+%build
+export CFLAGS="${RPM_OPT_FLAGS}" CXXFLAGS="${RPM_OPT_FLAGS}";
+make
+# Make doxygen docs
+doxygen
+
+%install
+[ -d ${RPM_BUILD_ROOT} ] && rm -rf ${RPM_BUILD_ROOT}
+make DESTDIR=${RPM_BUILD_ROOT} install
+
+%clean
+[ -d ${RPM_BUILD_ROOT} ] && rm -rf ${RPM_BUILD_ROOT}
+
+%post -p /sbin/ldconfig
+%postun -p /sbin/ldconfig
+
+%files
+%defattr(-,root,root)
+%doc CHANGELOG.txt CREDITS.txt INSTALL.txt LICENSE.txt TODO.txt
+%{_bindir}/test_physfs
+%{_libdir}/*so.*
+
+%files devel
+%defattr(-,root,root)
+%doc docs/*
+%{_libdir}/*.so
+%{_includedir}/physfs.h
+
+%changelog
+* Sun Mar 11 2007 Ryan C. Gordon <icculus@icculus.org>
+- Updated filenames in documents.
+
+* Thu Dec 18 2002 Edward Rudd <eddie@omegaware.com>
+- added zlib_license_change.txt to documents
+
+* Wed Jul 10 2002 Edward Rudd <eddie@omegaware.com>
+- added doxygen to build requirements
+
+* Wed Jul 10 2002 Edward Rudd <eddie@omegaware.com>
+- updated to release 0.17
+
+* Tue May 15 2002 Edward Rudd <eddie@omegaware.com>
+- updated to latest CVS and modified spec file to use 
+  the autoconf/automake support in the latest CVS
+
+* Tue Apr 30 2002 Edward Rudd <eddie@omegaware.com>
+- Initial spec file
+
diff --git a/src/unison/physfs-1.1.1/physfs_byteorder.c b/src/unison/physfs-1.1.1/physfs_byteorder.c
new file mode 100644 (file)
index 0000000..1e6742e
--- /dev/null
@@ -0,0 +1,324 @@
+/**
+ * PhysicsFS; a portable, flexible file i/o abstraction.
+ *
+ * Documentation is in physfs.h. It's verbose, honest.  :)
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+/* The macros used to swap values */
+/* Try to use superfast macros on systems that support them */
+#ifdef linux
+#include <asm/byteorder.h>
+#ifdef __arch__swab16
+#define PHYSFS_Swap16  __arch__swab16
+#endif
+#ifdef __arch__swab32
+#define PHYSFS_Swap32  __arch__swab32
+#endif
+#endif /* linux */
+
+#if (defined macintosh) && !(defined __MWERKS__)
+#define __inline__
+#endif
+
+#if (defined _MSC_VER)
+#define __inline__ __inline
+#endif
+
+#ifndef PHYSFS_Swap16
+static __inline__ PHYSFS_uint16 PHYSFS_Swap16(PHYSFS_uint16 D)
+{
+    return((D<<8)|(D>>8));
+}
+#endif
+#ifndef PHYSFS_Swap32
+static __inline__ PHYSFS_uint32 PHYSFS_Swap32(PHYSFS_uint32 D)
+{
+    return((D<<24)|((D<<8)&0x00FF0000)|((D>>8)&0x0000FF00)|(D>>24));
+}
+#endif
+#ifndef PHYSFS_NO_64BIT_SUPPORT
+#ifndef PHYSFS_Swap64
+static __inline__ PHYSFS_uint64 PHYSFS_Swap64(PHYSFS_uint64 val) {
+    PHYSFS_uint32 hi, lo;
+
+    /* Separate into high and low 32-bit values and swap them */
+    lo = (PHYSFS_uint32)(val&0xFFFFFFFF);
+    val >>= 32;
+    hi = (PHYSFS_uint32)(val&0xFFFFFFFF);
+    val = PHYSFS_Swap32(lo);
+    val <<= 32;
+    val |= PHYSFS_Swap32(hi);
+    return(val);
+}
+#endif
+#else
+#ifndef PHYSFS_Swap64
+/* This is mainly to keep compilers from complaining in PHYSFS code.
+   If there is no real 64-bit datatype, then compilers will complain about
+   the fake 64-bit datatype that PHYSFS provides when it compiles user code.
+*/
+#define PHYSFS_Swap64(X)    (X)
+#endif
+#endif /* PHYSFS_NO_64BIT_SUPPORT */
+
+
+/* Byteswap item from the specified endianness to the native endianness */
+#if PHYSFS_BYTEORDER == PHYSFS_LIL_ENDIAN
+PHYSFS_uint16 PHYSFS_swapULE16(PHYSFS_uint16 x) { return(x); }
+PHYSFS_sint16 PHYSFS_swapSLE16(PHYSFS_sint16 x) { return(x); }
+PHYSFS_uint32 PHYSFS_swapULE32(PHYSFS_uint32 x) { return(x); }
+PHYSFS_sint32 PHYSFS_swapSLE32(PHYSFS_sint32 x) { return(x); }
+PHYSFS_uint64 PHYSFS_swapULE64(PHYSFS_uint64 x) { return(x); }
+PHYSFS_sint64 PHYSFS_swapSLE64(PHYSFS_sint64 x) { return(x); }
+
+PHYSFS_uint16 PHYSFS_swapUBE16(PHYSFS_uint16 x) { return(PHYSFS_Swap16(x)); }
+PHYSFS_sint16 PHYSFS_swapSBE16(PHYSFS_sint16 x) { return(PHYSFS_Swap16(x)); }
+PHYSFS_uint32 PHYSFS_swapUBE32(PHYSFS_uint32 x) { return(PHYSFS_Swap32(x)); }
+PHYSFS_sint32 PHYSFS_swapSBE32(PHYSFS_sint32 x) { return(PHYSFS_Swap32(x)); }
+PHYSFS_uint64 PHYSFS_swapUBE64(PHYSFS_uint64 x) { return(PHYSFS_Swap64(x)); }
+PHYSFS_sint64 PHYSFS_swapSBE64(PHYSFS_sint64 x) { return(PHYSFS_Swap64(x)); }
+#else
+PHYSFS_uint16 PHYSFS_swapULE16(PHYSFS_uint16 x) { return(PHYSFS_Swap16(x)); }
+PHYSFS_sint16 PHYSFS_swapSLE16(PHYSFS_sint16 x) { return(PHYSFS_Swap16(x)); }
+PHYSFS_uint32 PHYSFS_swapULE32(PHYSFS_uint32 x) { return(PHYSFS_Swap32(x)); }
+PHYSFS_sint32 PHYSFS_swapSLE32(PHYSFS_sint32 x) { return(PHYSFS_Swap32(x)); }
+PHYSFS_uint64 PHYSFS_swapULE64(PHYSFS_uint64 x) { return(PHYSFS_Swap64(x)); }
+PHYSFS_sint64 PHYSFS_swapSLE64(PHYSFS_sint64 x) { return(PHYSFS_Swap64(x)); }
+
+PHYSFS_uint16 PHYSFS_swapUBE16(PHYSFS_uint16 x) { return(x); }
+PHYSFS_sint16 PHYSFS_swapSBE16(PHYSFS_sint16 x) { return(x); }
+PHYSFS_uint32 PHYSFS_swapUBE32(PHYSFS_uint32 x) { return(x); }
+PHYSFS_sint32 PHYSFS_swapSBE32(PHYSFS_sint32 x) { return(x); }
+PHYSFS_uint64 PHYSFS_swapUBE64(PHYSFS_uint64 x) { return(x); }
+PHYSFS_sint64 PHYSFS_swapSBE64(PHYSFS_sint64 x) { return(x); }
+#endif
+
+
+int PHYSFS_readSLE16(PHYSFS_File *file, PHYSFS_sint16 *val)
+{
+    PHYSFS_sint16 in;
+    BAIL_IF_MACRO(val == NULL, ERR_INVALID_ARGUMENT, 0);
+    BAIL_IF_MACRO(PHYSFS_read(file, &in, sizeof (in), 1) != 1, NULL, 0);
+    *val = PHYSFS_swapSLE16(in);
+    return(1);
+} /* PHYSFS_readSLE16 */
+
+
+int PHYSFS_readULE16(PHYSFS_File *file, PHYSFS_uint16 *val)
+{
+    PHYSFS_uint16 in;
+    BAIL_IF_MACRO(val == NULL, ERR_INVALID_ARGUMENT, 0);
+    BAIL_IF_MACRO(PHYSFS_read(file, &in, sizeof (in), 1) != 1, NULL, 0);
+    *val = PHYSFS_swapULE16(in);
+    return(1);
+} /* PHYSFS_readULE16 */
+
+
+int PHYSFS_readSBE16(PHYSFS_File *file, PHYSFS_sint16 *val)
+{
+    PHYSFS_sint16 in;
+    BAIL_IF_MACRO(val == NULL, ERR_INVALID_ARGUMENT, 0);
+    BAIL_IF_MACRO(PHYSFS_read(file, &in, sizeof (in), 1) != 1, NULL, 0);
+    *val = PHYSFS_swapSBE16(in);
+    return(1);
+} /* PHYSFS_readSBE16 */
+
+
+int PHYSFS_readUBE16(PHYSFS_File *file, PHYSFS_uint16 *val)
+{
+    PHYSFS_uint16 in;
+    BAIL_IF_MACRO(val == NULL, ERR_INVALID_ARGUMENT, 0);
+    BAIL_IF_MACRO(PHYSFS_read(file, &in, sizeof (in), 1) != 1, NULL, 0);
+    *val = PHYSFS_swapUBE16(in);
+    return(1);
+} /* PHYSFS_readUBE16 */
+
+
+int PHYSFS_readSLE32(PHYSFS_File *file, PHYSFS_sint32 *val)
+{
+    PHYSFS_sint32 in;
+    BAIL_IF_MACRO(val == NULL, ERR_INVALID_ARGUMENT, 0);
+    BAIL_IF_MACRO(PHYSFS_read(file, &in, sizeof (in), 1) != 1, NULL, 0);
+    *val = PHYSFS_swapSLE32(in);
+    return(1);
+} /* PHYSFS_readSLE32 */
+
+
+int PHYSFS_readULE32(PHYSFS_File *file, PHYSFS_uint32 *val)
+{
+    PHYSFS_uint32 in;
+    BAIL_IF_MACRO(val == NULL, ERR_INVALID_ARGUMENT, 0);
+    BAIL_IF_MACRO(PHYSFS_read(file, &in, sizeof (in), 1) != 1, NULL, 0);
+    *val = PHYSFS_swapULE32(in);
+    return(1);
+} /* PHYSFS_readULE32 */
+
+
+int PHYSFS_readSBE32(PHYSFS_File *file, PHYSFS_sint32 *val)
+{
+    PHYSFS_sint32 in;
+    BAIL_IF_MACRO(val == NULL, ERR_INVALID_ARGUMENT, 0);
+    BAIL_IF_MACRO(PHYSFS_read(file, &in, sizeof (in), 1) != 1, NULL, 0);
+    *val = PHYSFS_swapSBE32(in);
+    return(1);
+} /* PHYSFS_readSBE32 */
+
+
+int PHYSFS_readUBE32(PHYSFS_File *file, PHYSFS_uint32 *val)
+{
+    PHYSFS_uint32 in;
+    BAIL_IF_MACRO(val == NULL, ERR_INVALID_ARGUMENT, 0);
+    BAIL_IF_MACRO(PHYSFS_read(file, &in, sizeof (in), 1) != 1, NULL, 0);
+    *val = PHYSFS_swapUBE32(in);
+    return(1);
+} /* PHYSFS_readUBE32 */
+
+
+int PHYSFS_readSLE64(PHYSFS_File *file, PHYSFS_sint64 *val)
+{
+    PHYSFS_sint64 in;
+    BAIL_IF_MACRO(val == NULL, ERR_INVALID_ARGUMENT, 0);
+    BAIL_IF_MACRO(PHYSFS_read(file, &in, sizeof (in), 1) != 1, NULL, 0);
+    *val = PHYSFS_swapSLE64(in);
+    return(1);
+} /* PHYSFS_readSLE64 */
+
+
+int PHYSFS_readULE64(PHYSFS_File *file, PHYSFS_uint64 *val)
+{
+    PHYSFS_uint64 in;
+    BAIL_IF_MACRO(val == NULL, ERR_INVALID_ARGUMENT, 0);
+    BAIL_IF_MACRO(PHYSFS_read(file, &in, sizeof (in), 1) != 1, NULL, 0);
+    *val = PHYSFS_swapULE64(in);
+    return(1);
+} /* PHYSFS_readULE64 */
+
+
+int PHYSFS_readSBE64(PHYSFS_File *file, PHYSFS_sint64 *val)
+{
+    PHYSFS_sint64 in;
+    BAIL_IF_MACRO(val == NULL, ERR_INVALID_ARGUMENT, 0);
+    BAIL_IF_MACRO(PHYSFS_read(file, &in, sizeof (in), 1) != 1, NULL, 0);
+    *val = PHYSFS_swapSBE64(in);
+    return(1);
+} /* PHYSFS_readSBE64 */
+
+
+int PHYSFS_readUBE64(PHYSFS_File *file, PHYSFS_uint64 *val)
+{
+    PHYSFS_uint64 in;
+    BAIL_IF_MACRO(val == NULL, ERR_INVALID_ARGUMENT, 0);
+    BAIL_IF_MACRO(PHYSFS_read(file, &in, sizeof (in), 1) != 1, NULL, 0);
+    *val = PHYSFS_swapUBE64(in);
+    return(1);
+} /* PHYSFS_readUBE64 */
+
+
+
+int PHYSFS_writeSLE16(PHYSFS_File *file, PHYSFS_sint16 val)
+{
+    PHYSFS_sint16 out = PHYSFS_swapSLE16(val);
+    BAIL_IF_MACRO(PHYSFS_write(file, &out, sizeof (out), 1) != 1, NULL, 0);
+    return(1);
+} /* PHYSFS_writeSLE16 */
+
+
+int PHYSFS_writeULE16(PHYSFS_File *file, PHYSFS_uint16 val)
+{
+    PHYSFS_uint16 out = PHYSFS_swapULE16(val);
+    BAIL_IF_MACRO(PHYSFS_write(file, &out, sizeof (out), 1) != 1, NULL, 0);
+    return(1);
+} /* PHYSFS_writeULE16 */
+
+
+int PHYSFS_writeSBE16(PHYSFS_File *file, PHYSFS_sint16 val)
+{
+    PHYSFS_sint16 out = PHYSFS_swapSBE16(val);
+    BAIL_IF_MACRO(PHYSFS_write(file, &out, sizeof (out), 1) != 1, NULL, 0);
+    return(1);
+} /* PHYSFS_writeSBE16 */
+
+
+int PHYSFS_writeUBE16(PHYSFS_File *file, PHYSFS_uint16 val)
+{
+    PHYSFS_uint16 out = PHYSFS_swapUBE16(val);
+    BAIL_IF_MACRO(PHYSFS_write(file, &out, sizeof (out), 1) != 1, NULL, 0);
+    return(1);
+} /* PHYSFS_writeUBE16 */
+
+
+int PHYSFS_writeSLE32(PHYSFS_File *file, PHYSFS_sint32 val)
+{
+    PHYSFS_sint32 out = PHYSFS_swapSLE32(val);
+    BAIL_IF_MACRO(PHYSFS_write(file, &out, sizeof (out), 1) != 1, NULL, 0);
+    return(1);
+} /* PHYSFS_writeSLE32 */
+
+
+int PHYSFS_writeULE32(PHYSFS_File *file, PHYSFS_uint32 val)
+{
+    PHYSFS_uint32 out = PHYSFS_swapULE32(val);
+    BAIL_IF_MACRO(PHYSFS_write(file, &out, sizeof (out), 1) != 1, NULL, 0);
+    return(1);
+} /* PHYSFS_writeULE32 */
+
+
+int PHYSFS_writeSBE32(PHYSFS_File *file, PHYSFS_sint32 val)
+{
+    PHYSFS_sint32 out = PHYSFS_swapSBE32(val);
+    BAIL_IF_MACRO(PHYSFS_write(file, &out, sizeof (out), 1) != 1, NULL, 0);
+    return(1);
+} /* PHYSFS_writeSBE32 */
+
+
+int PHYSFS_writeUBE32(PHYSFS_File *file, PHYSFS_uint32 val)
+{
+    PHYSFS_uint32 out = PHYSFS_swapUBE32(val);
+    BAIL_IF_MACRO(PHYSFS_write(file, &out, sizeof (out), 1) != 1, NULL, 0);
+    return(1);
+} /* PHYSFS_writeUBE32 */
+
+
+int PHYSFS_writeSLE64(PHYSFS_File *file, PHYSFS_sint64 val)
+{
+    PHYSFS_sint64 out = PHYSFS_swapSLE64(val);
+    BAIL_IF_MACRO(PHYSFS_write(file, &out, sizeof (out), 1) != 1, NULL, 0);
+    return(1);
+} /* PHYSFS_writeSLE64 */
+
+
+int PHYSFS_writeULE64(PHYSFS_File *file, PHYSFS_uint64 val)
+{
+    PHYSFS_uint64 out = PHYSFS_swapULE64(val);
+    BAIL_IF_MACRO(PHYSFS_write(file, &out, sizeof (out), 1) != 1, NULL, 0);
+    return(1);
+} /* PHYSFS_writeULE64 */
+
+
+int PHYSFS_writeSBE64(PHYSFS_File *file, PHYSFS_sint64 val)
+{
+    PHYSFS_sint64 out = PHYSFS_swapSBE64(val);
+    BAIL_IF_MACRO(PHYSFS_write(file, &out, sizeof (out), 1) != 1, NULL, 0);
+    return(1);
+} /* PHYSFS_writeSBE64 */
+
+
+int PHYSFS_writeUBE64(PHYSFS_File *file, PHYSFS_uint64 val)
+{
+    PHYSFS_uint64 out = PHYSFS_swapUBE64(val);
+    BAIL_IF_MACRO(PHYSFS_write(file, &out, sizeof (out), 1) != 1, NULL, 0);
+    return(1);
+} /* PHYSFS_writeUBE64 */
+
+/* end of physfs_byteorder.c ... */
+
diff --git a/src/unison/physfs-1.1.1/physfs_casefolding.h b/src/unison/physfs-1.1.1/physfs_casefolding.h
new file mode 100644 (file)
index 0000000..0e50f1e
--- /dev/null
@@ -0,0 +1,2013 @@
+/*
+ * This file is part of PhysicsFS (http://icculus.org/physfs/)
+ *
+ * This data generated by physfs/extras/makecasefoldhashtable.pl ...
+ * Do not manually edit this file!
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ */
+
+#ifndef __PHYSICSFS_INTERNAL__
+#error Do not include this header from your applications.
+#endif
+
+static const CaseFoldMapping case_fold_000[] = {
+    { 0x0202, 0x0203, 0x0000, 0x0000 },
+    { 0x0404, 0x0454, 0x0000, 0x0000 },
+    { 0x1E1E, 0x1E1F, 0x0000, 0x0000 },
+    { 0x2C2C, 0x2C5C, 0x0000, 0x0000 },
+    { 0x10404, 0x1042C, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_001[] = {
+    { 0x0100, 0x0101, 0x0000, 0x0000 },
+    { 0x0405, 0x0455, 0x0000, 0x0000 },
+    { 0x0504, 0x0505, 0x0000, 0x0000 },
+    { 0x2C2D, 0x2C5D, 0x0000, 0x0000 },
+    { 0x10405, 0x1042D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_002[] = {
+    { 0x0200, 0x0201, 0x0000, 0x0000 },
+    { 0x0406, 0x0456, 0x0000, 0x0000 },
+    { 0x1E1C, 0x1E1D, 0x0000, 0x0000 },
+    { 0x1F1D, 0x1F15, 0x0000, 0x0000 },
+    { 0x2C2E, 0x2C5E, 0x0000, 0x0000 },
+    { 0x10406, 0x1042E, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_003[] = {
+    { 0x0102, 0x0103, 0x0000, 0x0000 },
+    { 0x0407, 0x0457, 0x0000, 0x0000 },
+    { 0x0506, 0x0507, 0x0000, 0x0000 },
+    { 0x1F1C, 0x1F14, 0x0000, 0x0000 },
+    { 0x10407, 0x1042F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_004[] = {
+    { 0x0206, 0x0207, 0x0000, 0x0000 },
+    { 0x0400, 0x0450, 0x0000, 0x0000 },
+    { 0x1E1A, 0x1E1B, 0x0000, 0x0000 },
+    { 0x1F1B, 0x1F13, 0x0000, 0x0000 },
+    { 0x2C28, 0x2C58, 0x0000, 0x0000 },
+    { 0x10400, 0x10428, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_005[] = {
+    { 0x0104, 0x0105, 0x0000, 0x0000 },
+    { 0x0401, 0x0451, 0x0000, 0x0000 },
+    { 0x0500, 0x0501, 0x0000, 0x0000 },
+    { 0x1F1A, 0x1F12, 0x0000, 0x0000 },
+    { 0x2C29, 0x2C59, 0x0000, 0x0000 },
+    { 0x10401, 0x10429, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_006[] = {
+    { 0x0204, 0x0205, 0x0000, 0x0000 },
+    { 0x0402, 0x0452, 0x0000, 0x0000 },
+    { 0x1E18, 0x1E19, 0x0000, 0x0000 },
+    { 0x1F19, 0x1F11, 0x0000, 0x0000 },
+    { 0x2C2A, 0x2C5A, 0x0000, 0x0000 },
+    { 0x10402, 0x1042A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_007[] = {
+    { 0x0106, 0x0107, 0x0000, 0x0000 },
+    { 0x0403, 0x0453, 0x0000, 0x0000 },
+    { 0x0502, 0x0503, 0x0000, 0x0000 },
+    { 0x1F18, 0x1F10, 0x0000, 0x0000 },
+    { 0x2126, 0x03C9, 0x0000, 0x0000 },
+    { 0x2C2B, 0x2C5B, 0x0000, 0x0000 },
+    { 0x10403, 0x1042B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_008[] = {
+    { 0x020A, 0x020B, 0x0000, 0x0000 },
+    { 0x040C, 0x045C, 0x0000, 0x0000 },
+    { 0x1E16, 0x1E17, 0x0000, 0x0000 },
+    { 0x2C24, 0x2C54, 0x0000, 0x0000 },
+    { 0x1040C, 0x10434, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_009[] = {
+    { 0x0108, 0x0109, 0x0000, 0x0000 },
+    { 0x040D, 0x045D, 0x0000, 0x0000 },
+    { 0x050C, 0x050D, 0x0000, 0x0000 },
+    { 0x2C25, 0x2C55, 0x0000, 0x0000 },
+    { 0x1040D, 0x10435, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_010[] = {
+    { 0x0208, 0x0209, 0x0000, 0x0000 },
+    { 0x040E, 0x045E, 0x0000, 0x0000 },
+    { 0x1E14, 0x1E15, 0x0000, 0x0000 },
+    { 0x212B, 0x00E5, 0x0000, 0x0000 },
+    { 0x2C26, 0x2C56, 0x0000, 0x0000 },
+    { 0x1040E, 0x10436, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_011[] = {
+    { 0x010A, 0x010B, 0x0000, 0x0000 },
+    { 0x040F, 0x045F, 0x0000, 0x0000 },
+    { 0x050E, 0x050F, 0x0000, 0x0000 },
+    { 0x212A, 0x006B, 0x0000, 0x0000 },
+    { 0x2C27, 0x2C57, 0x0000, 0x0000 },
+    { 0x1040F, 0x10437, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_012[] = {
+    { 0x020E, 0x020F, 0x0000, 0x0000 },
+    { 0x0408, 0x0458, 0x0000, 0x0000 },
+    { 0x1E12, 0x1E13, 0x0000, 0x0000 },
+    { 0x2C20, 0x2C50, 0x0000, 0x0000 },
+    { 0x10408, 0x10430, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_013[] = {
+    { 0x010C, 0x010D, 0x0000, 0x0000 },
+    { 0x0409, 0x0459, 0x0000, 0x0000 },
+    { 0x0508, 0x0509, 0x0000, 0x0000 },
+    { 0x2C21, 0x2C51, 0x0000, 0x0000 },
+    { 0x10409, 0x10431, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_014[] = {
+    { 0x020C, 0x020D, 0x0000, 0x0000 },
+    { 0x040A, 0x045A, 0x0000, 0x0000 },
+    { 0x1E10, 0x1E11, 0x0000, 0x0000 },
+    { 0x2C22, 0x2C52, 0x0000, 0x0000 },
+    { 0x1040A, 0x10432, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_015[] = {
+    { 0x010E, 0x010F, 0x0000, 0x0000 },
+    { 0x040B, 0x045B, 0x0000, 0x0000 },
+    { 0x050A, 0x050B, 0x0000, 0x0000 },
+    { 0x2C23, 0x2C53, 0x0000, 0x0000 },
+    { 0x1040B, 0x10433, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_016[] = {
+    { 0x0212, 0x0213, 0x0000, 0x0000 },
+    { 0x0414, 0x0434, 0x0000, 0x0000 },
+    { 0x1E0E, 0x1E0F, 0x0000, 0x0000 },
+    { 0x1F0F, 0x1F07, 0x0000, 0x0000 },
+    { 0x10414, 0x1043C, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_017[] = {
+    { 0x0110, 0x0111, 0x0000, 0x0000 },
+    { 0x0415, 0x0435, 0x0000, 0x0000 },
+    { 0x1F0E, 0x1F06, 0x0000, 0x0000 },
+    { 0x10415, 0x1043D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_018[] = {
+    { 0x0210, 0x0211, 0x0000, 0x0000 },
+    { 0x0416, 0x0436, 0x0000, 0x0000 },
+    { 0x1E0C, 0x1E0D, 0x0000, 0x0000 },
+    { 0x1F0D, 0x1F05, 0x0000, 0x0000 },
+    { 0x10416, 0x1043E, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_019[] = {
+    { 0x0112, 0x0113, 0x0000, 0x0000 },
+    { 0x0417, 0x0437, 0x0000, 0x0000 },
+    { 0x1F0C, 0x1F04, 0x0000, 0x0000 },
+    { 0x10417, 0x1043F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_020[] = {
+    { 0x0216, 0x0217, 0x0000, 0x0000 },
+    { 0x0410, 0x0430, 0x0000, 0x0000 },
+    { 0x1E0A, 0x1E0B, 0x0000, 0x0000 },
+    { 0x1F0B, 0x1F03, 0x0000, 0x0000 },
+    { 0x10410, 0x10438, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_021[] = {
+    { 0x0114, 0x0115, 0x0000, 0x0000 },
+    { 0x0411, 0x0431, 0x0000, 0x0000 },
+    { 0x1F0A, 0x1F02, 0x0000, 0x0000 },
+    { 0x10411, 0x10439, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_022[] = {
+    { 0x0214, 0x0215, 0x0000, 0x0000 },
+    { 0x0412, 0x0432, 0x0000, 0x0000 },
+    { 0x1E08, 0x1E09, 0x0000, 0x0000 },
+    { 0x1F09, 0x1F01, 0x0000, 0x0000 },
+    { 0x10412, 0x1043A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_023[] = {
+    { 0x0116, 0x0117, 0x0000, 0x0000 },
+    { 0x0413, 0x0433, 0x0000, 0x0000 },
+    { 0x1F08, 0x1F00, 0x0000, 0x0000 },
+    { 0x10413, 0x1043B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_024[] = {
+    { 0x021A, 0x021B, 0x0000, 0x0000 },
+    { 0x041C, 0x043C, 0x0000, 0x0000 },
+    { 0x1E06, 0x1E07, 0x0000, 0x0000 },
+    { 0x1041C, 0x10444, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_025[] = {
+    { 0x0118, 0x0119, 0x0000, 0x0000 },
+    { 0x041D, 0x043D, 0x0000, 0x0000 },
+    { 0x1041D, 0x10445, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_026[] = {
+    { 0x0218, 0x0219, 0x0000, 0x0000 },
+    { 0x041E, 0x043E, 0x0000, 0x0000 },
+    { 0x1E04, 0x1E05, 0x0000, 0x0000 },
+    { 0x1041E, 0x10446, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_027[] = {
+    { 0x011A, 0x011B, 0x0000, 0x0000 },
+    { 0x041F, 0x043F, 0x0000, 0x0000 },
+    { 0x1041F, 0x10447, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_028[] = {
+    { 0x021E, 0x021F, 0x0000, 0x0000 },
+    { 0x0418, 0x0438, 0x0000, 0x0000 },
+    { 0x1E02, 0x1E03, 0x0000, 0x0000 },
+    { 0x10418, 0x10440, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_029[] = {
+    { 0x011C, 0x011D, 0x0000, 0x0000 },
+    { 0x0419, 0x0439, 0x0000, 0x0000 },
+    { 0x10419, 0x10441, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_030[] = {
+    { 0x021C, 0x021D, 0x0000, 0x0000 },
+    { 0x041A, 0x043A, 0x0000, 0x0000 },
+    { 0x1E00, 0x1E01, 0x0000, 0x0000 },
+    { 0x1041A, 0x10442, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_031[] = {
+    { 0x011E, 0x011F, 0x0000, 0x0000 },
+    { 0x041B, 0x043B, 0x0000, 0x0000 },
+    { 0x1041B, 0x10443, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_032[] = {
+    { 0x0222, 0x0223, 0x0000, 0x0000 },
+    { 0x0424, 0x0444, 0x0000, 0x0000 },
+    { 0x1E3E, 0x1E3F, 0x0000, 0x0000 },
+    { 0x1F3F, 0x1F37, 0x0000, 0x0000 },
+    { 0x2C0C, 0x2C3C, 0x0000, 0x0000 },
+    { 0x10424, 0x1044C, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_033[] = {
+    { 0x0120, 0x0121, 0x0000, 0x0000 },
+    { 0x0425, 0x0445, 0x0000, 0x0000 },
+    { 0x1F3E, 0x1F36, 0x0000, 0x0000 },
+    { 0x2C0D, 0x2C3D, 0x0000, 0x0000 },
+    { 0x10425, 0x1044D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_034[] = {
+    { 0x0220, 0x019E, 0x0000, 0x0000 },
+    { 0x0426, 0x0446, 0x0000, 0x0000 },
+    { 0x1E3C, 0x1E3D, 0x0000, 0x0000 },
+    { 0x1F3D, 0x1F35, 0x0000, 0x0000 },
+    { 0x2C0E, 0x2C3E, 0x0000, 0x0000 },
+    { 0x10426, 0x1044E, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_035[] = {
+    { 0x0122, 0x0123, 0x0000, 0x0000 },
+    { 0x0427, 0x0447, 0x0000, 0x0000 },
+    { 0x1F3C, 0x1F34, 0x0000, 0x0000 },
+    { 0x2C0F, 0x2C3F, 0x0000, 0x0000 },
+    { 0x10427, 0x1044F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_036[] = {
+    { 0x0226, 0x0227, 0x0000, 0x0000 },
+    { 0x0420, 0x0440, 0x0000, 0x0000 },
+    { 0x1E3A, 0x1E3B, 0x0000, 0x0000 },
+    { 0x1F3B, 0x1F33, 0x0000, 0x0000 },
+    { 0x2C08, 0x2C38, 0x0000, 0x0000 },
+    { 0x10420, 0x10448, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_037[] = {
+    { 0x0124, 0x0125, 0x0000, 0x0000 },
+    { 0x0421, 0x0441, 0x0000, 0x0000 },
+    { 0x1F3A, 0x1F32, 0x0000, 0x0000 },
+    { 0x2C09, 0x2C39, 0x0000, 0x0000 },
+    { 0x10421, 0x10449, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_038[] = {
+    { 0x0224, 0x0225, 0x0000, 0x0000 },
+    { 0x0422, 0x0442, 0x0000, 0x0000 },
+    { 0x1E38, 0x1E39, 0x0000, 0x0000 },
+    { 0x1F39, 0x1F31, 0x0000, 0x0000 },
+    { 0x2C0A, 0x2C3A, 0x0000, 0x0000 },
+    { 0x10422, 0x1044A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_039[] = {
+    { 0x0126, 0x0127, 0x0000, 0x0000 },
+    { 0x0423, 0x0443, 0x0000, 0x0000 },
+    { 0x1F38, 0x1F30, 0x0000, 0x0000 },
+    { 0x2C0B, 0x2C3B, 0x0000, 0x0000 },
+    { 0x10423, 0x1044B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_040[] = {
+    { 0x022A, 0x022B, 0x0000, 0x0000 },
+    { 0x042C, 0x044C, 0x0000, 0x0000 },
+    { 0x1E36, 0x1E37, 0x0000, 0x0000 },
+    { 0x2C04, 0x2C34, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_041[] = {
+    { 0x0128, 0x0129, 0x0000, 0x0000 },
+    { 0x042D, 0x044D, 0x0000, 0x0000 },
+    { 0x2C05, 0x2C35, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_042[] = {
+    { 0x0228, 0x0229, 0x0000, 0x0000 },
+    { 0x042E, 0x044E, 0x0000, 0x0000 },
+    { 0x1E34, 0x1E35, 0x0000, 0x0000 },
+    { 0x2C06, 0x2C36, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_043[] = {
+    { 0x012A, 0x012B, 0x0000, 0x0000 },
+    { 0x042F, 0x044F, 0x0000, 0x0000 },
+    { 0x2C07, 0x2C37, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_044[] = {
+    { 0x022E, 0x022F, 0x0000, 0x0000 },
+    { 0x0428, 0x0448, 0x0000, 0x0000 },
+    { 0x1E32, 0x1E33, 0x0000, 0x0000 },
+    { 0x2C00, 0x2C30, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_045[] = {
+    { 0x012C, 0x012D, 0x0000, 0x0000 },
+    { 0x0429, 0x0449, 0x0000, 0x0000 },
+    { 0x2C01, 0x2C31, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_046[] = {
+    { 0x022C, 0x022D, 0x0000, 0x0000 },
+    { 0x042A, 0x044A, 0x0000, 0x0000 },
+    { 0x1E30, 0x1E31, 0x0000, 0x0000 },
+    { 0x2C02, 0x2C32, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_047[] = {
+    { 0x012E, 0x012F, 0x0000, 0x0000 },
+    { 0x042B, 0x044B, 0x0000, 0x0000 },
+    { 0x2C03, 0x2C33, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_048[] = {
+    { 0x0232, 0x0233, 0x0000, 0x0000 },
+    { 0x0535, 0x0565, 0x0000, 0x0000 },
+    { 0x1E2E, 0x1E2F, 0x0000, 0x0000 },
+    { 0x1F2F, 0x1F27, 0x0000, 0x0000 },
+    { 0x2C1C, 0x2C4C, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_049[] = {
+    { 0x0130, 0x0069, 0x0307, 0x0000 },
+    { 0x0534, 0x0564, 0x0000, 0x0000 },
+    { 0x1F2E, 0x1F26, 0x0000, 0x0000 },
+    { 0x2C1D, 0x2C4D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_050[] = {
+    { 0x0230, 0x0231, 0x0000, 0x0000 },
+    { 0x0537, 0x0567, 0x0000, 0x0000 },
+    { 0x1E2C, 0x1E2D, 0x0000, 0x0000 },
+    { 0x1F2D, 0x1F25, 0x0000, 0x0000 },
+    { 0x2C1E, 0x2C4E, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_051[] = {
+    { 0x0132, 0x0133, 0x0000, 0x0000 },
+    { 0x0536, 0x0566, 0x0000, 0x0000 },
+    { 0x1F2C, 0x1F24, 0x0000, 0x0000 },
+    { 0x2C1F, 0x2C4F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_052[] = {
+    { 0x0531, 0x0561, 0x0000, 0x0000 },
+    { 0x1E2A, 0x1E2B, 0x0000, 0x0000 },
+    { 0x1F2B, 0x1F23, 0x0000, 0x0000 },
+    { 0x2C18, 0x2C48, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_053[] = {
+    { 0x0134, 0x0135, 0x0000, 0x0000 },
+    { 0x1F2A, 0x1F22, 0x0000, 0x0000 },
+    { 0x2C19, 0x2C49, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_054[] = {
+    { 0x0533, 0x0563, 0x0000, 0x0000 },
+    { 0x1E28, 0x1E29, 0x0000, 0x0000 },
+    { 0x1F29, 0x1F21, 0x0000, 0x0000 },
+    { 0x2C1A, 0x2C4A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_055[] = {
+    { 0x0136, 0x0137, 0x0000, 0x0000 },
+    { 0x0532, 0x0562, 0x0000, 0x0000 },
+    { 0x1F28, 0x1F20, 0x0000, 0x0000 },
+    { 0x2C1B, 0x2C4B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_056[] = {
+    { 0x0139, 0x013A, 0x0000, 0x0000 },
+    { 0x053D, 0x056D, 0x0000, 0x0000 },
+    { 0x1E26, 0x1E27, 0x0000, 0x0000 },
+    { 0x2C14, 0x2C44, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_057[] = {
+    { 0x023B, 0x023C, 0x0000, 0x0000 },
+    { 0x053C, 0x056C, 0x0000, 0x0000 },
+    { 0x2C15, 0x2C45, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_058[] = {
+    { 0x013B, 0x013C, 0x0000, 0x0000 },
+    { 0x053F, 0x056F, 0x0000, 0x0000 },
+    { 0x1E24, 0x1E25, 0x0000, 0x0000 },
+    { 0x2C16, 0x2C46, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_059[] = {
+    { 0x053E, 0x056E, 0x0000, 0x0000 },
+    { 0x2C17, 0x2C47, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_060[] = {
+    { 0x013D, 0x013E, 0x0000, 0x0000 },
+    { 0x0539, 0x0569, 0x0000, 0x0000 },
+    { 0x1E22, 0x1E23, 0x0000, 0x0000 },
+    { 0x2C10, 0x2C40, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_061[] = {
+    { 0x0538, 0x0568, 0x0000, 0x0000 },
+    { 0x2C11, 0x2C41, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_062[] = {
+    { 0x013F, 0x0140, 0x0000, 0x0000 },
+    { 0x053B, 0x056B, 0x0000, 0x0000 },
+    { 0x1E20, 0x1E21, 0x0000, 0x0000 },
+    { 0x2C12, 0x2C42, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_063[] = {
+    { 0x023D, 0x019A, 0x0000, 0x0000 },
+    { 0x053A, 0x056A, 0x0000, 0x0000 },
+    { 0x2C13, 0x2C43, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_064[] = {
+    { 0x0141, 0x0142, 0x0000, 0x0000 },
+    { 0x0545, 0x0575, 0x0000, 0x0000 },
+    { 0x1E5E, 0x1E5F, 0x0000, 0x0000 },
+    { 0x1F5F, 0x1F57, 0x0000, 0x0000 },
+    { 0x2161, 0x2171, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_065[] = {
+    { 0x0041, 0x0061, 0x0000, 0x0000 },
+    { 0x0544, 0x0574, 0x0000, 0x0000 },
+    { 0x2160, 0x2170, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_066[] = {
+    { 0x0042, 0x0062, 0x0000, 0x0000 },
+    { 0x0143, 0x0144, 0x0000, 0x0000 },
+    { 0x0547, 0x0577, 0x0000, 0x0000 },
+    { 0x1E5C, 0x1E5D, 0x0000, 0x0000 },
+    { 0x1F5D, 0x1F55, 0x0000, 0x0000 },
+    { 0x2163, 0x2173, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_067[] = {
+    { 0x0043, 0x0063, 0x0000, 0x0000 },
+    { 0x0241, 0x0294, 0x0000, 0x0000 },
+    { 0x0546, 0x0576, 0x0000, 0x0000 },
+    { 0x2162, 0x2172, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_068[] = {
+    { 0x0044, 0x0064, 0x0000, 0x0000 },
+    { 0x0145, 0x0146, 0x0000, 0x0000 },
+    { 0x0541, 0x0571, 0x0000, 0x0000 },
+    { 0x1E5A, 0x1E5B, 0x0000, 0x0000 },
+    { 0x1F5B, 0x1F53, 0x0000, 0x0000 },
+    { 0x2165, 0x2175, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_069[] = {
+    { 0x0045, 0x0065, 0x0000, 0x0000 },
+    { 0x0540, 0x0570, 0x0000, 0x0000 },
+    { 0x2164, 0x2174, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_070[] = {
+    { 0x0046, 0x0066, 0x0000, 0x0000 },
+    { 0x0147, 0x0148, 0x0000, 0x0000 },
+    { 0x0345, 0x03B9, 0x0000, 0x0000 },
+    { 0x0543, 0x0573, 0x0000, 0x0000 },
+    { 0x1E58, 0x1E59, 0x0000, 0x0000 },
+    { 0x1F59, 0x1F51, 0x0000, 0x0000 },
+    { 0x2167, 0x2177, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_071[] = {
+    { 0x0047, 0x0067, 0x0000, 0x0000 },
+    { 0x0542, 0x0572, 0x0000, 0x0000 },
+    { 0x2166, 0x2176, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_072[] = {
+    { 0x0048, 0x0068, 0x0000, 0x0000 },
+    { 0x0149, 0x02BC, 0x006E, 0x0000 },
+    { 0x054D, 0x057D, 0x0000, 0x0000 },
+    { 0x1E56, 0x1E57, 0x0000, 0x0000 },
+    { 0x2169, 0x2179, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_073[] = {
+    { 0x0049, 0x0069, 0x0000, 0x0000 },
+    { 0x054C, 0x057C, 0x0000, 0x0000 },
+    { 0x1F56, 0x03C5, 0x0313, 0x0342 },
+    { 0x2168, 0x2178, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_074[] = {
+    { 0x004A, 0x006A, 0x0000, 0x0000 },
+    { 0x054F, 0x057F, 0x0000, 0x0000 },
+    { 0x1E54, 0x1E55, 0x0000, 0x0000 },
+    { 0x216B, 0x217B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_075[] = {
+    { 0x004B, 0x006B, 0x0000, 0x0000 },
+    { 0x014A, 0x014B, 0x0000, 0x0000 },
+    { 0x054E, 0x057E, 0x0000, 0x0000 },
+    { 0x1F54, 0x03C5, 0x0313, 0x0301 },
+    { 0x216A, 0x217A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_076[] = {
+    { 0x004C, 0x006C, 0x0000, 0x0000 },
+    { 0x0549, 0x0579, 0x0000, 0x0000 },
+    { 0x1E52, 0x1E53, 0x0000, 0x0000 },
+    { 0x216D, 0x217D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_077[] = {
+    { 0x004D, 0x006D, 0x0000, 0x0000 },
+    { 0x014C, 0x014D, 0x0000, 0x0000 },
+    { 0x0548, 0x0578, 0x0000, 0x0000 },
+    { 0x1F52, 0x03C5, 0x0313, 0x0300 },
+    { 0x216C, 0x217C, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_078[] = {
+    { 0x004E, 0x006E, 0x0000, 0x0000 },
+    { 0x054B, 0x057B, 0x0000, 0x0000 },
+    { 0x1E50, 0x1E51, 0x0000, 0x0000 },
+    { 0x216F, 0x217F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_079[] = {
+    { 0x004F, 0x006F, 0x0000, 0x0000 },
+    { 0x014E, 0x014F, 0x0000, 0x0000 },
+    { 0x054A, 0x057A, 0x0000, 0x0000 },
+    { 0x1F50, 0x03C5, 0x0313, 0x0000 },
+    { 0x216E, 0x217E, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_080[] = {
+    { 0x0050, 0x0070, 0x0000, 0x0000 },
+    { 0x0555, 0x0585, 0x0000, 0x0000 },
+    { 0x1E4E, 0x1E4F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_081[] = {
+    { 0x0051, 0x0071, 0x0000, 0x0000 },
+    { 0x0150, 0x0151, 0x0000, 0x0000 },
+    { 0x0554, 0x0584, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_082[] = {
+    { 0x0052, 0x0072, 0x0000, 0x0000 },
+    { 0x1E4C, 0x1E4D, 0x0000, 0x0000 },
+    { 0x1F4D, 0x1F45, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_083[] = {
+    { 0x0053, 0x0073, 0x0000, 0x0000 },
+    { 0x0152, 0x0153, 0x0000, 0x0000 },
+    { 0x0556, 0x0586, 0x0000, 0x0000 },
+    { 0x1F4C, 0x1F44, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_084[] = {
+    { 0x0054, 0x0074, 0x0000, 0x0000 },
+    { 0x0551, 0x0581, 0x0000, 0x0000 },
+    { 0x1E4A, 0x1E4B, 0x0000, 0x0000 },
+    { 0x1F4B, 0x1F43, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_085[] = {
+    { 0x0055, 0x0075, 0x0000, 0x0000 },
+    { 0x0154, 0x0155, 0x0000, 0x0000 },
+    { 0x0550, 0x0580, 0x0000, 0x0000 },
+    { 0x1F4A, 0x1F42, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_086[] = {
+    { 0x0056, 0x0076, 0x0000, 0x0000 },
+    { 0x0553, 0x0583, 0x0000, 0x0000 },
+    { 0x1E48, 0x1E49, 0x0000, 0x0000 },
+    { 0x1F49, 0x1F41, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_087[] = {
+    { 0x0057, 0x0077, 0x0000, 0x0000 },
+    { 0x0156, 0x0157, 0x0000, 0x0000 },
+    { 0x0552, 0x0582, 0x0000, 0x0000 },
+    { 0x1F48, 0x1F40, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_088[] = {
+    { 0x0058, 0x0078, 0x0000, 0x0000 },
+    { 0x1E46, 0x1E47, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_089[] = {
+    { 0x0059, 0x0079, 0x0000, 0x0000 },
+    { 0x0158, 0x0159, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_090[] = {
+    { 0x005A, 0x007A, 0x0000, 0x0000 },
+    { 0x1E44, 0x1E45, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_091[] = {
+    { 0x015A, 0x015B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_092[] = {
+    { 0x1E42, 0x1E43, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_093[] = {
+    { 0x015C, 0x015D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_094[] = {
+    { 0x1E40, 0x1E41, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_095[] = {
+    { 0x015E, 0x015F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_096[] = {
+    { 0x0464, 0x0465, 0x0000, 0x0000 },
+    { 0x1E7E, 0x1E7F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_097[] = {
+    { 0x0160, 0x0161, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_098[] = {
+    { 0x0466, 0x0467, 0x0000, 0x0000 },
+    { 0x1E7C, 0x1E7D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_099[] = {
+    { 0x0162, 0x0163, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_100[] = {
+    { 0x0460, 0x0461, 0x0000, 0x0000 },
+    { 0x1E7A, 0x1E7B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_101[] = {
+    { 0x0164, 0x0165, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_102[] = {
+    { 0x0462, 0x0463, 0x0000, 0x0000 },
+    { 0x1E78, 0x1E79, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_103[] = {
+    { 0x0166, 0x0167, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_104[] = {
+    { 0x046C, 0x046D, 0x0000, 0x0000 },
+    { 0x1E76, 0x1E77, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_105[] = {
+    { 0x0168, 0x0169, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_106[] = {
+    { 0x046E, 0x046F, 0x0000, 0x0000 },
+    { 0x1E74, 0x1E75, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_107[] = {
+    { 0x016A, 0x016B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_108[] = {
+    { 0x0468, 0x0469, 0x0000, 0x0000 },
+    { 0x1E72, 0x1E73, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_109[] = {
+    { 0x016C, 0x016D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_110[] = {
+    { 0x046A, 0x046B, 0x0000, 0x0000 },
+    { 0x1E70, 0x1E71, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_111[] = {
+    { 0x016E, 0x016F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_112[] = {
+    { 0x0474, 0x0475, 0x0000, 0x0000 },
+    { 0x1E6E, 0x1E6F, 0x0000, 0x0000 },
+    { 0x1F6F, 0x1F67, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_113[] = {
+    { 0x0170, 0x0171, 0x0000, 0x0000 },
+    { 0x1F6E, 0x1F66, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_114[] = {
+    { 0x0476, 0x0477, 0x0000, 0x0000 },
+    { 0x1E6C, 0x1E6D, 0x0000, 0x0000 },
+    { 0x1F6D, 0x1F65, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_115[] = {
+    { 0x0172, 0x0173, 0x0000, 0x0000 },
+    { 0x1F6C, 0x1F64, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_116[] = {
+    { 0x0470, 0x0471, 0x0000, 0x0000 },
+    { 0x1E6A, 0x1E6B, 0x0000, 0x0000 },
+    { 0x1F6B, 0x1F63, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_117[] = {
+    { 0x0174, 0x0175, 0x0000, 0x0000 },
+    { 0x1F6A, 0x1F62, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_118[] = {
+    { 0x0472, 0x0473, 0x0000, 0x0000 },
+    { 0x1E68, 0x1E69, 0x0000, 0x0000 },
+    { 0x1F69, 0x1F61, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_119[] = {
+    { 0x0176, 0x0177, 0x0000, 0x0000 },
+    { 0x1F68, 0x1F60, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_120[] = {
+    { 0x0179, 0x017A, 0x0000, 0x0000 },
+    { 0x047C, 0x047D, 0x0000, 0x0000 },
+    { 0x1E66, 0x1E67, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_121[] = {
+    { 0x0178, 0x00FF, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_122[] = {
+    { 0x017B, 0x017C, 0x0000, 0x0000 },
+    { 0x047E, 0x047F, 0x0000, 0x0000 },
+    { 0x1E64, 0x1E65, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_124[] = {
+    { 0x017D, 0x017E, 0x0000, 0x0000 },
+    { 0x0478, 0x0479, 0x0000, 0x0000 },
+    { 0x1E62, 0x1E63, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_126[] = {
+    { 0x017F, 0x0073, 0x0000, 0x0000 },
+    { 0x047A, 0x047B, 0x0000, 0x0000 },
+    { 0x1E60, 0x1E61, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_128[] = {
+    { 0x0181, 0x0253, 0x0000, 0x0000 },
+    { 0x1F9F, 0x1F27, 0x03B9, 0x0000 },
+    { 0x2CAC, 0x2CAD, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_129[] = {
+    { 0x1F9E, 0x1F26, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_130[] = {
+    { 0x0587, 0x0565, 0x0582, 0x0000 },
+    { 0x1F9D, 0x1F25, 0x03B9, 0x0000 },
+    { 0x2CAE, 0x2CAF, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_131[] = {
+    { 0x0182, 0x0183, 0x0000, 0x0000 },
+    { 0x1F9C, 0x1F24, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_132[] = {
+    { 0x0480, 0x0481, 0x0000, 0x0000 },
+    { 0x1E9A, 0x0061, 0x02BE, 0x0000 },
+    { 0x1F9B, 0x1F23, 0x03B9, 0x0000 },
+    { 0x2CA8, 0x2CA9, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_133[] = {
+    { 0x0184, 0x0185, 0x0000, 0x0000 },
+    { 0x0386, 0x03AC, 0x0000, 0x0000 },
+    { 0x1E9B, 0x1E61, 0x0000, 0x0000 },
+    { 0x1F9A, 0x1F22, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_134[] = {
+    { 0x0187, 0x0188, 0x0000, 0x0000 },
+    { 0x1E98, 0x0077, 0x030A, 0x0000 },
+    { 0x1F99, 0x1F21, 0x03B9, 0x0000 },
+    { 0x2CAA, 0x2CAB, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_135[] = {
+    { 0x0186, 0x0254, 0x0000, 0x0000 },
+    { 0x1E99, 0x0079, 0x030A, 0x0000 },
+    { 0x1F98, 0x1F20, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_136[] = {
+    { 0x0189, 0x0256, 0x0000, 0x0000 },
+    { 0x048C, 0x048D, 0x0000, 0x0000 },
+    { 0x1E96, 0x0068, 0x0331, 0x0000 },
+    { 0x1F97, 0x1F27, 0x03B9, 0x0000 },
+    { 0x2CA4, 0x2CA5, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_137[] = {
+    { 0x038A, 0x03AF, 0x0000, 0x0000 },
+    { 0x1E97, 0x0074, 0x0308, 0x0000 },
+    { 0x1F96, 0x1F26, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_138[] = {
+    { 0x018B, 0x018C, 0x0000, 0x0000 },
+    { 0x0389, 0x03AE, 0x0000, 0x0000 },
+    { 0x048E, 0x048F, 0x0000, 0x0000 },
+    { 0x1E94, 0x1E95, 0x0000, 0x0000 },
+    { 0x1F95, 0x1F25, 0x03B9, 0x0000 },
+    { 0x2CA6, 0x2CA7, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_139[] = {
+    { 0x018A, 0x0257, 0x0000, 0x0000 },
+    { 0x0388, 0x03AD, 0x0000, 0x0000 },
+    { 0x1F94, 0x1F24, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_140[] = {
+    { 0x038F, 0x03CE, 0x0000, 0x0000 },
+    { 0x1E92, 0x1E93, 0x0000, 0x0000 },
+    { 0x1F93, 0x1F23, 0x03B9, 0x0000 },
+    { 0x2CA0, 0x2CA1, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_141[] = {
+    { 0x038E, 0x03CD, 0x0000, 0x0000 },
+    { 0x1F92, 0x1F22, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_142[] = {
+    { 0x018F, 0x0259, 0x0000, 0x0000 },
+    { 0x048A, 0x048B, 0x0000, 0x0000 },
+    { 0x1E90, 0x1E91, 0x0000, 0x0000 },
+    { 0x1F91, 0x1F21, 0x03B9, 0x0000 },
+    { 0x2CA2, 0x2CA3, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_143[] = {
+    { 0x018E, 0x01DD, 0x0000, 0x0000 },
+    { 0x038C, 0x03CC, 0x0000, 0x0000 },
+    { 0x1F90, 0x1F20, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_144[] = {
+    { 0x0191, 0x0192, 0x0000, 0x0000 },
+    { 0x0393, 0x03B3, 0x0000, 0x0000 },
+    { 0x0494, 0x0495, 0x0000, 0x0000 },
+    { 0x1E8E, 0x1E8F, 0x0000, 0x0000 },
+    { 0x1F8F, 0x1F07, 0x03B9, 0x0000 },
+    { 0x2CBC, 0x2CBD, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_145[] = {
+    { 0x0190, 0x025B, 0x0000, 0x0000 },
+    { 0x0392, 0x03B2, 0x0000, 0x0000 },
+    { 0x1F8E, 0x1F06, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_146[] = {
+    { 0x0193, 0x0260, 0x0000, 0x0000 },
+    { 0x0391, 0x03B1, 0x0000, 0x0000 },
+    { 0x0496, 0x0497, 0x0000, 0x0000 },
+    { 0x1E8C, 0x1E8D, 0x0000, 0x0000 },
+    { 0x1F8D, 0x1F05, 0x03B9, 0x0000 },
+    { 0x24B6, 0x24D0, 0x0000, 0x0000 },
+    { 0x2CBE, 0x2CBF, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_147[] = {
+    { 0x0390, 0x03B9, 0x0308, 0x0301 },
+    { 0x1F8C, 0x1F04, 0x03B9, 0x0000 },
+    { 0x24B7, 0x24D1, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_148[] = {
+    { 0x0397, 0x03B7, 0x0000, 0x0000 },
+    { 0x0490, 0x0491, 0x0000, 0x0000 },
+    { 0x1E8A, 0x1E8B, 0x0000, 0x0000 },
+    { 0x1F8B, 0x1F03, 0x03B9, 0x0000 },
+    { 0x2CB8, 0x2CB9, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_149[] = {
+    { 0x0194, 0x0263, 0x0000, 0x0000 },
+    { 0x0396, 0x03B6, 0x0000, 0x0000 },
+    { 0x1F8A, 0x1F02, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_150[] = {
+    { 0x0197, 0x0268, 0x0000, 0x0000 },
+    { 0x0395, 0x03B5, 0x0000, 0x0000 },
+    { 0x0492, 0x0493, 0x0000, 0x0000 },
+    { 0x1E88, 0x1E89, 0x0000, 0x0000 },
+    { 0x1F89, 0x1F01, 0x03B9, 0x0000 },
+    { 0x2CBA, 0x2CBB, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_151[] = {
+    { 0x0196, 0x0269, 0x0000, 0x0000 },
+    { 0x0394, 0x03B4, 0x0000, 0x0000 },
+    { 0x1F88, 0x1F00, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_152[] = {
+    { 0x039B, 0x03BB, 0x0000, 0x0000 },
+    { 0x049C, 0x049D, 0x0000, 0x0000 },
+    { 0x1E86, 0x1E87, 0x0000, 0x0000 },
+    { 0x1F87, 0x1F07, 0x03B9, 0x0000 },
+    { 0x24BC, 0x24D6, 0x0000, 0x0000 },
+    { 0x2CB4, 0x2CB5, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_153[] = {
+    { 0x0198, 0x0199, 0x0000, 0x0000 },
+    { 0x039A, 0x03BA, 0x0000, 0x0000 },
+    { 0x1F86, 0x1F06, 0x03B9, 0x0000 },
+    { 0x24BD, 0x24D7, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_154[] = {
+    { 0x0399, 0x03B9, 0x0000, 0x0000 },
+    { 0x049E, 0x049F, 0x0000, 0x0000 },
+    { 0x1E84, 0x1E85, 0x0000, 0x0000 },
+    { 0x1F85, 0x1F05, 0x03B9, 0x0000 },
+    { 0x24BE, 0x24D8, 0x0000, 0x0000 },
+    { 0x2CB6, 0x2CB7, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_155[] = {
+    { 0x0398, 0x03B8, 0x0000, 0x0000 },
+    { 0x1F84, 0x1F04, 0x03B9, 0x0000 },
+    { 0x24BF, 0x24D9, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_156[] = {
+    { 0x019D, 0x0272, 0x0000, 0x0000 },
+    { 0x039F, 0x03BF, 0x0000, 0x0000 },
+    { 0x0498, 0x0499, 0x0000, 0x0000 },
+    { 0x1E82, 0x1E83, 0x0000, 0x0000 },
+    { 0x1F83, 0x1F03, 0x03B9, 0x0000 },
+    { 0x24B8, 0x24D2, 0x0000, 0x0000 },
+    { 0x2CB0, 0x2CB1, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_157[] = {
+    { 0x019C, 0x026F, 0x0000, 0x0000 },
+    { 0x039E, 0x03BE, 0x0000, 0x0000 },
+    { 0x1F82, 0x1F02, 0x03B9, 0x0000 },
+    { 0x24B9, 0x24D3, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_158[] = {
+    { 0x019F, 0x0275, 0x0000, 0x0000 },
+    { 0x039D, 0x03BD, 0x0000, 0x0000 },
+    { 0x049A, 0x049B, 0x0000, 0x0000 },
+    { 0x1E80, 0x1E81, 0x0000, 0x0000 },
+    { 0x1F81, 0x1F01, 0x03B9, 0x0000 },
+    { 0x24BA, 0x24D4, 0x0000, 0x0000 },
+    { 0x2CB2, 0x2CB3, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_159[] = {
+    { 0x039C, 0x03BC, 0x0000, 0x0000 },
+    { 0x1F80, 0x1F00, 0x03B9, 0x0000 },
+    { 0x24BB, 0x24D5, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_160[] = {
+    { 0x03A3, 0x03C3, 0x0000, 0x0000 },
+    { 0x04A4, 0x04A5, 0x0000, 0x0000 },
+    { 0x10B0, 0x2D10, 0x0000, 0x0000 },
+    { 0x1EBE, 0x1EBF, 0x0000, 0x0000 },
+    { 0x2C8C, 0x2C8D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_161[] = {
+    { 0x01A0, 0x01A1, 0x0000, 0x0000 },
+    { 0x10B1, 0x2D11, 0x0000, 0x0000 },
+    { 0x1FBE, 0x03B9, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_162[] = {
+    { 0x03A1, 0x03C1, 0x0000, 0x0000 },
+    { 0x04A6, 0x04A7, 0x0000, 0x0000 },
+    { 0x10B2, 0x2D12, 0x0000, 0x0000 },
+    { 0x1EBC, 0x1EBD, 0x0000, 0x0000 },
+    { 0x2C8E, 0x2C8F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_163[] = {
+    { 0x01A2, 0x01A3, 0x0000, 0x0000 },
+    { 0x03A0, 0x03C0, 0x0000, 0x0000 },
+    { 0x10B3, 0x2D13, 0x0000, 0x0000 },
+    { 0x1FBC, 0x03B1, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_164[] = {
+    { 0x03A7, 0x03C7, 0x0000, 0x0000 },
+    { 0x04A0, 0x04A1, 0x0000, 0x0000 },
+    { 0x10B4, 0x2D14, 0x0000, 0x0000 },
+    { 0x1EBA, 0x1EBB, 0x0000, 0x0000 },
+    { 0x1FBB, 0x1F71, 0x0000, 0x0000 },
+    { 0x2C88, 0x2C89, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_165[] = {
+    { 0x01A4, 0x01A5, 0x0000, 0x0000 },
+    { 0x03A6, 0x03C6, 0x0000, 0x0000 },
+    { 0x10B5, 0x2D15, 0x0000, 0x0000 },
+    { 0x1FBA, 0x1F70, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_166[] = {
+    { 0x01A7, 0x01A8, 0x0000, 0x0000 },
+    { 0x03A5, 0x03C5, 0x0000, 0x0000 },
+    { 0x04A2, 0x04A3, 0x0000, 0x0000 },
+    { 0x10B6, 0x2D16, 0x0000, 0x0000 },
+    { 0x1EB8, 0x1EB9, 0x0000, 0x0000 },
+    { 0x1FB9, 0x1FB1, 0x0000, 0x0000 },
+    { 0x2C8A, 0x2C8B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_167[] = {
+    { 0x01A6, 0x0280, 0x0000, 0x0000 },
+    { 0x03A4, 0x03C4, 0x0000, 0x0000 },
+    { 0x10B7, 0x2D17, 0x0000, 0x0000 },
+    { 0x1FB8, 0x1FB0, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_168[] = {
+    { 0x01A9, 0x0283, 0x0000, 0x0000 },
+    { 0x03AB, 0x03CB, 0x0000, 0x0000 },
+    { 0x04AC, 0x04AD, 0x0000, 0x0000 },
+    { 0x10B8, 0x2D18, 0x0000, 0x0000 },
+    { 0x1EB6, 0x1EB7, 0x0000, 0x0000 },
+    { 0x1FB7, 0x03B1, 0x0342, 0x03B9 },
+    { 0x2C84, 0x2C85, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_169[] = {
+    { 0x03AA, 0x03CA, 0x0000, 0x0000 },
+    { 0x10B9, 0x2D19, 0x0000, 0x0000 },
+    { 0x1FB6, 0x03B1, 0x0342, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_170[] = {
+    { 0x03A9, 0x03C9, 0x0000, 0x0000 },
+    { 0x04AE, 0x04AF, 0x0000, 0x0000 },
+    { 0x10BA, 0x2D1A, 0x0000, 0x0000 },
+    { 0x1EB4, 0x1EB5, 0x0000, 0x0000 },
+    { 0x2C86, 0x2C87, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_171[] = {
+    { 0x03A8, 0x03C8, 0x0000, 0x0000 },
+    { 0x10BB, 0x2D1B, 0x0000, 0x0000 },
+    { 0x1FB4, 0x03AC, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_172[] = {
+    { 0x04A8, 0x04A9, 0x0000, 0x0000 },
+    { 0x10BC, 0x2D1C, 0x0000, 0x0000 },
+    { 0x1EB2, 0x1EB3, 0x0000, 0x0000 },
+    { 0x1FB3, 0x03B1, 0x03B9, 0x0000 },
+    { 0x2C80, 0x2C81, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_173[] = {
+    { 0x01AC, 0x01AD, 0x0000, 0x0000 },
+    { 0x10BD, 0x2D1D, 0x0000, 0x0000 },
+    { 0x1FB2, 0x1F70, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_174[] = {
+    { 0x01AF, 0x01B0, 0x0000, 0x0000 },
+    { 0x04AA, 0x04AB, 0x0000, 0x0000 },
+    { 0x10BE, 0x2D1E, 0x0000, 0x0000 },
+    { 0x1EB0, 0x1EB1, 0x0000, 0x0000 },
+    { 0x2C82, 0x2C83, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_175[] = {
+    { 0x01AE, 0x0288, 0x0000, 0x0000 },
+    { 0x10BF, 0x2D1F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_176[] = {
+    { 0x01B1, 0x028A, 0x0000, 0x0000 },
+    { 0x04B4, 0x04B5, 0x0000, 0x0000 },
+    { 0x10A0, 0x2D00, 0x0000, 0x0000 },
+    { 0x1EAE, 0x1EAF, 0x0000, 0x0000 },
+    { 0x1FAF, 0x1F67, 0x03B9, 0x0000 },
+    { 0x2C9C, 0x2C9D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_177[] = {
+    { 0x10A1, 0x2D01, 0x0000, 0x0000 },
+    { 0x1FAE, 0x1F66, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_178[] = {
+    { 0x01B3, 0x01B4, 0x0000, 0x0000 },
+    { 0x04B6, 0x04B7, 0x0000, 0x0000 },
+    { 0x10A2, 0x2D02, 0x0000, 0x0000 },
+    { 0x1EAC, 0x1EAD, 0x0000, 0x0000 },
+    { 0x1FAD, 0x1F65, 0x03B9, 0x0000 },
+    { 0x2C9E, 0x2C9F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_179[] = {
+    { 0x01B2, 0x028B, 0x0000, 0x0000 },
+    { 0x03B0, 0x03C5, 0x0308, 0x0301 },
+    { 0x10A3, 0x2D03, 0x0000, 0x0000 },
+    { 0x1FAC, 0x1F64, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_180[] = {
+    { 0x01B5, 0x01B6, 0x0000, 0x0000 },
+    { 0x04B0, 0x04B1, 0x0000, 0x0000 },
+    { 0x10A4, 0x2D04, 0x0000, 0x0000 },
+    { 0x1EAA, 0x1EAB, 0x0000, 0x0000 },
+    { 0x1FAB, 0x1F63, 0x03B9, 0x0000 },
+    { 0x2C98, 0x2C99, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_181[] = {
+    { 0x00B5, 0x03BC, 0x0000, 0x0000 },
+    { 0x10A5, 0x2D05, 0x0000, 0x0000 },
+    { 0x1FAA, 0x1F62, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_182[] = {
+    { 0x01B7, 0x0292, 0x0000, 0x0000 },
+    { 0x04B2, 0x04B3, 0x0000, 0x0000 },
+    { 0x10A6, 0x2D06, 0x0000, 0x0000 },
+    { 0x1EA8, 0x1EA9, 0x0000, 0x0000 },
+    { 0x1FA9, 0x1F61, 0x03B9, 0x0000 },
+    { 0x2C9A, 0x2C9B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_183[] = {
+    { 0x10A7, 0x2D07, 0x0000, 0x0000 },
+    { 0x1FA8, 0x1F60, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_184[] = {
+    { 0x04BC, 0x04BD, 0x0000, 0x0000 },
+    { 0x10A8, 0x2D08, 0x0000, 0x0000 },
+    { 0x1EA6, 0x1EA7, 0x0000, 0x0000 },
+    { 0x1FA7, 0x1F67, 0x03B9, 0x0000 },
+    { 0x2C94, 0x2C95, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_185[] = {
+    { 0x01B8, 0x01B9, 0x0000, 0x0000 },
+    { 0x10A9, 0x2D09, 0x0000, 0x0000 },
+    { 0x1FA6, 0x1F66, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_186[] = {
+    { 0x04BE, 0x04BF, 0x0000, 0x0000 },
+    { 0x10AA, 0x2D0A, 0x0000, 0x0000 },
+    { 0x1EA4, 0x1EA5, 0x0000, 0x0000 },
+    { 0x1FA5, 0x1F65, 0x03B9, 0x0000 },
+    { 0x2C96, 0x2C97, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_187[] = {
+    { 0x10AB, 0x2D0B, 0x0000, 0x0000 },
+    { 0x1FA4, 0x1F64, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_188[] = {
+    { 0x04B8, 0x04B9, 0x0000, 0x0000 },
+    { 0x10AC, 0x2D0C, 0x0000, 0x0000 },
+    { 0x1EA2, 0x1EA3, 0x0000, 0x0000 },
+    { 0x1FA3, 0x1F63, 0x03B9, 0x0000 },
+    { 0x2C90, 0x2C91, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_189[] = {
+    { 0x01BC, 0x01BD, 0x0000, 0x0000 },
+    { 0x10AD, 0x2D0D, 0x0000, 0x0000 },
+    { 0x1FA2, 0x1F62, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_190[] = {
+    { 0x04BA, 0x04BB, 0x0000, 0x0000 },
+    { 0x10AE, 0x2D0E, 0x0000, 0x0000 },
+    { 0x1EA0, 0x1EA1, 0x0000, 0x0000 },
+    { 0x1FA1, 0x1F61, 0x03B9, 0x0000 },
+    { 0x2C92, 0x2C93, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_191[] = {
+    { 0x10AF, 0x2D0F, 0x0000, 0x0000 },
+    { 0x1FA0, 0x1F60, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_192[] = {
+    { 0x00C0, 0x00E0, 0x0000, 0x0000 },
+    { 0x1EDE, 0x1EDF, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_193[] = {
+    { 0x00C1, 0x00E1, 0x0000, 0x0000 },
+    { 0x03C2, 0x03C3, 0x0000, 0x0000 },
+    { 0x04C5, 0x04C6, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_194[] = {
+    { 0x00C2, 0x00E2, 0x0000, 0x0000 },
+    { 0x1EDC, 0x1EDD, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_195[] = {
+    { 0x00C3, 0x00E3, 0x0000, 0x0000 },
+    { 0x04C7, 0x04C8, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_196[] = {
+    { 0x00C4, 0x00E4, 0x0000, 0x0000 },
+    { 0x01C5, 0x01C6, 0x0000, 0x0000 },
+    { 0x1EDA, 0x1EDB, 0x0000, 0x0000 },
+    { 0x1FDB, 0x1F77, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_197[] = {
+    { 0x00C5, 0x00E5, 0x0000, 0x0000 },
+    { 0x01C4, 0x01C6, 0x0000, 0x0000 },
+    { 0x04C1, 0x04C2, 0x0000, 0x0000 },
+    { 0x1FDA, 0x1F76, 0x0000, 0x0000 },
+    { 0xFF3A, 0xFF5A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_198[] = {
+    { 0x00C6, 0x00E6, 0x0000, 0x0000 },
+    { 0x01C7, 0x01C9, 0x0000, 0x0000 },
+    { 0x1ED8, 0x1ED9, 0x0000, 0x0000 },
+    { 0x1FD9, 0x1FD1, 0x0000, 0x0000 },
+    { 0xFF39, 0xFF59, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_199[] = {
+    { 0x00C7, 0x00E7, 0x0000, 0x0000 },
+    { 0x04C3, 0x04C4, 0x0000, 0x0000 },
+    { 0x1FD8, 0x1FD0, 0x0000, 0x0000 },
+    { 0xFF38, 0xFF58, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_200[] = {
+    { 0x00C8, 0x00E8, 0x0000, 0x0000 },
+    { 0x1ED6, 0x1ED7, 0x0000, 0x0000 },
+    { 0x1FD7, 0x03B9, 0x0308, 0x0342 },
+    { 0xFF37, 0xFF57, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_201[] = {
+    { 0x00C9, 0x00E9, 0x0000, 0x0000 },
+    { 0x01C8, 0x01C9, 0x0000, 0x0000 },
+    { 0x04CD, 0x04CE, 0x0000, 0x0000 },
+    { 0x1FD6, 0x03B9, 0x0342, 0x0000 },
+    { 0xFF36, 0xFF56, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_202[] = {
+    { 0x00CA, 0x00EA, 0x0000, 0x0000 },
+    { 0x01CB, 0x01CC, 0x0000, 0x0000 },
+    { 0x1ED4, 0x1ED5, 0x0000, 0x0000 },
+    { 0xFF35, 0xFF55, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_203[] = {
+    { 0x00CB, 0x00EB, 0x0000, 0x0000 },
+    { 0x01CA, 0x01CC, 0x0000, 0x0000 },
+    { 0xFF34, 0xFF54, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_204[] = {
+    { 0x00CC, 0x00EC, 0x0000, 0x0000 },
+    { 0x01CD, 0x01CE, 0x0000, 0x0000 },
+    { 0x1ED2, 0x1ED3, 0x0000, 0x0000 },
+    { 0x1FD3, 0x03B9, 0x0308, 0x0301 },
+    { 0x2CE0, 0x2CE1, 0x0000, 0x0000 },
+    { 0xFF33, 0xFF53, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_205[] = {
+    { 0x00CD, 0x00ED, 0x0000, 0x0000 },
+    { 0x04C9, 0x04CA, 0x0000, 0x0000 },
+    { 0x1FD2, 0x03B9, 0x0308, 0x0300 },
+    { 0xFF32, 0xFF52, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_206[] = {
+    { 0x00CE, 0x00EE, 0x0000, 0x0000 },
+    { 0x01CF, 0x01D0, 0x0000, 0x0000 },
+    { 0x1ED0, 0x1ED1, 0x0000, 0x0000 },
+    { 0x2CE2, 0x2CE3, 0x0000, 0x0000 },
+    { 0xFF31, 0xFF51, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_207[] = {
+    { 0x00CF, 0x00EF, 0x0000, 0x0000 },
+    { 0x04CB, 0x04CC, 0x0000, 0x0000 },
+    { 0xFF30, 0xFF50, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_208[] = {
+    { 0x00D0, 0x00F0, 0x0000, 0x0000 },
+    { 0x01D1, 0x01D2, 0x0000, 0x0000 },
+    { 0x04D4, 0x04D5, 0x0000, 0x0000 },
+    { 0x10C0, 0x2D20, 0x0000, 0x0000 },
+    { 0x1ECE, 0x1ECF, 0x0000, 0x0000 },
+    { 0xFF2F, 0xFF4F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_209[] = {
+    { 0x00D1, 0x00F1, 0x0000, 0x0000 },
+    { 0x10C1, 0x2D21, 0x0000, 0x0000 },
+    { 0xFF2E, 0xFF4E, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_210[] = {
+    { 0x00D2, 0x00F2, 0x0000, 0x0000 },
+    { 0x01D3, 0x01D4, 0x0000, 0x0000 },
+    { 0x03D1, 0x03B8, 0x0000, 0x0000 },
+    { 0x04D6, 0x04D7, 0x0000, 0x0000 },
+    { 0x10C2, 0x2D22, 0x0000, 0x0000 },
+    { 0x1ECC, 0x1ECD, 0x0000, 0x0000 },
+    { 0xFF2D, 0xFF4D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_211[] = {
+    { 0x00D3, 0x00F3, 0x0000, 0x0000 },
+    { 0x03D0, 0x03B2, 0x0000, 0x0000 },
+    { 0x10C3, 0x2D23, 0x0000, 0x0000 },
+    { 0x1FCC, 0x03B7, 0x03B9, 0x0000 },
+    { 0xFF2C, 0xFF4C, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_212[] = {
+    { 0x00D4, 0x00F4, 0x0000, 0x0000 },
+    { 0x01D5, 0x01D6, 0x0000, 0x0000 },
+    { 0x04D0, 0x04D1, 0x0000, 0x0000 },
+    { 0x10C4, 0x2D24, 0x0000, 0x0000 },
+    { 0x1ECA, 0x1ECB, 0x0000, 0x0000 },
+    { 0x1FCB, 0x1F75, 0x0000, 0x0000 },
+    { 0xFF2B, 0xFF4B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_213[] = {
+    { 0x00D5, 0x00F5, 0x0000, 0x0000 },
+    { 0x03D6, 0x03C0, 0x0000, 0x0000 },
+    { 0x10C5, 0x2D25, 0x0000, 0x0000 },
+    { 0x1FCA, 0x1F74, 0x0000, 0x0000 },
+    { 0xFF2A, 0xFF4A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_214[] = {
+    { 0x00D6, 0x00F6, 0x0000, 0x0000 },
+    { 0x01D7, 0x01D8, 0x0000, 0x0000 },
+    { 0x03D5, 0x03C6, 0x0000, 0x0000 },
+    { 0x04D2, 0x04D3, 0x0000, 0x0000 },
+    { 0x1EC8, 0x1EC9, 0x0000, 0x0000 },
+    { 0x1FC9, 0x1F73, 0x0000, 0x0000 },
+    { 0xFF29, 0xFF49, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_215[] = {
+    { 0x1FC8, 0x1F72, 0x0000, 0x0000 },
+    { 0xFF28, 0xFF48, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_216[] = {
+    { 0x00D8, 0x00F8, 0x0000, 0x0000 },
+    { 0x01D9, 0x01DA, 0x0000, 0x0000 },
+    { 0x04DC, 0x04DD, 0x0000, 0x0000 },
+    { 0x1EC6, 0x1EC7, 0x0000, 0x0000 },
+    { 0x1FC7, 0x03B7, 0x0342, 0x03B9 },
+    { 0xFF27, 0xFF47, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_217[] = {
+    { 0x00D9, 0x00F9, 0x0000, 0x0000 },
+    { 0x03DA, 0x03DB, 0x0000, 0x0000 },
+    { 0x1FC6, 0x03B7, 0x0342, 0x0000 },
+    { 0xFF26, 0xFF46, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_218[] = {
+    { 0x00DA, 0x00FA, 0x0000, 0x0000 },
+    { 0x01DB, 0x01DC, 0x0000, 0x0000 },
+    { 0x04DE, 0x04DF, 0x0000, 0x0000 },
+    { 0x1EC4, 0x1EC5, 0x0000, 0x0000 },
+    { 0xFF25, 0xFF45, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_219[] = {
+    { 0x00DB, 0x00FB, 0x0000, 0x0000 },
+    { 0x03D8, 0x03D9, 0x0000, 0x0000 },
+    { 0x1FC4, 0x03AE, 0x03B9, 0x0000 },
+    { 0xFF24, 0xFF44, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_220[] = {
+    { 0x00DC, 0x00FC, 0x0000, 0x0000 },
+    { 0x04D8, 0x04D9, 0x0000, 0x0000 },
+    { 0x1EC2, 0x1EC3, 0x0000, 0x0000 },
+    { 0x1FC3, 0x03B7, 0x03B9, 0x0000 },
+    { 0xFF23, 0xFF43, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_221[] = {
+    { 0x00DD, 0x00FD, 0x0000, 0x0000 },
+    { 0x03DE, 0x03DF, 0x0000, 0x0000 },
+    { 0x1FC2, 0x1F74, 0x03B9, 0x0000 },
+    { 0xFF22, 0xFF42, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_222[] = {
+    { 0x00DE, 0x00FE, 0x0000, 0x0000 },
+    { 0x04DA, 0x04DB, 0x0000, 0x0000 },
+    { 0x1EC0, 0x1EC1, 0x0000, 0x0000 },
+    { 0xFF21, 0xFF41, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_223[] = {
+    { 0x00DF, 0x0073, 0x0073, 0x0000 },
+    { 0x01DE, 0x01DF, 0x0000, 0x0000 },
+    { 0x03DC, 0x03DD, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_224[] = {
+    { 0x04E4, 0x04E5, 0x0000, 0x0000 },
+    { 0x24C4, 0x24DE, 0x0000, 0x0000 },
+    { 0x2CCC, 0x2CCD, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_225[] = {
+    { 0x01E0, 0x01E1, 0x0000, 0x0000 },
+    { 0x03E2, 0x03E3, 0x0000, 0x0000 },
+    { 0x24C5, 0x24DF, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_226[] = {
+    { 0x04E6, 0x04E7, 0x0000, 0x0000 },
+    { 0x24C6, 0x24E0, 0x0000, 0x0000 },
+    { 0x2CCE, 0x2CCF, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_227[] = {
+    { 0x01E2, 0x01E3, 0x0000, 0x0000 },
+    { 0x03E0, 0x03E1, 0x0000, 0x0000 },
+    { 0x1FFC, 0x03C9, 0x03B9, 0x0000 },
+    { 0x24C7, 0x24E1, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_228[] = {
+    { 0x04E0, 0x04E1, 0x0000, 0x0000 },
+    { 0x1FFB, 0x1F7D, 0x0000, 0x0000 },
+    { 0x24C0, 0x24DA, 0x0000, 0x0000 },
+    { 0x2CC8, 0x2CC9, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_229[] = {
+    { 0x01E4, 0x01E5, 0x0000, 0x0000 },
+    { 0x03E6, 0x03E7, 0x0000, 0x0000 },
+    { 0x1FFA, 0x1F7C, 0x0000, 0x0000 },
+    { 0x24C1, 0x24DB, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_230[] = {
+    { 0x04E2, 0x04E3, 0x0000, 0x0000 },
+    { 0x1EF8, 0x1EF9, 0x0000, 0x0000 },
+    { 0x1FF9, 0x1F79, 0x0000, 0x0000 },
+    { 0x24C2, 0x24DC, 0x0000, 0x0000 },
+    { 0x2CCA, 0x2CCB, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_231[] = {
+    { 0x01E6, 0x01E7, 0x0000, 0x0000 },
+    { 0x03E4, 0x03E5, 0x0000, 0x0000 },
+    { 0x1FF8, 0x1F78, 0x0000, 0x0000 },
+    { 0x24C3, 0x24DD, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_232[] = {
+    { 0x04EC, 0x04ED, 0x0000, 0x0000 },
+    { 0x1EF6, 0x1EF7, 0x0000, 0x0000 },
+    { 0x1FF7, 0x03C9, 0x0342, 0x03B9 },
+    { 0x24CC, 0x24E6, 0x0000, 0x0000 },
+    { 0x2CC4, 0x2CC5, 0x0000, 0x0000 },
+    { 0xFB13, 0x0574, 0x0576, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_233[] = {
+    { 0x01E8, 0x01E9, 0x0000, 0x0000 },
+    { 0x03EA, 0x03EB, 0x0000, 0x0000 },
+    { 0x1FF6, 0x03C9, 0x0342, 0x0000 },
+    { 0x24CD, 0x24E7, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_234[] = {
+    { 0x04EE, 0x04EF, 0x0000, 0x0000 },
+    { 0x1EF4, 0x1EF5, 0x0000, 0x0000 },
+    { 0x24CE, 0x24E8, 0x0000, 0x0000 },
+    { 0x2CC6, 0x2CC7, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_235[] = {
+    { 0x01EA, 0x01EB, 0x0000, 0x0000 },
+    { 0x03E8, 0x03E9, 0x0000, 0x0000 },
+    { 0x1FF4, 0x03CE, 0x03B9, 0x0000 },
+    { 0x24CF, 0x24E9, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_236[] = {
+    { 0x04E8, 0x04E9, 0x0000, 0x0000 },
+    { 0x1EF2, 0x1EF3, 0x0000, 0x0000 },
+    { 0x1FF3, 0x03C9, 0x03B9, 0x0000 },
+    { 0x24C8, 0x24E2, 0x0000, 0x0000 },
+    { 0x2CC0, 0x2CC1, 0x0000, 0x0000 },
+    { 0xFB17, 0x0574, 0x056D, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_237[] = {
+    { 0x01EC, 0x01ED, 0x0000, 0x0000 },
+    { 0x03EE, 0x03EF, 0x0000, 0x0000 },
+    { 0x1FF2, 0x1F7C, 0x03B9, 0x0000 },
+    { 0x24C9, 0x24E3, 0x0000, 0x0000 },
+    { 0xFB16, 0x057E, 0x0576, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_238[] = {
+    { 0x04EA, 0x04EB, 0x0000, 0x0000 },
+    { 0x1EF0, 0x1EF1, 0x0000, 0x0000 },
+    { 0x24CA, 0x24E4, 0x0000, 0x0000 },
+    { 0x2CC2, 0x2CC3, 0x0000, 0x0000 },
+    { 0xFB15, 0x0574, 0x056B, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_239[] = {
+    { 0x01EE, 0x01EF, 0x0000, 0x0000 },
+    { 0x03EC, 0x03ED, 0x0000, 0x0000 },
+    { 0x24CB, 0x24E5, 0x0000, 0x0000 },
+    { 0xFB14, 0x0574, 0x0565, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_240[] = {
+    { 0x01F1, 0x01F3, 0x0000, 0x0000 },
+    { 0x04F4, 0x04F5, 0x0000, 0x0000 },
+    { 0x1EEE, 0x1EEF, 0x0000, 0x0000 },
+    { 0x2CDC, 0x2CDD, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_241[] = {
+    { 0x01F0, 0x006A, 0x030C, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_242[] = {
+    { 0x03F1, 0x03C1, 0x0000, 0x0000 },
+    { 0x04F6, 0x04F7, 0x0000, 0x0000 },
+    { 0x1EEC, 0x1EED, 0x0000, 0x0000 },
+    { 0x2CDE, 0x2CDF, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_243[] = {
+    { 0x01F2, 0x01F3, 0x0000, 0x0000 },
+    { 0x03F0, 0x03BA, 0x0000, 0x0000 },
+    { 0x1FEC, 0x1FE5, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_244[] = {
+    { 0x03F7, 0x03F8, 0x0000, 0x0000 },
+    { 0x04F0, 0x04F1, 0x0000, 0x0000 },
+    { 0x1EEA, 0x1EEB, 0x0000, 0x0000 },
+    { 0x1FEB, 0x1F7B, 0x0000, 0x0000 },
+    { 0x2CD8, 0x2CD9, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_245[] = {
+    { 0x01F4, 0x01F5, 0x0000, 0x0000 },
+    { 0x1FEA, 0x1F7A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_246[] = {
+    { 0x01F7, 0x01BF, 0x0000, 0x0000 },
+    { 0x03F5, 0x03B5, 0x0000, 0x0000 },
+    { 0x04F2, 0x04F3, 0x0000, 0x0000 },
+    { 0x1EE8, 0x1EE9, 0x0000, 0x0000 },
+    { 0x1FE9, 0x1FE1, 0x0000, 0x0000 },
+    { 0x2CDA, 0x2CDB, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_247[] = {
+    { 0x01F6, 0x0195, 0x0000, 0x0000 },
+    { 0x03F4, 0x03B8, 0x0000, 0x0000 },
+    { 0x1FE8, 0x1FE0, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_248[] = {
+    { 0x1EE6, 0x1EE7, 0x0000, 0x0000 },
+    { 0x1FE7, 0x03C5, 0x0308, 0x0342 },
+    { 0x2CD4, 0x2CD5, 0x0000, 0x0000 },
+    { 0xFB03, 0x0066, 0x0066, 0x0069 }
+};
+
+static const CaseFoldMapping case_fold_249[] = {
+    { 0x01F8, 0x01F9, 0x0000, 0x0000 },
+    { 0x03FA, 0x03FB, 0x0000, 0x0000 },
+    { 0x1FE6, 0x03C5, 0x0342, 0x0000 },
+    { 0xFB02, 0x0066, 0x006C, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_250[] = {
+    { 0x03F9, 0x03F2, 0x0000, 0x0000 },
+    { 0x1EE4, 0x1EE5, 0x0000, 0x0000 },
+    { 0x2CD6, 0x2CD7, 0x0000, 0x0000 },
+    { 0xFB01, 0x0066, 0x0069, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_251[] = {
+    { 0x01FA, 0x01FB, 0x0000, 0x0000 },
+    { 0x1FE4, 0x03C1, 0x0313, 0x0000 },
+    { 0xFB00, 0x0066, 0x0066, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_252[] = {
+    { 0x04F8, 0x04F9, 0x0000, 0x0000 },
+    { 0x1EE2, 0x1EE3, 0x0000, 0x0000 },
+    { 0x1FE3, 0x03C5, 0x0308, 0x0301 },
+    { 0x2CD0, 0x2CD1, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_253[] = {
+    { 0x01FC, 0x01FD, 0x0000, 0x0000 },
+    { 0x1FE2, 0x03C5, 0x0308, 0x0300 },
+    { 0xFB06, 0x0073, 0x0074, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_254[] = {
+    { 0x1EE0, 0x1EE1, 0x0000, 0x0000 },
+    { 0x2CD2, 0x2CD3, 0x0000, 0x0000 },
+    { 0xFB05, 0x0073, 0x0074, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_255[] = {
+    { 0x01FE, 0x01FF, 0x0000, 0x0000 },
+    { 0xFB04, 0x0066, 0x0066, 0x006C }
+};
+
+
+static const CaseFoldHashBucket case_fold_hash[256] = {
+    { __PHYSFS_ARRAYLEN(case_fold_000), case_fold_000 },
+    { __PHYSFS_ARRAYLEN(case_fold_001), case_fold_001 },
+    { __PHYSFS_ARRAYLEN(case_fold_002), case_fold_002 },
+    { __PHYSFS_ARRAYLEN(case_fold_003), case_fold_003 },
+    { __PHYSFS_ARRAYLEN(case_fold_004), case_fold_004 },
+    { __PHYSFS_ARRAYLEN(case_fold_005), case_fold_005 },
+    { __PHYSFS_ARRAYLEN(case_fold_006), case_fold_006 },
+    { __PHYSFS_ARRAYLEN(case_fold_007), case_fold_007 },
+    { __PHYSFS_ARRAYLEN(case_fold_008), case_fold_008 },
+    { __PHYSFS_ARRAYLEN(case_fold_009), case_fold_009 },
+    { __PHYSFS_ARRAYLEN(case_fold_010), case_fold_010 },
+    { __PHYSFS_ARRAYLEN(case_fold_011), case_fold_011 },
+    { __PHYSFS_ARRAYLEN(case_fold_012), case_fold_012 },
+    { __PHYSFS_ARRAYLEN(case_fold_013), case_fold_013 },
+    { __PHYSFS_ARRAYLEN(case_fold_014), case_fold_014 },
+    { __PHYSFS_ARRAYLEN(case_fold_015), case_fold_015 },
+    { __PHYSFS_ARRAYLEN(case_fold_016), case_fold_016 },
+    { __PHYSFS_ARRAYLEN(case_fold_017), case_fold_017 },
+    { __PHYSFS_ARRAYLEN(case_fold_018), case_fold_018 },
+    { __PHYSFS_ARRAYLEN(case_fold_019), case_fold_019 },
+    { __PHYSFS_ARRAYLEN(case_fold_020), case_fold_020 },
+    { __PHYSFS_ARRAYLEN(case_fold_021), case_fold_021 },
+    { __PHYSFS_ARRAYLEN(case_fold_022), case_fold_022 },
+    { __PHYSFS_ARRAYLEN(case_fold_023), case_fold_023 },
+    { __PHYSFS_ARRAYLEN(case_fold_024), case_fold_024 },
+    { __PHYSFS_ARRAYLEN(case_fold_025), case_fold_025 },
+    { __PHYSFS_ARRAYLEN(case_fold_026), case_fold_026 },
+    { __PHYSFS_ARRAYLEN(case_fold_027), case_fold_027 },
+    { __PHYSFS_ARRAYLEN(case_fold_028), case_fold_028 },
+    { __PHYSFS_ARRAYLEN(case_fold_029), case_fold_029 },
+    { __PHYSFS_ARRAYLEN(case_fold_030), case_fold_030 },
+    { __PHYSFS_ARRAYLEN(case_fold_031), case_fold_031 },
+    { __PHYSFS_ARRAYLEN(case_fold_032), case_fold_032 },
+    { __PHYSFS_ARRAYLEN(case_fold_033), case_fold_033 },
+    { __PHYSFS_ARRAYLEN(case_fold_034), case_fold_034 },
+    { __PHYSFS_ARRAYLEN(case_fold_035), case_fold_035 },
+    { __PHYSFS_ARRAYLEN(case_fold_036), case_fold_036 },
+    { __PHYSFS_ARRAYLEN(case_fold_037), case_fold_037 },
+    { __PHYSFS_ARRAYLEN(case_fold_038), case_fold_038 },
+    { __PHYSFS_ARRAYLEN(case_fold_039), case_fold_039 },
+    { __PHYSFS_ARRAYLEN(case_fold_040), case_fold_040 },
+    { __PHYSFS_ARRAYLEN(case_fold_041), case_fold_041 },
+    { __PHYSFS_ARRAYLEN(case_fold_042), case_fold_042 },
+    { __PHYSFS_ARRAYLEN(case_fold_043), case_fold_043 },
+    { __PHYSFS_ARRAYLEN(case_fold_044), case_fold_044 },
+    { __PHYSFS_ARRAYLEN(case_fold_045), case_fold_045 },
+    { __PHYSFS_ARRAYLEN(case_fold_046), case_fold_046 },
+    { __PHYSFS_ARRAYLEN(case_fold_047), case_fold_047 },
+    { __PHYSFS_ARRAYLEN(case_fold_048), case_fold_048 },
+    { __PHYSFS_ARRAYLEN(case_fold_049), case_fold_049 },
+    { __PHYSFS_ARRAYLEN(case_fold_050), case_fold_050 },
+    { __PHYSFS_ARRAYLEN(case_fold_051), case_fold_051 },
+    { __PHYSFS_ARRAYLEN(case_fold_052), case_fold_052 },
+    { __PHYSFS_ARRAYLEN(case_fold_053), case_fold_053 },
+    { __PHYSFS_ARRAYLEN(case_fold_054), case_fold_054 },
+    { __PHYSFS_ARRAYLEN(case_fold_055), case_fold_055 },
+    { __PHYSFS_ARRAYLEN(case_fold_056), case_fold_056 },
+    { __PHYSFS_ARRAYLEN(case_fold_057), case_fold_057 },
+    { __PHYSFS_ARRAYLEN(case_fold_058), case_fold_058 },
+    { __PHYSFS_ARRAYLEN(case_fold_059), case_fold_059 },
+    { __PHYSFS_ARRAYLEN(case_fold_060), case_fold_060 },
+    { __PHYSFS_ARRAYLEN(case_fold_061), case_fold_061 },
+    { __PHYSFS_ARRAYLEN(case_fold_062), case_fold_062 },
+    { __PHYSFS_ARRAYLEN(case_fold_063), case_fold_063 },
+    { __PHYSFS_ARRAYLEN(case_fold_064), case_fold_064 },
+    { __PHYSFS_ARRAYLEN(case_fold_065), case_fold_065 },
+    { __PHYSFS_ARRAYLEN(case_fold_066), case_fold_066 },
+    { __PHYSFS_ARRAYLEN(case_fold_067), case_fold_067 },
+    { __PHYSFS_ARRAYLEN(case_fold_068), case_fold_068 },
+    { __PHYSFS_ARRAYLEN(case_fold_069), case_fold_069 },
+    { __PHYSFS_ARRAYLEN(case_fold_070), case_fold_070 },
+    { __PHYSFS_ARRAYLEN(case_fold_071), case_fold_071 },
+    { __PHYSFS_ARRAYLEN(case_fold_072), case_fold_072 },
+    { __PHYSFS_ARRAYLEN(case_fold_073), case_fold_073 },
+    { __PHYSFS_ARRAYLEN(case_fold_074), case_fold_074 },
+    { __PHYSFS_ARRAYLEN(case_fold_075), case_fold_075 },
+    { __PHYSFS_ARRAYLEN(case_fold_076), case_fold_076 },
+    { __PHYSFS_ARRAYLEN(case_fold_077), case_fold_077 },
+    { __PHYSFS_ARRAYLEN(case_fold_078), case_fold_078 },
+    { __PHYSFS_ARRAYLEN(case_fold_079), case_fold_079 },
+    { __PHYSFS_ARRAYLEN(case_fold_080), case_fold_080 },
+    { __PHYSFS_ARRAYLEN(case_fold_081), case_fold_081 },
+    { __PHYSFS_ARRAYLEN(case_fold_082), case_fold_082 },
+    { __PHYSFS_ARRAYLEN(case_fold_083), case_fold_083 },
+    { __PHYSFS_ARRAYLEN(case_fold_084), case_fold_084 },
+    { __PHYSFS_ARRAYLEN(case_fold_085), case_fold_085 },
+    { __PHYSFS_ARRAYLEN(case_fold_086), case_fold_086 },
+    { __PHYSFS_ARRAYLEN(case_fold_087), case_fold_087 },
+    { __PHYSFS_ARRAYLEN(case_fold_088), case_fold_088 },
+    { __PHYSFS_ARRAYLEN(case_fold_089), case_fold_089 },
+    { __PHYSFS_ARRAYLEN(case_fold_090), case_fold_090 },
+    { __PHYSFS_ARRAYLEN(case_fold_091), case_fold_091 },
+    { __PHYSFS_ARRAYLEN(case_fold_092), case_fold_092 },
+    { __PHYSFS_ARRAYLEN(case_fold_093), case_fold_093 },
+    { __PHYSFS_ARRAYLEN(case_fold_094), case_fold_094 },
+    { __PHYSFS_ARRAYLEN(case_fold_095), case_fold_095 },
+    { __PHYSFS_ARRAYLEN(case_fold_096), case_fold_096 },
+    { __PHYSFS_ARRAYLEN(case_fold_097), case_fold_097 },
+    { __PHYSFS_ARRAYLEN(case_fold_098), case_fold_098 },
+    { __PHYSFS_ARRAYLEN(case_fold_099), case_fold_099 },
+    { __PHYSFS_ARRAYLEN(case_fold_100), case_fold_100 },
+    { __PHYSFS_ARRAYLEN(case_fold_101), case_fold_101 },
+    { __PHYSFS_ARRAYLEN(case_fold_102), case_fold_102 },
+    { __PHYSFS_ARRAYLEN(case_fold_103), case_fold_103 },
+    { __PHYSFS_ARRAYLEN(case_fold_104), case_fold_104 },
+    { __PHYSFS_ARRAYLEN(case_fold_105), case_fold_105 },
+    { __PHYSFS_ARRAYLEN(case_fold_106), case_fold_106 },
+    { __PHYSFS_ARRAYLEN(case_fold_107), case_fold_107 },
+    { __PHYSFS_ARRAYLEN(case_fold_108), case_fold_108 },
+    { __PHYSFS_ARRAYLEN(case_fold_109), case_fold_109 },
+    { __PHYSFS_ARRAYLEN(case_fold_110), case_fold_110 },
+    { __PHYSFS_ARRAYLEN(case_fold_111), case_fold_111 },
+    { __PHYSFS_ARRAYLEN(case_fold_112), case_fold_112 },
+    { __PHYSFS_ARRAYLEN(case_fold_113), case_fold_113 },
+    { __PHYSFS_ARRAYLEN(case_fold_114), case_fold_114 },
+    { __PHYSFS_ARRAYLEN(case_fold_115), case_fold_115 },
+    { __PHYSFS_ARRAYLEN(case_fold_116), case_fold_116 },
+    { __PHYSFS_ARRAYLEN(case_fold_117), case_fold_117 },
+    { __PHYSFS_ARRAYLEN(case_fold_118), case_fold_118 },
+    { __PHYSFS_ARRAYLEN(case_fold_119), case_fold_119 },
+    { __PHYSFS_ARRAYLEN(case_fold_120), case_fold_120 },
+    { __PHYSFS_ARRAYLEN(case_fold_121), case_fold_121 },
+    { __PHYSFS_ARRAYLEN(case_fold_122), case_fold_122 },
+    { 0, NULL },
+    { __PHYSFS_ARRAYLEN(case_fold_124), case_fold_124 },
+    { 0, NULL },
+    { __PHYSFS_ARRAYLEN(case_fold_126), case_fold_126 },
+    { 0, NULL },
+    { __PHYSFS_ARRAYLEN(case_fold_128), case_fold_128 },
+    { __PHYSFS_ARRAYLEN(case_fold_129), case_fold_129 },
+    { __PHYSFS_ARRAYLEN(case_fold_130), case_fold_130 },
+    { __PHYSFS_ARRAYLEN(case_fold_131), case_fold_131 },
+    { __PHYSFS_ARRAYLEN(case_fold_132), case_fold_132 },
+    { __PHYSFS_ARRAYLEN(case_fold_133), case_fold_133 },
+    { __PHYSFS_ARRAYLEN(case_fold_134), case_fold_134 },
+    { __PHYSFS_ARRAYLEN(case_fold_135), case_fold_135 },
+    { __PHYSFS_ARRAYLEN(case_fold_136), case_fold_136 },
+    { __PHYSFS_ARRAYLEN(case_fold_137), case_fold_137 },
+    { __PHYSFS_ARRAYLEN(case_fold_138), case_fold_138 },
+    { __PHYSFS_ARRAYLEN(case_fold_139), case_fold_139 },
+    { __PHYSFS_ARRAYLEN(case_fold_140), case_fold_140 },
+    { __PHYSFS_ARRAYLEN(case_fold_141), case_fold_141 },
+    { __PHYSFS_ARRAYLEN(case_fold_142), case_fold_142 },
+    { __PHYSFS_ARRAYLEN(case_fold_143), case_fold_143 },
+    { __PHYSFS_ARRAYLEN(case_fold_144), case_fold_144 },
+    { __PHYSFS_ARRAYLEN(case_fold_145), case_fold_145 },
+    { __PHYSFS_ARRAYLEN(case_fold_146), case_fold_146 },
+    { __PHYSFS_ARRAYLEN(case_fold_147), case_fold_147 },
+    { __PHYSFS_ARRAYLEN(case_fold_148), case_fold_148 },
+    { __PHYSFS_ARRAYLEN(case_fold_149), case_fold_149 },
+    { __PHYSFS_ARRAYLEN(case_fold_150), case_fold_150 },
+    { __PHYSFS_ARRAYLEN(case_fold_151), case_fold_151 },
+    { __PHYSFS_ARRAYLEN(case_fold_152), case_fold_152 },
+    { __PHYSFS_ARRAYLEN(case_fold_153), case_fold_153 },
+    { __PHYSFS_ARRAYLEN(case_fold_154), case_fold_154 },
+    { __PHYSFS_ARRAYLEN(case_fold_155), case_fold_155 },
+    { __PHYSFS_ARRAYLEN(case_fold_156), case_fold_156 },
+    { __PHYSFS_ARRAYLEN(case_fold_157), case_fold_157 },
+    { __PHYSFS_ARRAYLEN(case_fold_158), case_fold_158 },
+    { __PHYSFS_ARRAYLEN(case_fold_159), case_fold_159 },
+    { __PHYSFS_ARRAYLEN(case_fold_160), case_fold_160 },
+    { __PHYSFS_ARRAYLEN(case_fold_161), case_fold_161 },
+    { __PHYSFS_ARRAYLEN(case_fold_162), case_fold_162 },
+    { __PHYSFS_ARRAYLEN(case_fold_163), case_fold_163 },
+    { __PHYSFS_ARRAYLEN(case_fold_164), case_fold_164 },
+    { __PHYSFS_ARRAYLEN(case_fold_165), case_fold_165 },
+    { __PHYSFS_ARRAYLEN(case_fold_166), case_fold_166 },
+    { __PHYSFS_ARRAYLEN(case_fold_167), case_fold_167 },
+    { __PHYSFS_ARRAYLEN(case_fold_168), case_fold_168 },
+    { __PHYSFS_ARRAYLEN(case_fold_169), case_fold_169 },
+    { __PHYSFS_ARRAYLEN(case_fold_170), case_fold_170 },
+    { __PHYSFS_ARRAYLEN(case_fold_171), case_fold_171 },
+    { __PHYSFS_ARRAYLEN(case_fold_172), case_fold_172 },
+    { __PHYSFS_ARRAYLEN(case_fold_173), case_fold_173 },
+    { __PHYSFS_ARRAYLEN(case_fold_174), case_fold_174 },
+    { __PHYSFS_ARRAYLEN(case_fold_175), case_fold_175 },
+    { __PHYSFS_ARRAYLEN(case_fold_176), case_fold_176 },
+    { __PHYSFS_ARRAYLEN(case_fold_177), case_fold_177 },
+    { __PHYSFS_ARRAYLEN(case_fold_178), case_fold_178 },
+    { __PHYSFS_ARRAYLEN(case_fold_179), case_fold_179 },
+    { __PHYSFS_ARRAYLEN(case_fold_180), case_fold_180 },
+    { __PHYSFS_ARRAYLEN(case_fold_181), case_fold_181 },
+    { __PHYSFS_ARRAYLEN(case_fold_182), case_fold_182 },
+    { __PHYSFS_ARRAYLEN(case_fold_183), case_fold_183 },
+    { __PHYSFS_ARRAYLEN(case_fold_184), case_fold_184 },
+    { __PHYSFS_ARRAYLEN(case_fold_185), case_fold_185 },
+    { __PHYSFS_ARRAYLEN(case_fold_186), case_fold_186 },
+    { __PHYSFS_ARRAYLEN(case_fold_187), case_fold_187 },
+    { __PHYSFS_ARRAYLEN(case_fold_188), case_fold_188 },
+    { __PHYSFS_ARRAYLEN(case_fold_189), case_fold_189 },
+    { __PHYSFS_ARRAYLEN(case_fold_190), case_fold_190 },
+    { __PHYSFS_ARRAYLEN(case_fold_191), case_fold_191 },
+    { __PHYSFS_ARRAYLEN(case_fold_192), case_fold_192 },
+    { __PHYSFS_ARRAYLEN(case_fold_193), case_fold_193 },
+    { __PHYSFS_ARRAYLEN(case_fold_194), case_fold_194 },
+    { __PHYSFS_ARRAYLEN(case_fold_195), case_fold_195 },
+    { __PHYSFS_ARRAYLEN(case_fold_196), case_fold_196 },
+    { __PHYSFS_ARRAYLEN(case_fold_197), case_fold_197 },
+    { __PHYSFS_ARRAYLEN(case_fold_198), case_fold_198 },
+    { __PHYSFS_ARRAYLEN(case_fold_199), case_fold_199 },
+    { __PHYSFS_ARRAYLEN(case_fold_200), case_fold_200 },
+    { __PHYSFS_ARRAYLEN(case_fold_201), case_fold_201 },
+    { __PHYSFS_ARRAYLEN(case_fold_202), case_fold_202 },
+    { __PHYSFS_ARRAYLEN(case_fold_203), case_fold_203 },
+    { __PHYSFS_ARRAYLEN(case_fold_204), case_fold_204 },
+    { __PHYSFS_ARRAYLEN(case_fold_205), case_fold_205 },
+    { __PHYSFS_ARRAYLEN(case_fold_206), case_fold_206 },
+    { __PHYSFS_ARRAYLEN(case_fold_207), case_fold_207 },
+    { __PHYSFS_ARRAYLEN(case_fold_208), case_fold_208 },
+    { __PHYSFS_ARRAYLEN(case_fold_209), case_fold_209 },
+    { __PHYSFS_ARRAYLEN(case_fold_210), case_fold_210 },
+    { __PHYSFS_ARRAYLEN(case_fold_211), case_fold_211 },
+    { __PHYSFS_ARRAYLEN(case_fold_212), case_fold_212 },
+    { __PHYSFS_ARRAYLEN(case_fold_213), case_fold_213 },
+    { __PHYSFS_ARRAYLEN(case_fold_214), case_fold_214 },
+    { __PHYSFS_ARRAYLEN(case_fold_215), case_fold_215 },
+    { __PHYSFS_ARRAYLEN(case_fold_216), case_fold_216 },
+    { __PHYSFS_ARRAYLEN(case_fold_217), case_fold_217 },
+    { __PHYSFS_ARRAYLEN(case_fold_218), case_fold_218 },
+    { __PHYSFS_ARRAYLEN(case_fold_219), case_fold_219 },
+    { __PHYSFS_ARRAYLEN(case_fold_220), case_fold_220 },
+    { __PHYSFS_ARRAYLEN(case_fold_221), case_fold_221 },
+    { __PHYSFS_ARRAYLEN(case_fold_222), case_fold_222 },
+    { __PHYSFS_ARRAYLEN(case_fold_223), case_fold_223 },
+    { __PHYSFS_ARRAYLEN(case_fold_224), case_fold_224 },
+    { __PHYSFS_ARRAYLEN(case_fold_225), case_fold_225 },
+    { __PHYSFS_ARRAYLEN(case_fold_226), case_fold_226 },
+    { __PHYSFS_ARRAYLEN(case_fold_227), case_fold_227 },
+    { __PHYSFS_ARRAYLEN(case_fold_228), case_fold_228 },
+    { __PHYSFS_ARRAYLEN(case_fold_229), case_fold_229 },
+    { __PHYSFS_ARRAYLEN(case_fold_230), case_fold_230 },
+    { __PHYSFS_ARRAYLEN(case_fold_231), case_fold_231 },
+    { __PHYSFS_ARRAYLEN(case_fold_232), case_fold_232 },
+    { __PHYSFS_ARRAYLEN(case_fold_233), case_fold_233 },
+    { __PHYSFS_ARRAYLEN(case_fold_234), case_fold_234 },
+    { __PHYSFS_ARRAYLEN(case_fold_235), case_fold_235 },
+    { __PHYSFS_ARRAYLEN(case_fold_236), case_fold_236 },
+    { __PHYSFS_ARRAYLEN(case_fold_237), case_fold_237 },
+    { __PHYSFS_ARRAYLEN(case_fold_238), case_fold_238 },
+    { __PHYSFS_ARRAYLEN(case_fold_239), case_fold_239 },
+    { __PHYSFS_ARRAYLEN(case_fold_240), case_fold_240 },
+    { __PHYSFS_ARRAYLEN(case_fold_241), case_fold_241 },
+    { __PHYSFS_ARRAYLEN(case_fold_242), case_fold_242 },
+    { __PHYSFS_ARRAYLEN(case_fold_243), case_fold_243 },
+    { __PHYSFS_ARRAYLEN(case_fold_244), case_fold_244 },
+    { __PHYSFS_ARRAYLEN(case_fold_245), case_fold_245 },
+    { __PHYSFS_ARRAYLEN(case_fold_246), case_fold_246 },
+    { __PHYSFS_ARRAYLEN(case_fold_247), case_fold_247 },
+    { __PHYSFS_ARRAYLEN(case_fold_248), case_fold_248 },
+    { __PHYSFS_ARRAYLEN(case_fold_249), case_fold_249 },
+    { __PHYSFS_ARRAYLEN(case_fold_250), case_fold_250 },
+    { __PHYSFS_ARRAYLEN(case_fold_251), case_fold_251 },
+    { __PHYSFS_ARRAYLEN(case_fold_252), case_fold_252 },
+    { __PHYSFS_ARRAYLEN(case_fold_253), case_fold_253 },
+    { __PHYSFS_ARRAYLEN(case_fold_254), case_fold_254 },
+    { __PHYSFS_ARRAYLEN(case_fold_255), case_fold_255 },
+};
+
diff --git a/src/unison/physfs-1.1.1/physfs_internal.h b/src/unison/physfs-1.1.1/physfs_internal.h
new file mode 100644 (file)
index 0000000..f9da66e
--- /dev/null
@@ -0,0 +1,1779 @@
+/*
+ * Internal function/structure declaration. Do NOT include in your
+ *  application.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#ifndef _INCLUDE_PHYSFS_INTERNAL_H_
+#define _INCLUDE_PHYSFS_INTERNAL_H_
+
+#ifndef __PHYSICSFS_INTERNAL__
+#error Do not include this header from your applications.
+#endif
+
+#include "physfs.h"
+
+#include <stdlib.h>  /* make sure NULL is defined... */
+
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#elif (!defined assert)
+#define assert(x)
+#endif
+
+/* !!! FIXME: remove this when revamping stack allocation code... */
+#ifdef _MSC_VER
+#include <malloc.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Interface for small allocations. If you need a little scratch space for
+ *  a throwaway buffer or string, use this. It will make small allocations
+ *  on the stack if possible, and use allocator.Malloc() if they are too
+ *  large. This helps reduce malloc pressure.
+ * There are some rules, though:
+ * NEVER return a pointer from this, as stack-allocated buffers go away
+ *  when your function returns.
+ * NEVER allocate in a loop, as stack-allocated pointers will pile up. Call
+ *  a function that uses smallAlloc from your loop, so the allocation can
+ *  free each time.
+ * NEVER call smallAlloc with any complex expression (it's a macro that WILL
+ *  have side effects...it references the argument multiple times). Use a
+ *  variable or a literal.
+ * NEVER free a pointer from this with anything but smallFree. It will not
+ *  be a valid pointer to the allocator, regardless of where the memory came
+ *  from.
+ * NEVER realloc a pointer from this.
+ * NEVER forget to use smallFree: it may not be a pointer from the stack.
+ * NEVER forget to check for NULL...allocation can fail here, of course!
+ */
+#define __PHYSFS_SMALLALLOCTHRESHOLD 128
+void *__PHYSFS_initSmallAlloc(void *ptr, PHYSFS_uint64 len);
+
+#define __PHYSFS_smallAlloc(bytes) ( \
+    __PHYSFS_initSmallAlloc((((bytes) < __PHYSFS_SMALLALLOCTHRESHOLD) ? \
+                             alloca((size_t)((bytes)+1)) : NULL), (bytes)) \
+)
+
+void __PHYSFS_smallFree(void *ptr);
+
+
+/* Use the allocation hooks. */
+#define malloc(x) Do not use malloc() directly.
+#define realloc(x, y) Do not use realloc() directly.
+#define free(x) Do not use free() directly.
+/* !!! FIXME: add alloca check here. */
+
+/* The LANG section. */
+/*  please send questions/translations to Ryan: icculus@icculus.org. */
+
+#if (!defined PHYSFS_LANG)
+#  define PHYSFS_LANG PHYSFS_LANG_ENGLISH
+#endif
+
+#define PHYSFS_LANG_ENGLISH            1  /* English by Ryan C. Gordon  */
+#define PHYSFS_LANG_RUSSIAN_KOI8_R     2  /* Russian by Ed Sinjiashvili */
+#define PHYSFS_LANG_RUSSIAN_CP1251     3  /* Russian by Ed Sinjiashvili */
+#define PHYSFS_LANG_RUSSIAN_CP866      4  /* Russian by Ed Sinjiashvili */
+#define PHYSFS_LANG_RUSSIAN_ISO_8859_5 5  /* Russian by Ed Sinjiashvili */
+#define PHYSFS_LANG_SPANISH            6  /* Spanish by Pedro J. Pérez  */
+#define PHYSFS_LANG_FRENCH             7  /*  French by Stéphane Peter  */
+#define PHYSFS_LANG_GERMAN             8  /*  German by Michael Renner  */
+#define PHYSFS_LANG_PORTUGUESE_BR      9  /* pt-br by Danny Angelo Carminati Grein  */
+
+#if (PHYSFS_LANG == PHYSFS_LANG_ENGLISH)
+ #define DIR_ARCHIVE_DESCRIPTION  "Non-archive, direct filesystem I/O"
+ #define GRP_ARCHIVE_DESCRIPTION  "Build engine Groupfile format"
+ #define HOG_ARCHIVE_DESCRIPTION  "Descent I/II HOG file format"
+ #define MVL_ARCHIVE_DESCRIPTION  "Descent II Movielib format"
+ #define QPAK_ARCHIVE_DESCRIPTION "Quake I/II format"
+ #define ZIP_ARCHIVE_DESCRIPTION  "PkZip/WinZip/Info-Zip compatible"
+ #define WAD_ARCHIVE_DESCRIPTION  "DOOM engine format"
+ #define LZMA_ARCHIVE_DESCRIPTION "LZMA (7zip) format"
+
+ #define ERR_IS_INITIALIZED       "Already initialized"
+ #define ERR_NOT_INITIALIZED      "Not initialized"
+ #define ERR_INVALID_ARGUMENT     "Invalid argument"
+ #define ERR_FILES_STILL_OPEN     "Files still open"
+ #define ERR_NO_DIR_CREATE        "Failed to create directories"
+ #define ERR_OUT_OF_MEMORY        "Out of memory"
+ #define ERR_NOT_IN_SEARCH_PATH   "No such entry in search path"
+ #define ERR_NOT_SUPPORTED        "Operation not supported"
+ #define ERR_UNSUPPORTED_ARCHIVE  "Archive type unsupported"
+ #define ERR_NOT_A_HANDLE         "Not a file handle"
+ #define ERR_INSECURE_FNAME       "Insecure filename"
+ #define ERR_SYMLINK_DISALLOWED   "Symbolic links are disabled"
+ #define ERR_NO_WRITE_DIR         "Write directory is not set"
+ #define ERR_NO_SUCH_FILE         "File not found"
+ #define ERR_NO_SUCH_PATH         "Path not found"
+ #define ERR_NO_SUCH_VOLUME       "Volume not found"
+ #define ERR_PAST_EOF             "Past end of file"
+ #define ERR_ARC_IS_READ_ONLY     "Archive is read-only"
+ #define ERR_IO_ERROR             "I/O error"
+ #define ERR_CANT_SET_WRITE_DIR   "Can't set write directory"
+ #define ERR_SYMLINK_LOOP         "Infinite symbolic link loop"
+ #define ERR_COMPRESSION          "(De)compression error"
+ #define ERR_NOT_IMPLEMENTED      "Not implemented"
+ #define ERR_OS_ERROR             "Operating system reported error"
+ #define ERR_FILE_EXISTS          "File already exists"
+ #define ERR_NOT_A_FILE           "Not a file"
+ #define ERR_NOT_A_DIR            "Not a directory"
+ #define ERR_NOT_AN_ARCHIVE       "Not an archive"
+ #define ERR_CORRUPTED            "Corrupted archive"
+ #define ERR_SEEK_OUT_OF_RANGE    "Seek out of range"
+ #define ERR_BAD_FILENAME         "Bad filename"
+ #define ERR_PHYSFS_BAD_OS_CALL   "(BUG) PhysicsFS made a bad system call"
+ #define ERR_ARGV0_IS_NULL        "argv0 is NULL"
+ #define ERR_NEED_DICT            "need dictionary"
+ #define ERR_DATA_ERROR           "data error"
+ #define ERR_MEMORY_ERROR         "memory error"
+ #define ERR_BUFFER_ERROR         "buffer error"
+ #define ERR_VERSION_ERROR        "version error"
+ #define ERR_UNKNOWN_ERROR        "unknown error"
+ #define ERR_SEARCHPATH_TRUNC     "Search path was truncated"
+ #define ERR_GETMODFN_TRUNC       "GetModuleFileName() was truncated"
+ #define ERR_GETMODFN_NO_DIR      "GetModuleFileName() had no dir"
+ #define ERR_DISK_FULL            "Disk is full"
+ #define ERR_DIRECTORY_FULL       "Directory full"
+ #define ERR_MACOS_GENERIC        "MacOS reported error (%d)"
+ #define ERR_OS2_GENERIC          "OS/2 reported error (%d)"
+ #define ERR_VOL_LOCKED_HW        "Volume is locked through hardware"
+ #define ERR_VOL_LOCKED_SW        "Volume is locked through software"
+ #define ERR_FILE_LOCKED          "File is locked"
+ #define ERR_FILE_OR_DIR_BUSY     "File/directory is busy"
+ #define ERR_FILE_ALREADY_OPEN_W  "File already open for writing"
+ #define ERR_FILE_ALREADY_OPEN_R  "File already open for reading"
+ #define ERR_INVALID_REFNUM       "Invalid reference number"
+ #define ERR_GETTING_FILE_POS     "Error getting file position"
+ #define ERR_VOLUME_OFFLINE       "Volume is offline"
+ #define ERR_PERMISSION_DENIED    "Permission denied"
+ #define ERR_VOL_ALREADY_ONLINE   "Volume already online"
+ #define ERR_NO_SUCH_DRIVE        "No such drive"
+ #define ERR_NOT_MAC_DISK         "Not a Macintosh disk"
+ #define ERR_VOL_EXTERNAL_FS      "Volume belongs to an external filesystem"
+ #define ERR_PROBLEM_RENAME       "Problem during rename"
+ #define ERR_BAD_MASTER_BLOCK     "Bad master directory block"
+ #define ERR_CANT_MOVE_FORBIDDEN  "Attempt to move forbidden"
+ #define ERR_WRONG_VOL_TYPE       "Wrong volume type"
+ #define ERR_SERVER_VOL_LOST      "Server volume has been disconnected"
+ #define ERR_FILE_ID_NOT_FOUND    "File ID not found"
+ #define ERR_FILE_ID_EXISTS       "File ID already exists"
+ #define ERR_SERVER_NO_RESPOND    "Server not responding"
+ #define ERR_USER_AUTH_FAILED     "User authentication failed"
+ #define ERR_PWORD_EXPIRED        "Password has expired on server"
+ #define ERR_ACCESS_DENIED        "Access denied"
+ #define ERR_NOT_A_DOS_DISK       "Not a DOS disk"
+ #define ERR_SHARING_VIOLATION    "Sharing violation"
+ #define ERR_CANNOT_MAKE          "Cannot make"
+ #define ERR_DEV_IN_USE           "Device already in use"
+ #define ERR_OPEN_FAILED          "Open failed"
+ #define ERR_PIPE_BUSY            "Pipe is busy"
+ #define ERR_SHARING_BUF_EXCEEDED "Sharing buffer exceeded"
+ #define ERR_TOO_MANY_HANDLES     "Too many open handles"
+ #define ERR_SEEK_ERROR           "Seek error"
+ #define ERR_DEL_CWD              "Trying to delete current working directory"
+ #define ERR_WRITE_PROTECT_ERROR  "Write protect error"
+ #define ERR_WRITE_FAULT          "Write fault"
+ #define ERR_LOCK_VIOLATION       "Lock violation"
+ #define ERR_GEN_FAILURE          "General failure"
+ #define ERR_UNCERTAIN_MEDIA      "Uncertain media"
+ #define ERR_PROT_VIOLATION       "Protection violation"
+ #define ERR_BROKEN_PIPE          "Broken pipe"
+
+#elif (PHYSFS_LANG == PHYSFS_LANG_GERMAN)
+ #define DIR_ARCHIVE_DESCRIPTION  "Kein Archiv, direkte Ein/Ausgabe in das Dateisystem"
+ #define GRP_ARCHIVE_DESCRIPTION  "Build engine Groupfile format"
+ #define HOG_ARCHIVE_DESCRIPTION  "Descent I/II HOG file format"
+ #define MVL_ARCHIVE_DESCRIPTION  "Descent II Movielib format"
+ #define QPAK_ARCHIVE_DESCRIPTION "Quake I/II format"
+ #define ZIP_ARCHIVE_DESCRIPTION  "PkZip/WinZip/Info-Zip kompatibel"
+ #define WAD_ARCHIVE_DESCRIPTION  "DOOM engine format" /* !!! FIXME: translate this line if needed */
+ #define LZMA_ARCHIVE_DESCRIPTION "LZMA (7zip) format" /* !!! FIXME: translate this line if needed */
+
+ #define ERR_IS_INITIALIZED       "Bereits initialisiert"
+ #define ERR_NOT_INITIALIZED      "Nicht initialisiert"
+ #define ERR_INVALID_ARGUMENT     "Ungültiges Argument"
+ #define ERR_FILES_STILL_OPEN     "Dateien noch immer geöffnet"
+ #define ERR_NO_DIR_CREATE        "Fehler beim Erzeugen der Verzeichnisse"
+ #define ERR_OUT_OF_MEMORY        "Kein Speicher mehr frei"
+ #define ERR_NOT_IN_SEARCH_PATH   "Eintrag nicht im Suchpfad enthalten"
+ #define ERR_NOT_SUPPORTED        "Befehl nicht unterstützt"
+ #define ERR_UNSUPPORTED_ARCHIVE  "Archiv-Typ nicht unterstützt"
+ #define ERR_NOT_A_HANDLE         "Ist kein Dateideskriptor"
+ #define ERR_INSECURE_FNAME       "Unsicherer Dateiname"
+ #define ERR_SYMLINK_DISALLOWED   "Symbolische Verweise deaktiviert"
+ #define ERR_NO_WRITE_DIR         "Schreibverzeichnis ist nicht gesetzt"
+ #define ERR_NO_SUCH_FILE         "Datei nicht gefunden"
+ #define ERR_NO_SUCH_PATH         "Pfad nicht gefunden"
+ #define ERR_NO_SUCH_VOLUME       "Datencontainer nicht gefunden"
+ #define ERR_PAST_EOF             "Hinter dem Ende der Datei"
+ #define ERR_ARC_IS_READ_ONLY     "Archiv ist schreibgeschützt"
+ #define ERR_IO_ERROR             "Ein/Ausgabe Fehler"
+ #define ERR_CANT_SET_WRITE_DIR   "Kann Schreibverzeichnis nicht setzen"
+ #define ERR_SYMLINK_LOOP         "Endlosschleife durch symbolische Verweise"
+ #define ERR_COMPRESSION          "(De)Kompressionsfehler"
+ #define ERR_NOT_IMPLEMENTED      "Nicht implementiert"
+ #define ERR_OS_ERROR             "Betriebssystem meldete Fehler"
+ #define ERR_FILE_EXISTS          "Datei existiert bereits"
+ #define ERR_NOT_A_FILE           "Ist keine Datei"
+ #define ERR_NOT_A_DIR            "Ist kein Verzeichnis"
+ #define ERR_NOT_AN_ARCHIVE       "Ist kein Archiv"
+ #define ERR_CORRUPTED            "Beschädigtes Archiv"
+ #define ERR_SEEK_OUT_OF_RANGE    "Suche war ausserhalb der Reichweite"
+ #define ERR_BAD_FILENAME         "Unzulässiger Dateiname"
+ #define ERR_PHYSFS_BAD_OS_CALL   "(BUG) PhysicsFS verursachte einen ungültigen Systemaufruf"
+ #define ERR_ARGV0_IS_NULL        "argv0 ist NULL"
+ #define ERR_NEED_DICT            "brauche Wörterbuch"
+ #define ERR_DATA_ERROR           "Datenfehler"
+ #define ERR_MEMORY_ERROR         "Speicherfehler"
+ #define ERR_BUFFER_ERROR         "Bufferfehler"
+ #define ERR_VERSION_ERROR        "Versionskonflikt"
+ #define ERR_UNKNOWN_ERROR        "Unbekannter Fehler"
+ #define ERR_SEARCHPATH_TRUNC     "Suchpfad war abgeschnitten"
+ #define ERR_GETMODFN_TRUNC       "GetModuleFileName() war abgeschnitten"
+ #define ERR_GETMODFN_NO_DIR      "GetModuleFileName() bekam kein Verzeichnis"
+ #define ERR_DISK_FULL            "Laufwerk ist voll"
+ #define ERR_DIRECTORY_FULL       "Verzeichnis ist voll"
+ #define ERR_MACOS_GENERIC        "MacOS meldete Fehler (%d)"
+ #define ERR_OS2_GENERIC          "OS/2 meldete Fehler (%d)"
+ #define ERR_VOL_LOCKED_HW        "Datencontainer ist durch Hardware gesperrt"
+ #define ERR_VOL_LOCKED_SW        "Datencontainer ist durch Software gesperrt"
+ #define ERR_FILE_LOCKED          "Datei ist gesperrt"
+ #define ERR_FILE_OR_DIR_BUSY     "Datei/Verzeichnis ist beschäftigt"
+ #define ERR_FILE_ALREADY_OPEN_W  "Datei schon im Schreibmodus geöffnet"
+ #define ERR_FILE_ALREADY_OPEN_R  "Datei schon im Lesemodus geöffnet"
+ #define ERR_INVALID_REFNUM       "Ungültige Referenznummer"
+ #define ERR_GETTING_FILE_POS     "Fehler beim Finden der Dateiposition"
+ #define ERR_VOLUME_OFFLINE       "Datencontainer ist offline"
+ #define ERR_PERMISSION_DENIED    "Zugriff verweigert"
+ #define ERR_VOL_ALREADY_ONLINE   "Datencontainer ist bereits online"
+ #define ERR_NO_SUCH_DRIVE        "Laufwerk nicht vorhanden"
+ #define ERR_NOT_MAC_DISK         "Ist kein Macintosh Laufwerk"
+ #define ERR_VOL_EXTERNAL_FS      "Datencontainer liegt auf einem externen Dateisystem"
+ #define ERR_PROBLEM_RENAME       "Fehler beim Umbenennen"
+ #define ERR_BAD_MASTER_BLOCK     "Beschädigter Hauptverzeichnisblock"
+ #define ERR_CANT_MOVE_FORBIDDEN  "Verschieben nicht erlaubt"
+ #define ERR_WRONG_VOL_TYPE       "Falscher Datencontainer-Typ"
+ #define ERR_SERVER_VOL_LOST      "Datencontainer am Server wurde getrennt"
+ #define ERR_FILE_ID_NOT_FOUND    "Dateikennung nicht gefunden"
+ #define ERR_FILE_ID_EXISTS       "Dateikennung existiert bereits"
+ #define ERR_SERVER_NO_RESPOND    "Server antwortet nicht"
+ #define ERR_USER_AUTH_FAILED     "Benutzerauthentifizierung fehlgeschlagen"
+ #define ERR_PWORD_EXPIRED        "Passwort am Server ist abgelaufen"
+ #define ERR_ACCESS_DENIED        "Zugriff verweigert"
+ #define ERR_NOT_A_DOS_DISK       "Ist kein DOS-Laufwerk"
+ #define ERR_SHARING_VIOLATION    "Zugriffsverletzung"
+ #define ERR_CANNOT_MAKE          "Kann nicht erzeugen"
+ #define ERR_DEV_IN_USE           "Gerät wird bereits benutzt"
+ #define ERR_OPEN_FAILED          "Öffnen fehlgeschlagen"
+ #define ERR_PIPE_BUSY            "Pipeverbindung ist belegt"
+ #define ERR_SHARING_BUF_EXCEEDED "Zugriffsbuffer überschritten"
+ #define ERR_TOO_MANY_HANDLES     "Zu viele offene Dateien"
+ #define ERR_SEEK_ERROR           "Fehler beim Suchen"
+ #define ERR_DEL_CWD              "Aktuelles Arbeitsverzeichnis darf nicht gelöscht werden"
+ #define ERR_WRITE_PROTECT_ERROR  "Schreibschutzfehler"
+ #define ERR_WRITE_FAULT          "Schreibfehler"
+ #define ERR_LOCK_VIOLATION       "Sperrverletzung"
+ #define ERR_GEN_FAILURE          "Allgemeiner Fehler"
+ #define ERR_UNCERTAIN_MEDIA      "Unsicheres Medium"
+ #define ERR_PROT_VIOLATION       "Schutzverletzung"
+ #define ERR_BROKEN_PIPE          "Pipeverbindung unterbrochen"
+
+#elif (PHYSFS_LANG == PHYSFS_LANG_RUSSIAN_KOI8_R)
+ #define DIR_ARCHIVE_DESCRIPTION  "îÅ ÁÒÈÉ×, ÎÅÐÏÓÒÅÄÓÔ×ÅÎÎÙÊ ××ÏÄ/×Ù×ÏÄ ÆÁÊÌÏ×ÏÊ ÓÉÓÔÅÍÙ"
+ #define GRP_ARCHIVE_DESCRIPTION  "æÏÒÍÁÔ ÇÒÕÐÐÏ×ÏÇÏ ÆÁÊÌÁ Build engine"
+ #define HOG_ARCHIVE_DESCRIPTION  "Descent I/II HOG file format"
+ #define MVL_ARCHIVE_DESCRIPTION  "Descent II Movielib format"
+ #define ZIP_ARCHIVE_DESCRIPTION  "PkZip/WinZip/Info-Zip ÓÏ×ÍÅÓÔÉÍÙÊ"
+ #define WAD_ARCHIVE_DESCRIPTION  "DOOM engine format" /* !!! FIXME: translate this line if needed */
+ #define LZMA_ARCHIVE_DESCRIPTION "LZMA (7zip) format" /* !!! FIXME: translate this line if needed */
+
+ #define ERR_IS_INITIALIZED       "õÖÅ ÉÎÉÃÉÁÌÉÚÉÒÏ×ÁÎ"
+ #define ERR_NOT_INITIALIZED      "îÅ ÉÎÉÃÉÁÌÉÚÉÒÏ×ÁÎ"
+ #define ERR_INVALID_ARGUMENT     "îÅ×ÅÒÎÙÊ ÁÒÇÕÍÅÎÔ"
+ #define ERR_FILES_STILL_OPEN     "æÁÊÌÙ ÅÝÅ ÏÔËÒÙÔÙ"
+ #define ERR_NO_DIR_CREATE        "îÅ ÍÏÇÕ ÓÏÚÄÁÔØ ËÁÔÁÌÏÇÉ"
+ #define ERR_OUT_OF_MEMORY        "ëÏÎÞÉÌÁÓØ ÐÁÍÑÔØ"
+ #define ERR_NOT_IN_SEARCH_PATH   "îÅÔ ÔÁËÏÇÏ ÜÌÅÍÅÎÔÁ × ÐÕÔÉ ÐÏÉÓËÁ"
+ #define ERR_NOT_SUPPORTED        "ïÐÅÒÁÃÉÑ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔÓÑ"
+ #define ERR_UNSUPPORTED_ARCHIVE  "áÒÈÉ×Ù ÔÁËÏÇÏ ÔÉÐÁ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÀÔÓÑ"
+ #define ERR_NOT_A_HANDLE         "îÅ ÆÁÊÌÏ×ÙÊ ÄÅÓËÒÉÐÔÏÒ"
+ #define ERR_INSECURE_FNAME       "îÅÂÅÚÏÐÁÓÎÏÅ ÉÍÑ ÆÁÊÌÁ"
+ #define ERR_SYMLINK_DISALLOWED   "óÉÍ×ÏÌØÎÙÅ ÓÓÙÌËÉ ÏÔËÌÀÞÅÎÙ"
+ #define ERR_NO_WRITE_DIR         "ëÁÔÁÌÏÇ ÄÌÑ ÚÁÐÉÓÉ ÎÅ ÕÓÔÁÎÏ×ÌÅÎ"
+ #define ERR_NO_SUCH_FILE         "æÁÊÌ ÎÅ ÎÁÊÄÅÎ"
+ #define ERR_NO_SUCH_PATH         "ðÕÔØ ÎÅ ÎÁÊÄÅÎ"
+ #define ERR_NO_SUCH_VOLUME       "ôÏÍ ÎÅ ÎÁÊÄÅÎ"
+ #define ERR_PAST_EOF             "úÁ ËÏÎÃÏÍ ÆÁÊÌÁ"
+ #define ERR_ARC_IS_READ_ONLY     "áÒÈÉ× ÔÏÌØËÏ ÄÌÑ ÞÔÅÎÉÑ"
+ #define ERR_IO_ERROR             "ïÛÉÂËÁ ××ÏÄÁ/×Ù×ÏÄÁ"
+ #define ERR_CANT_SET_WRITE_DIR   "îÅ ÍÏÇÕ ÕÓÔÁÎÏ×ÉÔØ ËÁÔÁÌÏÇ ÄÌÑ ÚÁÐÉÓÉ"
+ #define ERR_SYMLINK_LOOP         "âÅÓËÏÎÅÞÎÙÊ ÃÉËÌ ÓÉÍ×ÏÌØÎÏÊ ÓÓÙÌËÉ"
+ #define ERR_COMPRESSION          "ïÛÉÂËÁ (òÁÓ)ÐÁËÏ×ËÉ"
+ #define ERR_NOT_IMPLEMENTED      "îÅ ÒÅÁÌÉÚÏ×ÁÎÏ"
+ #define ERR_OS_ERROR             "ïÐÅÒÁÃÉÏÎÎÁÑ ÓÉÓÔÅÍÁ ÓÏÏÂÝÉÌÁ ÏÛÉÂËÕ"
+ #define ERR_FILE_EXISTS          "æÁÊÌ ÕÖÅ ÓÕÝÅÓÔ×ÕÅÔ"
+ #define ERR_NOT_A_FILE           "îÅ ÆÁÊÌ"
+ #define ERR_NOT_A_DIR            "îÅ ËÁÔÁÌÏÇ"
+ #define ERR_NOT_AN_ARCHIVE       "îÅ ÁÒÈÉ×"
+ #define ERR_CORRUPTED            "ðÏ×ÒÅÖÄÅÎÎÙÊ ÁÒÈÉ×"
+ #define ERR_SEEK_OUT_OF_RANGE    "ðÏÚÉÃÉÏÎÉÒÏ×ÁÎÉÅ ÚÁ ÐÒÅÄÅÌÙ"
+ #define ERR_BAD_FILENAME         "îÅ×ÅÒÎÏÅ ÉÍÑ ÆÁÊÌÁ"
+ #define ERR_PHYSFS_BAD_OS_CALL   "(BUG) PhysicsFS ×ÙÐÏÌÎÉÌÁ ÎÅ×ÅÒÎÙÊ ÓÉÓÔÅÍÎÙÊ ×ÙÚÏ×"
+ #define ERR_ARGV0_IS_NULL        "argv0 is NULL"
+ #define ERR_NEED_DICT            "ÎÕÖÅΠÓÌÏ×ÁÒØ"
+ #define ERR_DATA_ERROR           "ÏÛÉÂËÁ ÄÁÎÎÙÈ"
+ #define ERR_MEMORY_ERROR         "ÏÛÉÂËÁ ÐÁÍÑÔÉ"
+ #define ERR_BUFFER_ERROR         "ÏÛÉÂËÁ ÂÕÆÅÒÁ"
+ #define ERR_VERSION_ERROR        "ÏÛÉÂËÁ ×ÅÒÓÉÉ"
+ #define ERR_UNKNOWN_ERROR        "ÎÅÉÚ×ÅÓÔÎÁÑ ÏÛÉÂËÁ"
+ #define ERR_SEARCHPATH_TRUNC     "ðÕÔØ ÐÏÉÓËÁ ÏÂÒÅÚÁÎ"
+ #define ERR_GETMODFN_TRUNC       "GetModuleFileName() ÏÂÒÅÚÁÎ"
+ #define ERR_GETMODFN_NO_DIR      "GetModuleFileName() ÎÅ ÐÏÌÕÞÉÌ ËÁÔÁÌÏÇ"
+ #define ERR_DISK_FULL            "äÉÓË ÐÏÌÏÎ"
+ #define ERR_DIRECTORY_FULL       "ëÁÔÁÌÏÇ ÐÏÌÏÎ"
+ #define ERR_MACOS_GENERIC        "MacOS ÓÏÏÂÝÉÌÁ ÏÛÉÂËÕ (%d)"
+ #define ERR_OS2_GENERIC          "OS/2 ÓÏÏÂÝÉÌÁ ÏÛÉÂËÕ (%d)"
+ #define ERR_VOL_LOCKED_HW        "ôÏÍ ÂÌÏËÉÒÏ×ÁΠÁÐÐÁÒÁÔÎÏ"
+ #define ERR_VOL_LOCKED_SW        "ôÏÍ ÂÌÏËÉÒÏ×ÁΠÐÒÏÇÒÁÍÍÎÏ"
+ #define ERR_FILE_LOCKED          "æÁÊÌ ÚÁÂÌÏËÉÒÏ×ÁÎ"
+ #define ERR_FILE_OR_DIR_BUSY     "æÁÊÌ/ËÁÔÁÌÏÇ ÚÁÎÑÔ"
+ #define ERR_FILE_ALREADY_OPEN_W  "æÁÊÌ ÕÖÅ ÏÔËÒÙÔ ÎÁ ÚÁÐÉÓØ"
+ #define ERR_FILE_ALREADY_OPEN_R  "æÁÊÌ ÕÖÅ ÏÔËÒÙÔ ÎÁ ÞÔÅÎÉÅ"
+ #define ERR_INVALID_REFNUM       "îÅ×ÅÒÎÏÅ ËÏÌÉÞÅÓÔ×Ï ÓÓÙÌÏË"
+ #define ERR_GETTING_FILE_POS     "ïÛÉÂËÁ ÐÒÉ ÐÏÌÕÞÅÎÉÉ ÐÏÚÉÃÉÉ ÆÁÊÌÁ"
+ #define ERR_VOLUME_OFFLINE       "ôÏÍ ÏÔÓÏÅÄÉÎÅÎ"
+ #define ERR_PERMISSION_DENIED    "ïÔËÁÚÁÎÏ × ÒÁÚÒÅÛÅÎÉÉ"
+ #define ERR_VOL_ALREADY_ONLINE   "ôÏÍ ÕÖÅ ÐÏÄÓÏÅÄÉÎÅÎ"
+ #define ERR_NO_SUCH_DRIVE        "îÅÔ ÔÁËÏÇÏ ÄÉÓËÁ"
+ #define ERR_NOT_MAC_DISK         "îÅ ÄÉÓË Macintosh"
+ #define ERR_VOL_EXTERNAL_FS      "ôÏÍ ÐÒÉÎÁÄÌÅÖÉÔ ×ÎÅÛÎÅÊ ÆÁÊÌÏ×ÏÊ ÓÉÓÔÅÍÅ"
+ #define ERR_PROBLEM_RENAME       "ðÒÏÂÌÅÍÁ ÐÒÉ ÐÅÒÅÉÍÅÎÏ×ÁÎÉÉ"
+ #define ERR_BAD_MASTER_BLOCK     "ðÌÏÈÏÊ ÇÌÁ×ÎÙÊ ÂÌÏË ËÁÔÁÌÏÇÁ"
+ #define ERR_CANT_MOVE_FORBIDDEN  "ðÏÐÙÔËÁ ÐÅÒÅÍÅÓÔÉÔØ ÚÁÐÒÅÝÅÎÁ"
+ #define ERR_WRONG_VOL_TYPE       "îÅ×ÅÒÎÙÊ ÔÉРÔÏÍÁ"
+ #define ERR_SERVER_VOL_LOST      "óÅÒ×ÅÒÎÙÊ ÔÏÍ ÂÙÌ ÏÔÓÏÅÄÉÎÅÎ"
+ #define ERR_FILE_ID_NOT_FOUND    "éÄÅÎÔÉÆÉËÁÔÏÒ ÆÁÊÌÁ ÎÅ ÎÁÊÄÅÎ"
+ #define ERR_FILE_ID_EXISTS       "éÄÅÎÔÉÆÉËÁÔÏÒ ÆÁÊÌÁ ÕÖÅ ÓÕÝÅÓÔ×ÕÅÔ"
+ #define ERR_SERVER_NO_RESPOND    "óÅÒ×ÅÒ ÎÅ ÏÔ×ÅÞÁÅÔ"
+ #define ERR_USER_AUTH_FAILED     "éÄÅÎÔÉÆÉËÁÃÉÑ ÐÏÌØÚÏ×ÁÔÅÌÑ ÎÅ ÕÄÁÌÁÓØ"
+ #define ERR_PWORD_EXPIRED        "ðÁÒÏÌØ ÎÁ ÓÅÒ×ÅÒÅ ÕÓÔÁÒÅÌ"
+ #define ERR_ACCESS_DENIED        "ïÔËÁÚÁÎÏ × ÄÏÓÔÕÐÅ"
+ #define ERR_NOT_A_DOS_DISK       "îÅ ÄÉÓË DOS"
+ #define ERR_SHARING_VIOLATION    "îÁÒÕÛÅÎÉÅ ÓÏ×ÍÅÓÔÎÏÇÏ ÄÏÓÔÕÐÁ"
+ #define ERR_CANNOT_MAKE          "îÅ ÍÏÇÕ ÓÏÂÒÁÔØ"
+ #define ERR_DEV_IN_USE           "õÓÔÒÏÊÓÔ×Ï ÕÖÅ ÉÓÐÏÌØÚÕÅÔÓÑ"
+ #define ERR_OPEN_FAILED          "ïÔËÒÙÔÉÅ ÎÅ ÕÄÁÌÏÓØ"
+ #define ERR_PIPE_BUSY            "ëÏÎ×ÅÊÅÒ ÚÁÎÑÔ"
+ #define ERR_SHARING_BUF_EXCEEDED "òÁÚÄÅÌÑÅÍÙÊ ÂÕÆÅÒ ÐÅÒÅÐÏÌÎÅÎ"
+ #define ERR_TOO_MANY_HANDLES     "óÌÉÛËÏÍ ÍÎÏÇÏ ÏÔËÒÙÔÙÈ ÄÅÓËÒÉÐÔÏÒÏ×"
+ #define ERR_SEEK_ERROR           "ïÛÉÂËÁ ÐÏÚÉÃÉÏÎÉÒÏ×ÁÎÉÑ"
+ #define ERR_DEL_CWD              "ðÏÐÙÔËÁ ÕÄÁÌÉÔØ ÔÅËÕÝÉÊ ÒÁÂÏÞÉÊ ËÁÔÁÌÏÇ"
+ #define ERR_WRITE_PROTECT_ERROR  "ïÛÉÂËÁ ÚÁÝÉÔÙ ÚÁÐÉÓÉ"
+ #define ERR_WRITE_FAULT          "ïÛÉÂËÁ ÚÁÐÉÓÉ"
+ #define ERR_LOCK_VIOLATION       "îÁÒÕÛÅÎÉÅ ÂÌÏËÉÒÏ×ËÉ"
+ #define ERR_GEN_FAILURE          "ïÂÝÉÊ ÓÂÏÊ"
+ #define ERR_UNCERTAIN_MEDIA      "îÅÏÐÒÅÄÅÌÅÎÎÙÊ ÎÏÓÉÔÅÌØ"
+ #define ERR_PROT_VIOLATION       "îÁÒÕÛÅÎÉÅ ÚÁÝÉÔÙ"
+ #define ERR_BROKEN_PIPE          "óÌÏÍÁÎÎÙÊ ËÏÎ×ÅÊÅÒ"
+
+#elif (PHYSFS_LANG == PHYSFS_LANG_RUSSIAN_CP1251)
+ #define DIR_ARCHIVE_DESCRIPTION  "Íå àðõèâ, íåïîñðåäñòâåííûé ââîä/âûâîä ôàéëîâîé ñèñòåìû"
+ #define GRP_ARCHIVE_DESCRIPTION  "Ôîðìàò ãðóïïîâîãî ôàéëà Build engine"
+ #define HOG_ARCHIVE_DESCRIPTION  "Descent I/II HOG file format"
+ #define MVL_ARCHIVE_DESCRIPTION  "Descent II Movielib format"
+ #define ZIP_ARCHIVE_DESCRIPTION  "PkZip/WinZip/Info-Zip ñîâìåñòèìûé"
+ #define WAD_ARCHIVE_DESCRIPTION  "DOOM engine format" /* !!! FIXME: translate this line if needed */
+ #define LZMA_ARCHIVE_DESCRIPTION "LZMA (7zip) format" /* !!! FIXME: translate this line if needed */
+
+ #define ERR_IS_INITIALIZED       "Óæå èíèöèàëèçèðîâàí"
+ #define ERR_NOT_INITIALIZED      "Íå èíèöèàëèçèðîâàí"
+ #define ERR_INVALID_ARGUMENT     "Íåâåðíûé àðãóìåíò"
+ #define ERR_FILES_STILL_OPEN     "Ôàéëû åùå îòêðûòû"
+ #define ERR_NO_DIR_CREATE        "Íå ìîãó ñîçäàòü êàòàëîãè"
+ #define ERR_OUT_OF_MEMORY        "Êîí÷èëàñü ïàìÿòü"
+ #define ERR_NOT_IN_SEARCH_PATH   "Íåò òàêîãî ýëåìåíòà â ïóòè ïîèñêà"
+ #define ERR_NOT_SUPPORTED        "Îïåðàöèÿ íå ïîääåðæèâàåòñÿ"
+ #define ERR_UNSUPPORTED_ARCHIVE  "Àðõèâû òàêîãî òèïà íå ïîääåðæèâàþòñÿ"
+ #define ERR_NOT_A_HANDLE         "Íå ôàéëîâûé äåñêðèïòîð"
+ #define ERR_INSECURE_FNAME       "Íåáåçîïàñíîå èìÿ ôàéëà"
+ #define ERR_SYMLINK_DISALLOWED   "Ñèìâîëüíûå ññûëêè îòêëþ÷åíû"
+ #define ERR_NO_WRITE_DIR         "Êàòàëîã äëÿ çàïèñè íå óñòàíîâëåí"
+ #define ERR_NO_SUCH_FILE         "Ôàéë íå íàéäåí"
+ #define ERR_NO_SUCH_PATH         "Ïóòü íå íàéäåí"
+ #define ERR_NO_SUCH_VOLUME       "Òîì íå íàéäåí"
+ #define ERR_PAST_EOF             "Çà êîíöîì ôàéëà"
+ #define ERR_ARC_IS_READ_ONLY     "Àðõèâ òîëüêî äëÿ ÷òåíèÿ"
+ #define ERR_IO_ERROR             "Îøèáêà ââîäà/âûâîäà"
+ #define ERR_CANT_SET_WRITE_DIR   "Íå ìîãó óñòàíîâèòü êàòàëîã äëÿ çàïèñè"
+ #define ERR_SYMLINK_LOOP         "Áåñêîíå÷íûé öèêë ñèìâîëüíîé ññûëêè"
+ #define ERR_COMPRESSION          "Îøèáêà (Ðàñ)ïàêîâêè"
+ #define ERR_NOT_IMPLEMENTED      "Íå ðåàëèçîâàíî"
+ #define ERR_OS_ERROR             "Îïåðàöèîííàÿ ñèñòåìà ñîîáùèëà îøèáêó"
+ #define ERR_FILE_EXISTS          "Ôàéë óæå ñóùåñòâóåò"
+ #define ERR_NOT_A_FILE           "Íå ôàéë"
+ #define ERR_NOT_A_DIR            "Íå êàòàëîã"
+ #define ERR_NOT_AN_ARCHIVE       "Íå àðõèâ"
+ #define ERR_CORRUPTED            "Ïîâðåæäåííûé àðõèâ"
+ #define ERR_SEEK_OUT_OF_RANGE    "Ïîçèöèîíèðîâàíèå çà ïðåäåëû"
+ #define ERR_BAD_FILENAME         "Íåâåðíîå èìÿ ôàéëà"
+ #define ERR_PHYSFS_BAD_OS_CALL   "(BUG) PhysicsFS âûïîëíèëà íåâåðíûé ñèñòåìíûé âûçîâ"
+ #define ERR_ARGV0_IS_NULL        "argv0 is NULL"
+ #define ERR_NEED_DICT            "íóæåí ñëîâàðü"
+ #define ERR_DATA_ERROR           "îøèáêà äàííûõ"
+ #define ERR_MEMORY_ERROR         "îøèáêà ïàìÿòè"
+ #define ERR_BUFFER_ERROR         "îøèáêà áóôåðà"
+ #define ERR_VERSION_ERROR        "îøèáêà âåðñèè"
+ #define ERR_UNKNOWN_ERROR        "íåèçâåñòíàÿ îøèáêà"
+ #define ERR_SEARCHPATH_TRUNC     "Ïóòü ïîèñêà îáðåçàí"
+ #define ERR_GETMODFN_TRUNC       "GetModuleFileName() îáðåçàí"
+ #define ERR_GETMODFN_NO_DIR      "GetModuleFileName() íå ïîëó÷èë êàòàëîã"
+ #define ERR_DISK_FULL            "Äèñê ïîëîí"
+ #define ERR_DIRECTORY_FULL       "Êàòàëîã ïîëîí"
+ #define ERR_MACOS_GENERIC        "MacOS ñîîáùèëà îøèáêó (%d)"
+ #define ERR_OS2_GENERIC          "OS/2 ñîîáùèëà îøèáêó (%d)"
+ #define ERR_VOL_LOCKED_HW        "Òîì áëîêèðîâàí àïïàðàòíî"
+ #define ERR_VOL_LOCKED_SW        "Òîì áëîêèðîâàí ïðîãðàììíî"
+ #define ERR_FILE_LOCKED          "Ôàéë çàáëîêèðîâàí"
+ #define ERR_FILE_OR_DIR_BUSY     "Ôàéë/êàòàëîã çàíÿò"
+ #define ERR_FILE_ALREADY_OPEN_W  "Ôàéë óæå îòêðûò íà çàïèñü"
+ #define ERR_FILE_ALREADY_OPEN_R  "Ôàéë óæå îòêðûò íà ÷òåíèå"
+ #define ERR_INVALID_REFNUM       "Íåâåðíîå êîëè÷åñòâî ññûëîê"
+ #define ERR_GETTING_FILE_POS     "Îøèáêà ïðè ïîëó÷åíèè ïîçèöèè ôàéëà"
+ #define ERR_VOLUME_OFFLINE       "Òîì îòñîåäèíåí"
+ #define ERR_PERMISSION_DENIED    "Îòêàçàíî â ðàçðåøåíèè"
+ #define ERR_VOL_ALREADY_ONLINE   "Òîì óæå ïîäñîåäèíåí"
+ #define ERR_NO_SUCH_DRIVE        "Íåò òàêîãî äèñêà"
+ #define ERR_NOT_MAC_DISK         "Íå äèñê Macintosh"
+ #define ERR_VOL_EXTERNAL_FS      "Òîì ïðèíàäëåæèò âíåøíåé ôàéëîâîé ñèñòåìå"
+ #define ERR_PROBLEM_RENAME       "Ïðîáëåìà ïðè ïåðåèìåíîâàíèè"
+ #define ERR_BAD_MASTER_BLOCK     "Ïëîõîé ãëàâíûé áëîê êàòàëîãà"
+ #define ERR_CANT_MOVE_FORBIDDEN  "Ïîïûòêà ïåðåìåñòèòü çàïðåùåíà"
+ #define ERR_WRONG_VOL_TYPE       "Íåâåðíûé òèï òîìà"
+ #define ERR_SERVER_VOL_LOST      "Ñåðâåðíûé òîì áûë îòñîåäèíåí"
+ #define ERR_FILE_ID_NOT_FOUND    "Èäåíòèôèêàòîð ôàéëà íå íàéäåí"
+ #define ERR_FILE_ID_EXISTS       "Èäåíòèôèêàòîð ôàéëà óæå ñóùåñòâóåò"
+ #define ERR_SERVER_NO_RESPOND    "Ñåðâåð íå îòâå÷àåò"
+ #define ERR_USER_AUTH_FAILED     "Èäåíòèôèêàöèÿ ïîëüçîâàòåëÿ íå óäàëàñü"
+ #define ERR_PWORD_EXPIRED        "Ïàðîëü íà ñåðâåðå óñòàðåë"
+ #define ERR_ACCESS_DENIED        "Îòêàçàíî â äîñòóïå"
+ #define ERR_NOT_A_DOS_DISK       "Íå äèñê DOS"
+ #define ERR_SHARING_VIOLATION    "Íàðóøåíèå ñîâìåñòíîãî äîñòóïà"
+ #define ERR_CANNOT_MAKE          "Íå ìîãó ñîáðàòü"
+ #define ERR_DEV_IN_USE           "Óñòðîéñòâî óæå èñïîëüçóåòñÿ"
+ #define ERR_OPEN_FAILED          "Îòêðûòèå íå óäàëîñü"
+ #define ERR_PIPE_BUSY            "Êîíâåéåð çàíÿò"
+ #define ERR_SHARING_BUF_EXCEEDED "Ðàçäåëÿåìûé áóôåð ïåðåïîëíåí"
+ #define ERR_TOO_MANY_HANDLES     "Ñëèøêîì ìíîãî îòêðûòûõ äåñêðèïòîðîâ"
+ #define ERR_SEEK_ERROR           "Îøèáêà ïîçèöèîíèðîâàíèÿ"
+ #define ERR_DEL_CWD              "Ïîïûòêà óäàëèòü òåêóùèé ðàáî÷èé êàòàëîã"
+ #define ERR_WRITE_PROTECT_ERROR  "Îøèáêà çàùèòû çàïèñè"
+ #define ERR_WRITE_FAULT          "Îøèáêà çàïèñè"
+ #define ERR_LOCK_VIOLATION       "Íàðóøåíèå áëîêèðîâêè"
+ #define ERR_GEN_FAILURE          "Îáùèé ñáîé"
+ #define ERR_UNCERTAIN_MEDIA      "Íåîïðåäåëåííûé íîñèòåëü"
+ #define ERR_PROT_VIOLATION       "Íàðóøåíèå çàùèòû"
+ #define ERR_BROKEN_PIPE          "Ñëîìàííûé êîíâåéåð"
+
+#elif (PHYSFS_LANG == PHYSFS_LANG_RUSSIAN_CP866)
+ #define DIR_ARCHIVE_DESCRIPTION  "\8d¥  à娢, ­¥¯®á।á⢥­­ë© ¢¢®¤/¢ë¢®¤ ä ©«®¢®© á¨á⥬ë"
+ #define GRP_ARCHIVE_DESCRIPTION  "\94®à¬ â £à㯯®¢®£® ä ©«  Build engine"
+ #define HOG_ARCHIVE_DESCRIPTION  "Descent I/II HOG file format"
+ #define MVL_ARCHIVE_DESCRIPTION  "Descent II Movielib format"
+ #define ZIP_ARCHIVE_DESCRIPTION  "PkZip/WinZip/Info-Zip á®¢¬¥á⨬ë©"
+ #define WAD_ARCHIVE_DESCRIPTION  "DOOM engine format" /* !!! FIXME: translate this line if needed */
+ #define LZMA_ARCHIVE_DESCRIPTION "LZMA (7zip) format" /* !!! FIXME: translate this line if needed */
+
+ #define ERR_IS_INITIALIZED       "\93¦¥ ¨­¨æ¨ «¨§¨à®¢ ­"
+ #define ERR_NOT_INITIALIZED      "\8d¥ ¨­¨æ¨ «¨§¨à®¢ ­"
+ #define ERR_INVALID_ARGUMENT     "\8d¥¢¥à­ë©  à£ã¬¥­â"
+ #define ERR_FILES_STILL_OPEN     "\94 ©«ë ¥é¥ ®âªàëâë"
+ #define ERR_NO_DIR_CREATE        "\8d¥ ¬®£ã á®§¤ âì ª â «®£¨"
+ #define ERR_OUT_OF_MEMORY        "\8a®­ç¨« áì ¯ ¬ïâì"
+ #define ERR_NOT_IN_SEARCH_PATH   "\8d¥â â ª®£® í«¥¬¥­â  ¢ ¯ã⨠¯®¨áª "
+ #define ERR_NOT_SUPPORTED        "\8e¯¥à æ¨ï ­¥ ¯®¤¤¥à¦¨¢ ¥âáï"
+ #define ERR_UNSUPPORTED_ARCHIVE  "\80à娢ë â ª®£® â¨¯  ­¥ ¯®¤¤¥à¦¨¢ îâáï"
+ #define ERR_NOT_A_HANDLE         "\8d¥ ä ©«®¢ë© ¤¥áªà¨¯â®à"
+ #define ERR_INSECURE_FNAME       "\8d¥¡¥§®¯ á­®¥ ¨¬ï ä ©« "
+ #define ERR_SYMLINK_DISALLOWED   "\91¨¬¢®«ì­ë¥ áá뫪¨ ®âª«î祭ë"
+ #define ERR_NO_WRITE_DIR         "\8a â «®£ ¤«ï § ¯¨á¨ ­¥ ãáâ ­®¢«¥­"
+ #define ERR_NO_SUCH_FILE         "\94 ©« ­¥ ­ ©¤¥­"
+ #define ERR_NO_SUCH_PATH         "\8fãâì ­¥ ­ ©¤¥­"
+ #define ERR_NO_SUCH_VOLUME       "\92®¬ ­¥ ­ ©¤¥­"
+ #define ERR_PAST_EOF             "\87  ª®­æ®¬ ä ©« "
+ #define ERR_ARC_IS_READ_ONLY     "\80à娢 â®«ìª® ¤«ï ç⥭¨ï"
+ #define ERR_IO_ERROR             "\8e訡ª  ¢¢®¤ /¢ë¢®¤ "
+ #define ERR_CANT_SET_WRITE_DIR   "\8d¥ ¬®£ã ãáâ ­®¢¨âì ª â «®£ ¤«ï § ¯¨á¨"
+ #define ERR_SYMLINK_LOOP         "\81¥áª®­¥ç­ë© æ¨ª« á¨¬¢®«ì­®© áá뫪¨"
+ #define ERR_COMPRESSION          "\8e訡ª  (\90 á)¯ ª®¢ª¨"
+ #define ERR_NOT_IMPLEMENTED      "\8d¥ à¥ «¨§®¢ ­®"
+ #define ERR_OS_ERROR             "\8e¯¥à æ¨®­­ ï á¨á⥬  á®®¡é¨«  ®è¨¡ªã"
+ #define ERR_FILE_EXISTS          "\94 ©« ã¦¥ áãé¥áâ¢ã¥â"
+ #define ERR_NOT_A_FILE           "\8d¥ ä ©«"
+ #define ERR_NOT_A_DIR            "\8d¥ ª â «®£"
+ #define ERR_NOT_AN_ARCHIVE       "\8d¥  à娢"
+ #define ERR_CORRUPTED            "\8f®¢à¥¦¤¥­­ë©  à娢"
+ #define ERR_SEEK_OUT_OF_RANGE    "\8f®§¨æ¨®­¨à®¢ ­¨¥ §  ¯à¥¤¥«ë"
+ #define ERR_BAD_FILENAME         "\8d¥¢¥à­®¥ ¨¬ï ä ©« "
+ #define ERR_PHYSFS_BAD_OS_CALL   "(BUG) PhysicsFS ¢ë¯®«­¨«  ­¥¢¥à­ë© á¨á⥬­ë© ¢ë§®¢"
+ #define ERR_ARGV0_IS_NULL        "argv0 is NULL"
+ #define ERR_NEED_DICT            "­ã¦¥­ á«®¢ àì"
+ #define ERR_DATA_ERROR           "®è¨¡ª  ¤ ­­ëå"
+ #define ERR_MEMORY_ERROR         "®è¨¡ª  ¯ ¬ïâ¨"
+ #define ERR_BUFFER_ERROR         "®è¨¡ª  ¡ãä¥à "
+ #define ERR_VERSION_ERROR        "®è¨¡ª  ¢¥àᨨ"
+ #define ERR_UNKNOWN_ERROR        "­¥¨§¢¥á⭠訡ª "
+ #define ERR_SEARCHPATH_TRUNC     "\8fãâì ¯®¨áª  ®¡à¥§ ­"
+ #define ERR_GETMODFN_TRUNC       "GetModuleFileName() ®¡à¥§ ­"
+ #define ERR_GETMODFN_NO_DIR      "GetModuleFileName() ­¥ ¯®«ã稫 ª â «®£"
+ #define ERR_DISK_FULL            "\84¨áª ¯®«®­"
+ #define ERR_DIRECTORY_FULL       "\8a â «®£ ¯®«®­"
+ #define ERR_MACOS_GENERIC        "MacOS á®®¡é¨«  ®è¨¡ªã (%d)"
+ #define ERR_OS2_GENERIC          "OS/2 á®®¡é¨«  ®è¨¡ªã (%d)"
+ #define ERR_VOL_LOCKED_HW        "\92®¬ ¡«®ª¨à®¢ ­  ¯¯ à â­®"
+ #define ERR_VOL_LOCKED_SW        "\92®¬ ¡«®ª¨à®¢ ­ ¯à®£à ¬¬­®"
+ #define ERR_FILE_LOCKED          "\94 ©« § ¡«®ª¨à®¢ ­"
+ #define ERR_FILE_OR_DIR_BUSY     "\94 ©«/ª â «®£ § ­ïâ"
+ #define ERR_FILE_ALREADY_OPEN_W  "\94 ©« ã¦¥ ®âªàëâ ­  § ¯¨áì"
+ #define ERR_FILE_ALREADY_OPEN_R  "\94 ©« ã¦¥ ®âªàëâ ­  ç⥭¨¥"
+ #define ERR_INVALID_REFNUM       "\8d¥¢¥à­®¥ ª®«¨ç¥á⢮ ááë«®ª"
+ #define ERR_GETTING_FILE_POS     "\8e訡ª  ¯à¨ ¯®«ã祭¨¨ ¯®§¨æ¨¨ ä ©« "
+ #define ERR_VOLUME_OFFLINE       "\92®¬ ®âᮥ¤¨­¥­"
+ #define ERR_PERMISSION_DENIED    "\8e⪠§ ­® ¢ à §à¥è¥­¨¨"
+ #define ERR_VOL_ALREADY_ONLINE   "\92®¬ ã¦¥ ¯®¤á®¥¤¨­¥­"
+ #define ERR_NO_SUCH_DRIVE        "\8d¥â â ª®£® ¤¨áª "
+ #define ERR_NOT_MAC_DISK         "\8d¥ ¤¨áª Macintosh"
+ #define ERR_VOL_EXTERNAL_FS      "\92®¬ ¯à¨­ ¤«¥¦¨â ¢­¥è­¥© ä ©«®¢®© á¨á⥬¥"
+ #define ERR_PROBLEM_RENAME       "\8f஡«¥¬  ¯à¨ ¯¥à¥¨¬¥­®¢ ­¨¨"
+ #define ERR_BAD_MASTER_BLOCK     "\8f«®å®© £« ¢­ë© ¡«®ª ª â «®£ "
+ #define ERR_CANT_MOVE_FORBIDDEN  "\8f®¯ë⪠ ¯¥à¥¬¥áâ¨âì § ¯à¥é¥­ "
+ #define ERR_WRONG_VOL_TYPE       "\8d¥¢¥à­ë© â¨¯ â®¬ "
+ #define ERR_SERVER_VOL_LOST      "\91¥à¢¥à­ë© â®¬ ¡ë« ®âᮥ¤¨­¥­"
+ #define ERR_FILE_ID_NOT_FOUND    "\88¤¥­â¨ä¨ª â®à ä ©«  ­¥ ­ ©¤¥­"
+ #define ERR_FILE_ID_EXISTS       "\88¤¥­â¨ä¨ª â®à ä ©«  ã¦¥ áãé¥áâ¢ã¥â"
+ #define ERR_SERVER_NO_RESPOND    "\91¥à¢¥à ­¥ ®â¢¥ç ¥â"
+ #define ERR_USER_AUTH_FAILED     "\88¤¥­â¨ä¨ª æ¨ï ¯®«ì§®¢ â¥«ï ­¥ ã¤ « áì"
+ #define ERR_PWORD_EXPIRED        "\8f à®«ì ­  á¥à¢¥à¥ ãáâ à¥«"
+ #define ERR_ACCESS_DENIED        "\8e⪠§ ­® ¢ ¤®áâ㯥"
+ #define ERR_NOT_A_DOS_DISK       "\8d¥ ¤¨áª DOS"
+ #define ERR_SHARING_VIOLATION    "\8d àã襭¨¥ á®¢¬¥áâ­®£® ¤®áâ㯠"
+ #define ERR_CANNOT_MAKE          "\8d¥ ¬®£ã á®¡à âì"
+ #define ERR_DEV_IN_USE           "\93áâனá⢮ ã¦¥ ¨á¯®«ì§ã¥âáï"
+ #define ERR_OPEN_FAILED          "\8eâªàë⨥ ­¥ ã¤ «®áì"
+ #define ERR_PIPE_BUSY            "\8a®­¢¥©¥à § ­ïâ"
+ #define ERR_SHARING_BUF_EXCEEDED "\90 §¤¥«ï¥¬ë© ¡ãä¥à ¯¥à¥¯®«­¥­"
+ #define ERR_TOO_MANY_HANDLES     "\91«¨èª®¬ ¬­®£® ®âªàëâëå ¤¥áªà¨¯â®à®¢"
+ #define ERR_SEEK_ERROR           "\8e訡ª  ¯®§¨æ¨®­¨à®¢ ­¨ï"
+ #define ERR_DEL_CWD              "\8f®¯ë⪠ ã¤ «¨âì â¥ªã騩 à ¡®ç¨© ª â «®£"
+ #define ERR_WRITE_PROTECT_ERROR  "\8e訡ª  § é¨âë § ¯¨á¨"
+ #define ERR_WRITE_FAULT          "\8e訡ª  § ¯¨á¨"
+ #define ERR_LOCK_VIOLATION       "\8d àã襭¨¥ ¡«®ª¨à®¢ª¨"
+ #define ERR_GEN_FAILURE          "\8e¡é¨© á¡®©"
+ #define ERR_UNCERTAIN_MEDIA      "\8d¥®¯à¥¤¥«¥­­ë© ­®á¨â¥«ì"
+ #define ERR_PROT_VIOLATION       "\8d àã襭¨¥ § é¨âë"
+ #define ERR_BROKEN_PIPE          "\91«®¬ ­­ë© ª®­¢¥©¥à"
+
+#elif (PHYSFS_LANG == PHYSFS_LANG_RUSSIAN_ISO_8859_5)
+ #define DIR_ARCHIVE_DESCRIPTION  "½Õ ÐàåØÒ, ÝÕßÞáàÕÔáâÒÕÝÝëÙ ÒÒÞÔ/ÒëÒÞÔ äÐÙÛÞÒÞÙ áØáâÕÜë"
+ #define GRP_ARCHIVE_DESCRIPTION  "ÄÞàÜÐâ ÓàãßßÞÒÞÓÞ äÐÙÛРBuild engine"
+ #define HOG_ARCHIVE_DESCRIPTION  "Descent I/II HOG file format"
+ #define MVL_ARCHIVE_DESCRIPTION  "Descent II Movielib format"
+ #define ZIP_ARCHIVE_DESCRIPTION  "PkZip/WinZip/Info-Zip áÞÒÜÕáâØÜëÙ"
+ #define WAD_ARCHIVE_DESCRIPTION  "DOOM engine format" /* !!! FIXME: translate this line if needed */
+ #define LZMA_ARCHIVE_DESCRIPTION "LZMA (7zip) format" /* !!! FIXME: translate this line if needed */
+
+ #define ERR_IS_INITIALIZED       "ÃÖÕ ØÝØæØÐÛØ×ØàÞÒÐÝ"
+ #define ERR_NOT_INITIALIZED      "½Õ ØÝØæØÐÛØ×ØàÞÒÐÝ"
+ #define ERR_INVALID_ARGUMENT     "½ÕÒÕàÝëÙ ÐàÓãÜÕÝâ"
+ #define ERR_FILES_STILL_OPEN     "ÄÐÙÛë ÕéÕ ÞâÚàëâë"
+ #define ERR_NO_DIR_CREATE        "½Õ ÜÞÓã áÞ×ÔÐâì ÚÐâÐÛÞÓØ"
+ #define ERR_OUT_OF_MEMORY        "ºÞÝçØÛÐáì ßÐÜïâì"
+ #define ERR_NOT_IN_SEARCH_PATH   "½Õâ âÐÚÞÓÞ íÛÕÜÕÝâРҠßãâØ ßÞØáÚÐ"
+ #define ERR_NOT_SUPPORTED        "¾ßÕàÐæØï ÝÕ ßÞÔÔÕàÖØÒÐÕâáï"
+ #define ERR_UNSUPPORTED_ARCHIVE  "°àåØÒë âÐÚÞÓÞ âØßРÝÕ ßÞÔÔÕàÖØÒÐîâáï"
+ #define ERR_NOT_A_HANDLE         "½Õ äÐÙÛÞÒëÙ ÔÕáÚàØßâÞà"
+ #define ERR_INSECURE_FNAME       "½ÕÑÕ×ÞßÐáÝÞÕ ØÜï äÐÙÛÐ"
+ #define ERR_SYMLINK_DISALLOWED   "ÁØÜÒÞÛìÝëÕ ááëÛÚØ ÞâÚÛîçÕÝë"
+ #define ERR_NO_WRITE_DIR         "ºÐâÐÛÞÓ ÔÛï ×ÐßØáØ ÝÕ ãáâÐÝÞÒÛÕÝ"
+ #define ERR_NO_SUCH_FILE         "ÄÐÙÛ ÝÕ ÝÐÙÔÕÝ"
+ #define ERR_NO_SUCH_PATH         "¿ãâì ÝÕ ÝÐÙÔÕÝ"
+ #define ERR_NO_SUCH_VOLUME       "ÂÞÜ ÝÕ ÝÐÙÔÕÝ"
+ #define ERR_PAST_EOF             "·Ð ÚÞÝæÞÜ äÐÙÛÐ"
+ #define ERR_ARC_IS_READ_ONLY     "°àåØÒ âÞÛìÚÞ ÔÛï çâÕÝØï"
+ #define ERR_IO_ERROR             "¾èØÑÚРÒÒÞÔÐ/ÒëÒÞÔÐ"
+ #define ERR_CANT_SET_WRITE_DIR   "½Õ ÜÞÓã ãáâÐÝÞÒØâì ÚÐâÐÛÞÓ ÔÛï ×ÐßØáØ"
+ #define ERR_SYMLINK_LOOP         "±ÕáÚÞÝÕçÝëÙ æØÚÛ áØÜÒÞÛìÝÞÙ ááëÛÚØ"
+ #define ERR_COMPRESSION          "¾èØÑÚР(ÀÐá)ßÐÚÞÒÚØ"
+ #define ERR_NOT_IMPLEMENTED      "½Õ àÕÐÛØ×ÞÒÐÝÞ"
+ #define ERR_OS_ERROR             "¾ßÕàÐæØÞÝÝÐï áØáâÕÜРáÞÞÑéØÛРÞèØÑÚã"
+ #define ERR_FILE_EXISTS          "ÄÐÙÛ ãÖÕ áãéÕáâÒãÕâ"
+ #define ERR_NOT_A_FILE           "½Õ äÐÙÛ"
+ #define ERR_NOT_A_DIR            "½Õ ÚÐâÐÛÞÓ"
+ #define ERR_NOT_AN_ARCHIVE       "½Õ ÐàåØÒ"
+ #define ERR_CORRUPTED            "¿ÞÒàÕÖÔÕÝÝëÙ ÐàåØÒ"
+ #define ERR_SEEK_OUT_OF_RANGE    "¿Þ×ØæØÞÝØàÞÒÐÝØÕ ×РßàÕÔÕÛë"
+ #define ERR_BAD_FILENAME         "½ÕÒÕàÝÞÕ ØÜï äÐÙÛÐ"
+ #define ERR_PHYSFS_BAD_OS_CALL   "(BUG) PhysicsFS ÒëßÞÛÝØÛРÝÕÒÕàÝëÙ áØáâÕÜÝëÙ Òë×ÞÒ"
+ #define ERR_ARGV0_IS_NULL        "argv0 is NULL"
+ #define ERR_NEED_DICT            "ÝãÖÕÝ áÛÞÒÐàì"
+ #define ERR_DATA_ERROR           "ÞèØÑÚРÔÐÝÝëå"
+ #define ERR_MEMORY_ERROR         "ÞèØÑÚРßÐÜïâØ"
+ #define ERR_BUFFER_ERROR         "ÞèØÑÚРÑãäÕàÐ"
+ #define ERR_VERSION_ERROR        "ÞèØÑÚРÒÕàáØØ"
+ #define ERR_UNKNOWN_ERROR        "ÝÕØ×ÒÕáâÝÐï ÞèØÑÚÐ"
+ #define ERR_SEARCHPATH_TRUNC     "¿ãâì ßÞØáÚРÞÑàÕ×ÐÝ"
+ #define ERR_GETMODFN_TRUNC       "GetModuleFileName() ÞÑàÕ×ÐÝ"
+ #define ERR_GETMODFN_NO_DIR      "GetModuleFileName() ÝÕ ßÞÛãçØÛ ÚÐâÐÛÞÓ"
+ #define ERR_DISK_FULL            "´ØáÚ ßÞÛÞÝ"
+ #define ERR_DIRECTORY_FULL       "ºÐâÐÛÞÓ ßÞÛÞÝ"
+ #define ERR_MACOS_GENERIC        "MacOS áÞÞÑéØÛРÞèØÑÚã (%d)"
+ #define ERR_OS2_GENERIC          "OS/2 áÞÞÑéØÛРÞèØÑÚã (%d)"
+ #define ERR_VOL_LOCKED_HW        "ÂÞÜ ÑÛÞÚØàÞÒÐÝ ÐßßÐàÐâÝÞ"
+ #define ERR_VOL_LOCKED_SW        "ÂÞÜ ÑÛÞÚØàÞÒÐÝ ßàÞÓàÐÜÜÝÞ"
+ #define ERR_FILE_LOCKED          "ÄÐÙÛ ×ÐÑÛÞÚØàÞÒÐÝ"
+ #define ERR_FILE_OR_DIR_BUSY     "ÄÐÙÛ/ÚÐâÐÛÞÓ ×ÐÝïâ"
+ #define ERR_FILE_ALREADY_OPEN_W  "ÄÐÙÛ ãÖÕ ÞâÚàëâ ÝР×ÐßØáì"
+ #define ERR_FILE_ALREADY_OPEN_R  "ÄÐÙÛ ãÖÕ ÞâÚàëâ ÝРçâÕÝØÕ"
+ #define ERR_INVALID_REFNUM       "½ÕÒÕàÝÞÕ ÚÞÛØçÕáâÒÞ ááëÛÞÚ"
+ #define ERR_GETTING_FILE_POS     "¾èØÑÚРßàØ ßÞÛãçÕÝØØ ßÞ×ØæØØ äÐÙÛÐ"
+ #define ERR_VOLUME_OFFLINE       "ÂÞÜ ÞâáÞÕÔØÝÕÝ"
+ #define ERR_PERMISSION_DENIED    "¾âÚÐ×ÐÝÞ Ò àÐ×àÕèÕÝØØ"
+ #define ERR_VOL_ALREADY_ONLINE   "ÂÞÜ ãÖÕ ßÞÔáÞÕÔØÝÕÝ"
+ #define ERR_NO_SUCH_DRIVE        "½Õâ âÐÚÞÓÞ ÔØáÚÐ"
+ #define ERR_NOT_MAC_DISK         "½Õ ÔØáÚ Macintosh"
+ #define ERR_VOL_EXTERNAL_FS      "ÂÞÜ ßàØÝÐÔÛÕÖØâ ÒÝÕèÝÕÙ äÐÙÛÞÒÞÙ áØáâÕÜÕ"
+ #define ERR_PROBLEM_RENAME       "¿àÞÑÛÕÜРßàØ ßÕàÕØÜÕÝÞÒÐÝØØ"
+ #define ERR_BAD_MASTER_BLOCK     "¿ÛÞåÞÙ ÓÛÐÒÝëÙ ÑÛÞÚ ÚÐâÐÛÞÓÐ"
+ #define ERR_CANT_MOVE_FORBIDDEN  "¿ÞßëâÚРßÕàÕÜÕáâØâì ×ÐßàÕéÕÝÐ"
+ #define ERR_WRONG_VOL_TYPE       "½ÕÒÕàÝëÙ âØß âÞÜÐ"
+ #define ERR_SERVER_VOL_LOST      "ÁÕàÒÕàÝëÙ âÞÜ ÑëÛ ÞâáÞÕÔØÝÕÝ"
+ #define ERR_FILE_ID_NOT_FOUND    "¸ÔÕÝâØäØÚÐâÞà äÐÙÛРÝÕ ÝÐÙÔÕÝ"
+ #define ERR_FILE_ID_EXISTS       "¸ÔÕÝâØäØÚÐâÞà äÐÙÛРãÖÕ áãéÕáâÒãÕâ"
+ #define ERR_SERVER_NO_RESPOND    "ÁÕàÒÕà ÝÕ ÞâÒÕçÐÕâ"
+ #define ERR_USER_AUTH_FAILED     "¸ÔÕÝâØäØÚÐæØï ßÞÛì×ÞÒÐâÕÛï ÝÕ ãÔÐÛÐáì"
+ #define ERR_PWORD_EXPIRED        "¿ÐàÞÛì ÝРáÕàÒÕàÕ ãáâÐàÕÛ"
+ #define ERR_ACCESS_DENIED        "¾âÚÐ×ÐÝÞ Ò ÔÞáâãßÕ"
+ #define ERR_NOT_A_DOS_DISK       "½Õ ÔØáÚ DOS"
+ #define ERR_SHARING_VIOLATION    "½ÐàãèÕÝØÕ áÞÒÜÕáâÝÞÓÞ ÔÞáâãßÐ"
+ #define ERR_CANNOT_MAKE          "½Õ ÜÞÓã áÞÑàÐâì"
+ #define ERR_DEV_IN_USE           "ÃáâàÞÙáâÒÞ ãÖÕ ØáßÞÛì×ãÕâáï"
+ #define ERR_OPEN_FAILED          "¾âÚàëâØÕ ÝÕ ãÔÐÛÞáì"
+ #define ERR_PIPE_BUSY            "ºÞÝÒÕÙÕà ×ÐÝïâ"
+ #define ERR_SHARING_BUF_EXCEEDED "ÀÐ×ÔÕÛïÕÜëÙ ÑãäÕà ßÕàÕßÞÛÝÕÝ"
+ #define ERR_TOO_MANY_HANDLES     "ÁÛØèÚÞÜ ÜÝÞÓÞ ÞâÚàëâëå ÔÕáÚàØßâÞàÞÒ"
+ #define ERR_SEEK_ERROR           "¾èØÑÚРßÞ×ØæØÞÝØàÞÒÐÝØï"
+ #define ERR_DEL_CWD              "¿ÞßëâÚРãÔÐÛØâì âÕÚãéØÙ àÐÑÞçØÙ ÚÐâÐÛÞÓ"
+ #define ERR_WRITE_PROTECT_ERROR  "¾èØÑÚР×ÐéØâë ×ÐßØáØ"
+ #define ERR_WRITE_FAULT          "¾èØÑÚР×ÐßØáØ"
+ #define ERR_LOCK_VIOLATION       "½ÐàãèÕÝØÕ ÑÛÞÚØàÞÒÚØ"
+ #define ERR_GEN_FAILURE          "¾ÑéØÙ áÑÞÙ"
+ #define ERR_UNCERTAIN_MEDIA      "½ÕÞßàÕÔÕÛÕÝÝëÙ ÝÞáØâÕÛì"
+ #define ERR_PROT_VIOLATION       "½ÐàãèÕÝØÕ ×ÐéØâë"
+ #define ERR_BROKEN_PIPE          "ÁÛÞÜÐÝÝëÙ ÚÞÝÒÕÙÕà"
+
+
+#elif (PHYSFS_LANG == PHYSFS_LANG_FRENCH)
+ #define DIR_ARCHIVE_DESCRIPTION  "Pas d'archive, E/S directes sur système de fichiers"
+ #define GRP_ARCHIVE_DESCRIPTION  "Format Groupfile du moteur Build"
+ #define HOG_ARCHIVE_DESCRIPTION  "Descent I/II HOG file format"
+ #define MVL_ARCHIVE_DESCRIPTION  "Descent II Movielib format"
+ #define QPAK_ARCHIVE_DESCRIPTION "Quake I/II format"
+ #define ZIP_ARCHIVE_DESCRIPTION  "Compatible PkZip/WinZip/Info-Zip"
+ #define WAD_ARCHIVE_DESCRIPTION  "Format WAD du moteur DOOM"
+ #define LZMA_ARCHIVE_DESCRIPTION "LZMA (7zip) format" /* !!! FIXME: translate this line if needed */
+
+ #define ERR_IS_INITIALIZED       "Déjà initialisé"
+ #define ERR_NOT_INITIALIZED      "Non initialisé"
+ #define ERR_INVALID_ARGUMENT     "Argument invalide"
+ #define ERR_FILES_STILL_OPEN     "Fichiers encore ouverts"
+ #define ERR_NO_DIR_CREATE        "Echec de la création de répertoires"
+ #define ERR_OUT_OF_MEMORY        "A court de mémoire"
+ #define ERR_NOT_IN_SEARCH_PATH   "Aucune entrée dans le chemin de recherche"
+ #define ERR_NOT_SUPPORTED        "Opération non supportée"
+ #define ERR_UNSUPPORTED_ARCHIVE  "Type d'archive non supportée"
+ #define ERR_NOT_A_HANDLE         "Pas un descripteur de fichier"
+ #define ERR_INSECURE_FNAME       "Nom de fichier dangereux"
+ #define ERR_SYMLINK_DISALLOWED   "Les liens symboliques sont désactivés"
+ #define ERR_NO_WRITE_DIR         "Le répertoire d'écriture n'est pas spécifié"
+ #define ERR_NO_SUCH_FILE         "Fichier non trouvé"
+ #define ERR_NO_SUCH_PATH         "Chemin non trouvé"
+ #define ERR_NO_SUCH_VOLUME       "Volume non trouvé"
+ #define ERR_PAST_EOF             "Au-delà de la fin du fichier"
+ #define ERR_ARC_IS_READ_ONLY     "L'archive est en lecture seule"
+ #define ERR_IO_ERROR             "Erreur E/S"
+ #define ERR_CANT_SET_WRITE_DIR   "Ne peut utiliser le répertoire d'écriture"
+ #define ERR_SYMLINK_LOOP         "Boucle infinie dans les liens symboliques"
+ #define ERR_COMPRESSION          "Erreur de (dé)compression"
+ #define ERR_NOT_IMPLEMENTED      "Non implémenté"
+ #define ERR_OS_ERROR             "Erreur rapportée par le système d'exploitation"
+ #define ERR_FILE_EXISTS          "Le fichier existe déjà"
+ #define ERR_NOT_A_FILE           "Pas un fichier"
+ #define ERR_NOT_A_DIR            "Pas un répertoire"
+ #define ERR_NOT_AN_ARCHIVE       "Pas une archive"
+ #define ERR_CORRUPTED            "Archive corrompue"
+ #define ERR_SEEK_OUT_OF_RANGE    "Pointeur de fichier hors de portée"
+ #define ERR_BAD_FILENAME         "Mauvais nom de fichier"
+ #define ERR_PHYSFS_BAD_OS_CALL   "(BOGUE) PhysicsFS a fait un mauvais appel système, le salaud"
+ #define ERR_ARGV0_IS_NULL        "argv0 est NULL"
+ #define ERR_NEED_DICT            "a besoin du dico"
+ #define ERR_DATA_ERROR           "erreur de données"
+ #define ERR_MEMORY_ERROR         "erreur mémoire"
+ #define ERR_BUFFER_ERROR         "erreur tampon"
+ #define ERR_VERSION_ERROR        "erreur de version"
+ #define ERR_UNKNOWN_ERROR        "erreur inconnue"
+ #define ERR_SEARCHPATH_TRUNC     "Le chemin de recherche a été tronqué"
+ #define ERR_GETMODFN_TRUNC       "GetModuleFileName() a été tronqué"
+ #define ERR_GETMODFN_NO_DIR      "GetModuleFileName() n'a pas de répertoire"
+ #define ERR_DISK_FULL            "Disque plein"
+ #define ERR_DIRECTORY_FULL       "Répertoire plein"
+ #define ERR_MACOS_GENERIC        "Erreur rapportée par MacOS (%d)"
+ #define ERR_OS2_GENERIC          "Erreur rapportée par OS/2 (%d)"
+ #define ERR_VOL_LOCKED_HW        "Le volume est verrouillé matériellement"
+ #define ERR_VOL_LOCKED_SW        "Le volume est verrouillé par logiciel"
+ #define ERR_FILE_LOCKED          "Fichier verrouillé"
+ #define ERR_FILE_OR_DIR_BUSY     "Fichier/répertoire occupé"
+ #define ERR_FILE_ALREADY_OPEN_W  "Fichier déjà ouvert en écriture"
+ #define ERR_FILE_ALREADY_OPEN_R  "Fichier déjà ouvert en lecture"
+ #define ERR_INVALID_REFNUM       "Numéro de référence invalide"
+ #define ERR_GETTING_FILE_POS     "Erreur lors de l'obtention de la position du pointeur de fichier"
+ #define ERR_VOLUME_OFFLINE       "Le volume n'est pas en ligne"
+ #define ERR_PERMISSION_DENIED    "Permission refusée"
+ #define ERR_VOL_ALREADY_ONLINE   "Volumé déjà en ligne"
+ #define ERR_NO_SUCH_DRIVE        "Lecteur inexistant"
+ #define ERR_NOT_MAC_DISK         "Pas un disque Macintosh"
+ #define ERR_VOL_EXTERNAL_FS      "Le volume appartient à un système de fichiers externe"
+ #define ERR_PROBLEM_RENAME       "Problème lors du renommage"
+ #define ERR_BAD_MASTER_BLOCK     "Mauvais block maitre de répertoire"
+ #define ERR_CANT_MOVE_FORBIDDEN  "Essai de déplacement interdit"
+ #define ERR_WRONG_VOL_TYPE       "Mauvais type de volume"
+ #define ERR_SERVER_VOL_LOST      "Le volume serveur a été déconnecté"
+ #define ERR_FILE_ID_NOT_FOUND    "Identificateur de fichier non trouvé"
+ #define ERR_FILE_ID_EXISTS       "Identificateur de fichier existe déjà"
+ #define ERR_SERVER_NO_RESPOND    "Le serveur ne répond pas"
+ #define ERR_USER_AUTH_FAILED     "Authentification de l'utilisateur échouée"
+ #define ERR_PWORD_EXPIRED        "Le mot de passe a expiré sur le serveur"
+ #define ERR_ACCESS_DENIED        "Accès refusé"
+ #define ERR_NOT_A_DOS_DISK       "Pas un disque DOS"
+ #define ERR_SHARING_VIOLATION    "Violation de partage"
+ #define ERR_CANNOT_MAKE          "Ne peut faire"
+ #define ERR_DEV_IN_USE           "Périphérique déjà en utilisation"
+ #define ERR_OPEN_FAILED          "Ouverture échouée"
+ #define ERR_PIPE_BUSY            "Le tube est occupé"
+ #define ERR_SHARING_BUF_EXCEEDED "Tampon de partage dépassé"
+ #define ERR_TOO_MANY_HANDLES     "Trop de descripteurs ouverts"
+ #define ERR_SEEK_ERROR           "Erreur de positionement"
+ #define ERR_DEL_CWD              "Essai de supprimer le répertoire courant"
+ #define ERR_WRITE_PROTECT_ERROR  "Erreur de protection en écriture"
+ #define ERR_WRITE_FAULT          "Erreur d'écriture"
+ #define ERR_LOCK_VIOLATION       "Violation de verrou"
+ #define ERR_GEN_FAILURE          "Echec général"
+ #define ERR_UNCERTAIN_MEDIA      "Média incertain"
+ #define ERR_PROT_VIOLATION       "Violation de protection"
+ #define ERR_BROKEN_PIPE          "Tube cassé"
+
+#elif (PHYSFS_LANG == PHYSFS_LANG_PORTUGUESE_BR)
+ #define DIR_ARCHIVE_DESCRIPTION  "Não arquivo, E/S sistema de arquivos direto"
+ #define GRP_ARCHIVE_DESCRIPTION  "Formato Groupfile do engine Build"
+ #define HOG_ARCHIVE_DESCRIPTION  "Formato Descent I/II HOG file"
+ #define MVL_ARCHIVE_DESCRIPTION  "Formato Descent II Movielib"
+ #define QPAK_ARCHIVE_DESCRIPTION "Formato Quake I/II"
+ #define ZIP_ARCHIVE_DESCRIPTION  "Formato compatível PkZip/WinZip/Info-Zip"
+ #define WAD_ARCHIVE_DESCRIPTION  "Formato WAD do engine DOOM"
+ #define WAD_ARCHIVE_DESCRIPTION  "DOOM engine format" /* !!! FIXME: translate this line if needed */
+ #define LZMA_ARCHIVE_DESCRIPTION "LZMA (7zip) format" /* !!! FIXME: translate this line if needed */
+
+ #define ERR_IS_INITIALIZED       "Já inicializado"
+ #define ERR_NOT_INITIALIZED      "Não inicializado"
+ #define ERR_INVALID_ARGUMENT     "Argumento inválido"
+ #define ERR_FILES_STILL_OPEN     "Arquivos ainda abertos"
+ #define ERR_NO_DIR_CREATE        "Falha na criação de diretórios"
+ #define ERR_OUT_OF_MEMORY        "Memória insuficiente"
+ #define ERR_NOT_IN_SEARCH_PATH   "Entrada não encontrada no caminho de busca"
+ #define ERR_NOT_SUPPORTED        "Operação não suportada"
+ #define ERR_UNSUPPORTED_ARCHIVE  "Tipo de arquivo não suportado"
+ #define ERR_NOT_A_HANDLE         "Não é um handler de arquivo"
+ #define ERR_INSECURE_FNAME       "Nome de arquivo inseguro"
+ #define ERR_SYMLINK_DISALLOWED   "Links simbólicos desabilitados"
+ #define ERR_NO_WRITE_DIR         "Diretório de escrita não definido"
+ #define ERR_NO_SUCH_FILE         "Arquivo não encontrado"
+ #define ERR_NO_SUCH_PATH         "Caminho não encontrado"
+ #define ERR_NO_SUCH_VOLUME       "Volume não encontrado"
+ #define ERR_PAST_EOF             "Passou o fim do arquivo"
+ #define ERR_ARC_IS_READ_ONLY     "Arquivo é somente de leitura"
+ #define ERR_IO_ERROR             "Erro de E/S"
+ #define ERR_CANT_SET_WRITE_DIR   "Não foi possível definir diretório de escrita"
+ #define ERR_SYMLINK_LOOP         "Loop infinito de link simbólico"
+ #define ERR_COMPRESSION          "Erro de (Des)compressão"
+ #define ERR_NOT_IMPLEMENTED      "Não implementado"
+ #define ERR_OS_ERROR             "Erro reportado pelo Sistema Operacional"
+ #define ERR_FILE_EXISTS          "Arquivo já existente"
+ #define ERR_NOT_A_FILE           "Não é um arquivo"
+ #define ERR_NOT_A_DIR            "Não é um diretório"
+ #define ERR_NOT_AN_ARCHIVE       "Não é um pacote"
+ #define ERR_CORRUPTED            "Pacote corrompido"
+ #define ERR_SEEK_OUT_OF_RANGE    "Posicionamento além do tamanho"
+ #define ERR_BAD_FILENAME         "Nome de arquivo inválido"
+ #define ERR_PHYSFS_BAD_OS_CALL   "(BUG) PhysicsFS realizou uma chamada de sistema inválida"
+ #define ERR_ARGV0_IS_NULL        "argv0 é NULL"
+ #define ERR_NEED_DICT            "precisa de diretório"
+ #define ERR_DATA_ERROR           "erro nos dados"
+ #define ERR_MEMORY_ERROR         "erro de memória"
+ #define ERR_BUFFER_ERROR         "erro de buffer"
+ #define ERR_VERSION_ERROR        "erro na version"
+ #define ERR_UNKNOWN_ERROR        "erro desconhecido"
+ #define ERR_SEARCHPATH_TRUNC     "Caminho de procura quebrado"
+ #define ERR_GETMODFN_TRUNC       "GetModuleFileName() foi quebrado"
+ #define ERR_GETMODFN_NO_DIR      "GetModuleFileName() nao teve diretório"
+ #define ERR_DISK_FULL            "Disco cheio"
+ #define ERR_DIRECTORY_FULL       "Diretório cheio"
+ #define ERR_MACOS_GENERIC        "MacOS reportou um erro (%d)"
+ #define ERR_OS2_GENERIC          "OS/2 reportou um erro (%d)"
+ #define ERR_VOL_LOCKED_HW        "Volume travado por hardware"
+ #define ERR_VOL_LOCKED_SW        "Volume travado por software"
+ #define ERR_FILE_LOCKED          "Arquivo travado"
+ #define ERR_FILE_OR_DIR_BUSY     "Arquivo/Diretório está em uso"
+ #define ERR_FILE_ALREADY_OPEN_W  "Arquivo já aberto para escrita"
+ #define ERR_FILE_ALREADY_OPEN_R  "Arquivo já aberto para leitura"
+ #define ERR_INVALID_REFNUM       "Número de referência"
+ #define ERR_GETTING_FILE_POS     "Erro ao tentar obter posição do arquivo"
+ #define ERR_VOLUME_OFFLINE       "Volume está indisponível"
+ #define ERR_PERMISSION_DENIED    "Permissão negada"
+ #define ERR_VOL_ALREADY_ONLINE   "Volume disponível"
+ #define ERR_NO_SUCH_DRIVE        "Drive inexistente"
+ #define ERR_NOT_MAC_DISK         "Não é um disco Macintosh"
+ #define ERR_VOL_EXTERNAL_FS      "Volume pertence a um sistema de arquivos externo"
+ #define ERR_PROBLEM_RENAME       "Problema durante renomeação"
+ #define ERR_BAD_MASTER_BLOCK     "Bloco master do diretório inválido"
+ #define ERR_CANT_MOVE_FORBIDDEN  "Tentativa de mover proibida"
+ #define ERR_WRONG_VOL_TYPE       "Tipo inválido de volume"
+ #define ERR_SERVER_VOL_LOST      "Volume servidor desconectado"
+ #define ERR_FILE_ID_NOT_FOUND    "ID de Arquivo não encontrado"
+ #define ERR_FILE_ID_EXISTS       "ID de Arquivo já existente"
+ #define ERR_SERVER_NO_RESPOND    "Servidor não respondendo"
+ #define ERR_USER_AUTH_FAILED     "Autenticação de usuário falhada"
+ #define ERR_PWORD_EXPIRED        "Password foi expirada no servidor"
+ #define ERR_ACCESS_DENIED        "Accesso negado"
+ #define ERR_NOT_A_DOS_DISK       "Não é um disco DOS"
+ #define ERR_SHARING_VIOLATION    "Violação de compartilhamento"
+ #define ERR_CANNOT_MAKE          "Não pode ser feito"
+ #define ERR_DEV_IN_USE           "Device já em uso"
+ #define ERR_OPEN_FAILED          "Falaha na abertura"
+ #define ERR_PIPE_BUSY            "Fila ocupada"
+ #define ERR_SHARING_BUF_EXCEEDED "Buffer de compartilhamento excedeu"
+ #define ERR_TOO_MANY_HANDLES     "Muitos handles abertos"
+ #define ERR_SEEK_ERROR           "Erro de posicionamento"
+ #define ERR_DEL_CWD              "Tentando remover diretório de trabalho atual"
+ #define ERR_WRITE_PROTECT_ERROR  "Erro de proteção de escrita"
+ #define ERR_WRITE_FAULT          "Erro de escrita"
+ #define ERR_LOCK_VIOLATION       "Violação de trava"
+ #define ERR_GEN_FAILURE          "Falha geral"
+ #define ERR_UNCERTAIN_MEDIA      "Media incerta"
+ #define ERR_PROT_VIOLATION       "Violação de proteção"
+ #define ERR_BROKEN_PIPE          "Fila quebrada"
+
+#elif (PHYSFS_LANG == PHYSFS_LANG_SPANISH)
+ #define DIR_ARCHIVE_DESCRIPTION  "No es un archivo, E/S directa al sistema de ficheros"
+ #define GRP_ARCHIVE_DESCRIPTION  "Formato Build engine Groupfile"
+ #define HOG_ARCHIVE_DESCRIPTION  "Formato Descent I/II HOG file"
+ #define MVL_ARCHIVE_DESCRIPTION  "Formato Descent II Movielib"
+ #define QPAK_ARCHIVE_DESCRIPTION "Formato Quake I/II"
+ #define ZIP_ARCHIVE_DESCRIPTION  "Compatible con PkZip/WinZip/Info-Zip"
+ #define WAD_ARCHIVE_DESCRIPTION  "DOOM engine format" /* !!! FIXME: translate this line if needed */
+ #define LZMA_ARCHIVE_DESCRIPTION "LZMA (7zip) format" /* !!! FIXME: translate this line if needed */
+
+ #define ERR_IS_INITIALIZED       "Ya estaba inicializado"
+ #define ERR_NOT_INITIALIZED      "No está inicializado"
+ #define ERR_INVALID_ARGUMENT     "Argumento inválido"
+ #define ERR_FILES_STILL_OPEN     "Archivos aún abiertos"
+ #define ERR_NO_DIR_CREATE        "Fallo al crear los directorios"
+ #define ERR_OUT_OF_MEMORY        "Memoria agotada"
+ #define ERR_NOT_IN_SEARCH_PATH   "No existe tal entrada en la ruta de búsqueda"
+ #define ERR_NOT_SUPPORTED        "Operación no soportada"
+ #define ERR_UNSUPPORTED_ARCHIVE  "Tipo de archivo no soportado"
+ #define ERR_NOT_A_HANDLE         "No es un manejador de ficheo (file handle)"
+ #define ERR_INSECURE_FNAME       "Nombre de archivo inseguro"
+ #define ERR_SYMLINK_DISALLOWED   "Los enlaces simbólicos están desactivados"
+ #define ERR_NO_WRITE_DIR         "No has configurado un directorio de escritura"
+ #define ERR_NO_SUCH_FILE         "Archivo no encontrado"
+ #define ERR_NO_SUCH_PATH         "Ruta no encontrada"
+ #define ERR_NO_SUCH_VOLUME       "Volumen no encontrado"
+ #define ERR_PAST_EOF             "Te pasaste del final del archivo"
+ #define ERR_ARC_IS_READ_ONLY     "El archivo es de sólo lectura"
+ #define ERR_IO_ERROR             "Error E/S"
+ #define ERR_CANT_SET_WRITE_DIR   "No puedo configurar el directorio de escritura"
+ #define ERR_SYMLINK_LOOP         "Bucle infnito de enlaces simbólicos"
+ #define ERR_COMPRESSION          "Error de (des)compresión"
+ #define ERR_NOT_IMPLEMENTED      "No implementado"
+ #define ERR_OS_ERROR             "El sistema operativo ha devuelto un error"
+ #define ERR_FILE_EXISTS          "El archivo ya existe"
+ #define ERR_NOT_A_FILE           "No es un archivo"
+ #define ERR_NOT_A_DIR            "No es un directorio"
+ #define ERR_NOT_AN_ARCHIVE       "No es un archivo"
+ #define ERR_CORRUPTED            "Archivo corrupto"
+ #define ERR_SEEK_OUT_OF_RANGE    "Búsqueda fuera de rango"
+ #define ERR_BAD_FILENAME         "Nombre de archivo incorrecto"
+ #define ERR_PHYSFS_BAD_OS_CALL   "(BUG) PhysicsFS ha hecho una llamada incorrecta al sistema"
+ #define ERR_ARGV0_IS_NULL        "argv0 es NULL"
+ #define ERR_NEED_DICT            "necesito diccionario"
+ #define ERR_DATA_ERROR           "error de datos"
+ #define ERR_MEMORY_ERROR         "error de memoria"
+ #define ERR_BUFFER_ERROR         "error de buffer"
+ #define ERR_VERSION_ERROR        "error de versión"
+ #define ERR_UNKNOWN_ERROR        "error desconocido"
+ #define ERR_SEARCHPATH_TRUNC     "La ruta de búsqueda ha sido truncada"
+ #define ERR_GETMODFN_TRUNC       "GetModuleFileName() ha sido truncado"
+ #define ERR_GETMODFN_NO_DIR      "GetModuleFileName() no tenia directorio"
+ #define ERR_DISK_FULL            "El disco está lleno"
+ #define ERR_DIRECTORY_FULL       "El directorio está lleno"
+ #define ERR_MACOS_GENERIC        "MacOS ha devuelto un error (%d)"
+ #define ERR_OS2_GENERIC          "OS/2 ha devuelto un error (%d)"
+ #define ERR_VOL_LOCKED_HW        "El volumen está bloqueado por el hardware"
+ #define ERR_VOL_LOCKED_SW        "El volumen está bloqueado por el software"
+ #define ERR_FILE_LOCKED          "El archivo está bloqueado"
+ #define ERR_FILE_OR_DIR_BUSY     "Fichero o directorio ocupados"
+ #define ERR_FILE_ALREADY_OPEN_W  "Fichero ya abierto para escritura"
+ #define ERR_FILE_ALREADY_OPEN_R  "Fichero ya abierto para lectura"
+ #define ERR_INVALID_REFNUM       "El número de referencia no es válido"
+ #define ERR_GETTING_FILE_POS     "Error al tomar la posición del fichero"
+ #define ERR_VOLUME_OFFLINE       "El volumen está desconectado"
+ #define ERR_PERMISSION_DENIED    "Permiso denegado"
+ #define ERR_VOL_ALREADY_ONLINE   "El volumen ya estaba conectado"
+ #define ERR_NO_SUCH_DRIVE        "No existe tal unidad"
+ #define ERR_NOT_MAC_DISK         "No es un disco Macintosh"
+ #define ERR_VOL_EXTERNAL_FS      "El volumen pertence a un sistema de ficheros externo"
+ #define ERR_PROBLEM_RENAME       "Problemas al renombrar"
+ #define ERR_BAD_MASTER_BLOCK     "Bloque maestro de directorios incorrecto"
+ #define ERR_CANT_MOVE_FORBIDDEN  "Intento de mover forbidden"
+ #define ERR_WRONG_VOL_TYPE       "Tipo de volumen incorrecto"
+ #define ERR_SERVER_VOL_LOST      "El servidor de volúmenes ha sido desconectado"
+ #define ERR_FILE_ID_NOT_FOUND    "Identificador de archivo no encontrado"
+ #define ERR_FILE_ID_EXISTS       "El identificador de archivo ya existe"
+ #define ERR_SERVER_NO_RESPOND    "El servidor no responde"
+ #define ERR_USER_AUTH_FAILED     "Fallo al autentificar el usuario"
+ #define ERR_PWORD_EXPIRED        "La Password  en el servidor ha caducado"
+ #define ERR_ACCESS_DENIED        "Acceso denegado"
+ #define ERR_NOT_A_DOS_DISK       "No es un disco de DOS"
+ #define ERR_SHARING_VIOLATION    "Violación al compartir"
+ #define ERR_CANNOT_MAKE          "No puedo hacer make"
+ #define ERR_DEV_IN_USE           "El dispositivo ya estaba en uso"
+ #define ERR_OPEN_FAILED          "Fallo al abrir"
+ #define ERR_PIPE_BUSY            "Tubería ocupada"
+ #define ERR_SHARING_BUF_EXCEEDED "Buffer de compartición sobrepasado"
+ #define ERR_TOO_MANY_HANDLES     "Demasiados manejadores (handles)"
+ #define ERR_SEEK_ERROR           "Error de búsqueda"
+ #define ERR_DEL_CWD              "Intentando borrar el directorio de trabajo actual"
+ #define ERR_WRITE_PROTECT_ERROR  "Error de protección contra escritura"
+ #define ERR_WRITE_FAULT          "Fallo al escribir"
+ #define ERR_LOCK_VIOLATION       "Violación del bloqueo"
+ #define ERR_GEN_FAILURE          "Fallo general"
+ #define ERR_UNCERTAIN_MEDIA      "Medio incierto"
+ #define ERR_PROT_VIOLATION       "Violación de la protección"
+ #define ERR_BROKEN_PIPE          "Tubería rota"
+
+#else
+ #error Please define PHYSFS_LANG.
+#endif
+
+/* end LANG section. */
+
+struct __PHYSFS_DIRHANDLE__;
+struct __PHYSFS_FILEFUNCTIONS__;
+
+
+/* !!! FIXME: find something better than "dvoid" and "fvoid" ... */
+/* Opaque data for file and dir handlers... */
+typedef void dvoid;
+typedef void fvoid;
+
+
+typedef struct
+{
+        /*
+         * Basic info about this archiver...
+         */
+    const PHYSFS_ArchiveInfo *info;
+
+
+    /*
+     * DIRECTORY ROUTINES:
+     * These functions are for dir handles. Generate a handle with the
+     *  openArchive() method, then pass it as the "opaque" dvoid to the
+     *  others.
+     *
+     * Symlinks should always be followed; PhysicsFS will use the
+     *  isSymLink() method and make a judgement on whether to
+     *  continue to call other methods based on that.
+     */
+
+
+        /*
+         * Returns non-zero if (filename) is a valid archive that this
+         *  driver can handle. This filename is in platform-dependent
+         *  notation. forWriting is non-zero if this is to be used for
+         *  the write directory, and zero if this is to be used for an
+         *  element of the search path.
+         */
+    int (*isArchive)(const char *filename, int forWriting);
+
+        /*
+         * Open a dirhandle for dir/archive (name).
+         *  This filename is in platform-dependent notation.
+         *  forWriting is non-zero if this is to be used for
+         *  the write directory, and zero if this is to be used for an
+         *  element of the search path.
+         * Returns NULL on failure, and calls __PHYSFS_setError().
+         *  Returns non-NULL on success. The pointer returned will be
+         *  passed as the "opaque" parameter for later calls.
+         */
+    void *(*openArchive)(const char *name, int forWriting);
+
+        /*
+         * List all files in (dirname). Each file is passed to (callback),
+         *  where a copy is made if appropriate, so you should dispose of
+         *  it properly upon return from the callback.
+         * You should omit symlinks if (omitSymLinks) is non-zero.
+         * If you have a failure, report as much as you can.
+         *  (dirname) is in platform-independent notation.
+         */
+    void (*enumerateFiles)(dvoid *opaque,
+                            const char *dirname,
+                            int omitSymLinks,
+                            PHYSFS_EnumFilesCallback callback,
+                            const char *origdir,
+                            void *callbackdata);
+
+        /*
+         * Returns non-zero if filename can be opened for reading.
+         *  This filename is in platform-independent notation.
+         *  You should not follow symlinks.
+         */
+    int (*exists)(dvoid *opaque, const char *name);
+
+        /*
+         * Returns non-zero if filename is really a directory.
+         *  This filename is in platform-independent notation.
+         *  Symlinks should be followed; if what the symlink points
+         *  to is missing, or isn't a directory, then the retval is zero.
+         *
+         * Regardless of success or failure, please set *fileExists to
+         *  non-zero if the file existed (even if it's a broken symlink!),
+         *  zero if it did not.
+         */
+    int (*isDirectory)(dvoid *opaque, const char *name, int *fileExists);
+
+        /*
+         * Returns non-zero if filename is really a symlink.
+         *  This filename is in platform-independent notation.
+         *
+         * Regardless of success or failure, please set *fileExists to
+         *  non-zero if the file existed (even if it's a broken symlink!),
+         *  zero if it did not.
+         */
+    int (*isSymLink)(dvoid *opaque, const char *name, int *fileExists);
+
+        /*
+         * Retrieve the last modification time (mtime) of a file.
+         *  Returns -1 on failure, or the file's mtime in seconds since
+         *  the epoch (Jan 1, 1970) on success.
+         *  This filename is in platform-independent notation.
+         *
+         * Regardless of success or failure, please set *exists to
+         *  non-zero if the file existed (even if it's a broken symlink!),
+         *  zero if it did not.
+         */
+    PHYSFS_sint64 (*getLastModTime)(dvoid *opaque, const char *fnm, int *exist);
+
+        /*
+         * Open file for reading.
+         *  This filename is in platform-independent notation.
+         * If you can't handle multiple opens of the same file,
+         *  you can opt to fail for the second call.
+         * Fail if the file does not exist.
+         * Returns NULL on failure, and calls __PHYSFS_setError().
+         *  Returns non-NULL on success. The pointer returned will be
+         *  passed as the "opaque" parameter for later file calls.
+         *
+         * Regardless of success or failure, please set *fileExists to
+         *  non-zero if the file existed (even if it's a broken symlink!),
+         *  zero if it did not.
+         */
+    fvoid *(*openRead)(dvoid *opaque, const char *fname, int *fileExists);
+
+        /*
+         * Open file for writing.
+         * If the file does not exist, it should be created. If it exists,
+         *  it should be truncated to zero bytes. The writing
+         *  offset should be the start of the file.
+         * This filename is in platform-independent notation.
+         * If you can't handle multiple opens of the same file,
+         *  you can opt to fail for the second call.
+         * Returns NULL on failure, and calls __PHYSFS_setError().
+         *  Returns non-NULL on success. The pointer returned will be
+         *  passed as the "opaque" parameter for later file calls.
+         */
+    fvoid *(*openWrite)(dvoid *opaque, const char *filename);
+
+        /*
+         * Open file for appending.
+         * If the file does not exist, it should be created. The writing
+         *  offset should be the end of the file.
+         * This filename is in platform-independent notation.
+         * If you can't handle multiple opens of the same file,
+         *  you can opt to fail for the second call.
+         * Returns NULL on failure, and calls __PHYSFS_setError().
+         *  Returns non-NULL on success. The pointer returned will be
+         *  passed as the "opaque" parameter for later file calls.
+         */
+    fvoid *(*openAppend)(dvoid *opaque, const char *filename);
+
+        /*
+         * Delete a file in the archive/directory.
+         *  Return non-zero on success, zero on failure.
+         *  This filename is in platform-independent notation.
+         *  This method may be NULL.
+         * On failure, call __PHYSFS_setError().
+         */
+    int (*remove)(dvoid *opaque, const char *filename);
+
+        /*
+         * Create a directory in the archive/directory.
+         *  If the application is trying to make multiple dirs, PhysicsFS
+         *  will split them up into multiple calls before passing them to
+         *  your driver.
+         *  Return non-zero on success, zero on failure.
+         *  This filename is in platform-independent notation.
+         *  This method may be NULL.
+         * On failure, call __PHYSFS_setError().
+         */
+    int (*mkdir)(dvoid *opaque, const char *filename);
+
+        /*
+         * Close directories/archives, and free any associated memory,
+         *  including (opaque) itself if applicable. Implementation can assume
+         *  that it won't be called if there are still files open from
+         *  this archive.
+         */
+    void (*dirClose)(dvoid *opaque);
+
+
+
+    /*
+     * FILE ROUTINES:
+     * These functions are for file handles generated by the open*() methods.
+     *  They are distinguished by taking a "fvoid" instead of a "dvoid" for
+     *  the opaque handle.
+     */
+
+        /*
+         * Read more from the file.
+         * Returns number of objects of (objSize) bytes read from file, -1
+         *  if complete failure.
+         * On failure, call __PHYSFS_setError().
+         */
+    PHYSFS_sint64 (*read)(fvoid *opaque, void *buffer,
+                          PHYSFS_uint32 objSize, PHYSFS_uint32 objCount);
+
+        /*
+         * Write more to the file. Archives don't have to implement this.
+         *  (Set it to NULL if not implemented).
+         * Returns number of objects of (objSize) bytes written to file, -1
+         *  if complete failure.
+         * On failure, call __PHYSFS_setError().
+         */
+    PHYSFS_sint64 (*write)(fvoid *opaque, const void *buffer,
+                 PHYSFS_uint32 objSize, PHYSFS_uint32 objCount);
+
+        /*
+         * Returns non-zero if at end of file.
+         */
+    int (*eof)(fvoid *opaque);
+
+        /*
+         * Returns byte offset from start of file.
+         */
+    PHYSFS_sint64 (*tell)(fvoid *opaque);
+
+        /*
+         * Move read/write pointer to byte offset from start of file.
+         *  Returns non-zero on success, zero on error.
+         * On failure, call __PHYSFS_setError().
+         */
+    int (*seek)(fvoid *opaque, PHYSFS_uint64 offset);
+
+        /*
+         * Return number of bytes available in the file, or -1 if you
+         *  aren't able to determine.
+         * On failure, call __PHYSFS_setError().
+         */
+    PHYSFS_sint64 (*fileLength)(fvoid *opaque);
+
+        /*
+         * Close the file, and free associated resources, including (opaque)
+         *  if applicable. Returns non-zero on success, zero if can't close
+         *  file. On failure, call __PHYSFS_setError().
+         */
+    int (*fileClose)(fvoid *opaque);
+} PHYSFS_Archiver;
+
+
+/*
+ * Call this to set the message returned by PHYSFS_getLastError().
+ *  Please only use the ERR_* constants above, or add new constants to the
+ *  above group, but I want these all in one place.
+ *
+ * Calling this with a NULL argument is a safe no-op.
+ */
+void __PHYSFS_setError(const char *err);
+
+
+/*
+ * Convert (dirName) to platform-dependent notation, then prepend (prepend)
+ *  and append (append) to the converted string.
+ *
+ *  So, on Win32, calling:
+ *     __PHYSFS_convertToDependent("C:\", "my/files", NULL);
+ *  ...will return the string "C:\my\files".
+ *
+ * This is a convenience function; you might want to hack something out that
+ *  is less generic (and therefore more efficient).
+ *
+ * Be sure to free() the return value when done with it.
+ */
+char *__PHYSFS_convertToDependent(const char *prepend,
+                                  const char *dirName,
+                                  const char *append);
+
+
+/* This byteorder stuff was lifted from SDL. http://www.libsdl.org/ */
+#define PHYSFS_LIL_ENDIAN  1234
+#define PHYSFS_BIG_ENDIAN  4321
+
+#if  defined(__i386__) || defined(__ia64__) || defined(WIN32) || \
+    (defined(__alpha__) || defined(__alpha)) || \
+     defined(__arm__) || defined(ARM) || \
+    (defined(__mips__) && defined(__MIPSEL__)) || \
+     defined(__SYMBIAN32__) || \
+     defined(__x86_64__) || \
+     defined(__LITTLE_ENDIAN__)
+#define PHYSFS_BYTEORDER    PHYSFS_LIL_ENDIAN
+#else
+#define PHYSFS_BYTEORDER    PHYSFS_BIG_ENDIAN
+#endif
+
+
+/*
+ * When sorting the entries in an archive, we use a modified QuickSort.
+ *  When there are less then PHYSFS_QUICKSORT_THRESHOLD entries left to sort,
+ *  we switch over to a BubbleSort for the remainder. Tweak to taste.
+ *
+ * You can override this setting by defining PHYSFS_QUICKSORT_THRESHOLD
+ *  before #including "physfs_internal.h".
+ */
+#ifndef PHYSFS_QUICKSORT_THRESHOLD
+#define PHYSFS_QUICKSORT_THRESHOLD 4
+#endif
+
+/*
+ * Sort an array (or whatever) of (max) elements. This uses a mixture of
+ *  a QuickSort and BubbleSort internally.
+ * (cmpfn) is used to determine ordering, and (swapfn) does the actual
+ *  swapping of elements in the list.
+ *
+ *  See zip.c for an example.
+ */
+void __PHYSFS_sort(void *entries, PHYSFS_uint32 max,
+                   int (*cmpfn)(void *, PHYSFS_uint32, PHYSFS_uint32),
+                   void (*swapfn)(void *, PHYSFS_uint32, PHYSFS_uint32));
+
+
+/* These get used all over for lessening code clutter. */
+#define BAIL_MACRO(e, r) { __PHYSFS_setError(e); return r; }
+#define BAIL_IF_MACRO(c, e, r) if (c) { __PHYSFS_setError(e); return r; }
+#define BAIL_MACRO_MUTEX(e, m, r) { __PHYSFS_setError(e); __PHYSFS_platformReleaseMutex(m); return r; }
+#define BAIL_IF_MACRO_MUTEX(c, e, m, r) if (c) { __PHYSFS_setError(e); __PHYSFS_platformReleaseMutex(m); return r; }
+#define GOTO_MACRO(e, g) { __PHYSFS_setError(e); goto g; }
+#define GOTO_IF_MACRO(c, e, g) if (c) { __PHYSFS_setError(e); goto g; }
+#define GOTO_MACRO_MUTEX(e, m, g) { __PHYSFS_setError(e); __PHYSFS_platformReleaseMutex(m); goto g; }
+#define GOTO_IF_MACRO_MUTEX(c, e, m, g) if (c) { __PHYSFS_setError(e); __PHYSFS_platformReleaseMutex(m); goto g; }
+
+#define __PHYSFS_ARRAYLEN(x) ( (sizeof (x)) / (sizeof (x[0])) )
+
+#if (defined __GNUC__)
+#define __PHYSFS_SI64(x) x##LL
+#define __PHYSFS_UI64(x) x##ULL
+#elif (defined _MSC_VER)
+#define __PHYSFS_SI64(x) x##i64
+#define __PHYSFS_UI64(x) x##ui64
+#else
+#define __PHYSFS_SI64(x) x
+#define __PHYSFS_UI64(x) x
+#endif
+
+/*
+ * Check if a ui64 will fit in the platform's address space.
+ *  The initial sizeof check will optimize this macro out entirely on
+ *  64-bit (and larger?!) platforms, and the other condition will
+ *  return zero or non-zero if the variable will fit in the platform's
+ *  size_t, suitable to pass to malloc. This is kinda messy, but effective.
+ */
+#define __PHYSFS_ui64FitsAddressSpace(s) ( \
+    (sizeof (PHYSFS_uint64) > sizeof (size_t)) && \
+    ((s) > (__PHYSFS_UI64(0xFFFFFFFFFFFFFFFF) >> (64-(sizeof(size_t)*8)))) \
+)
+
+/*
+ * This is a strcasecmp() or stricmp() replacement that expects both strings
+ *  to be in UTF-8 encoding. It will do "case folding" to decide if the
+ *  Unicode codepoints in the strings match.
+ *
+ * It will report which string is "greater than" the other, but be aware that
+ *  this doesn't necessarily mean anything: 'a' may be "less than" 'b', but
+ *  a random Kanji codepoint has no meaningful alphabetically relationship to
+ *  a Greek Lambda, but being able to assign a reliable "value" makes sorting
+ *  algorithms possible, if not entirely sane. Most cases should treat the
+ *  return value as "equal" or "not equal".
+ */
+int __PHYSFS_utf8strcasecmp(const char *s1, const char *s2);
+
+/*
+ * This works like __PHYSFS_utf8strcasecmp(), but takes a character (NOT BYTE
+ *  COUNT) argument, like strcasencmp().
+ */
+int __PHYSFS_utf8strnicmp(const char *s1, const char *s2, PHYSFS_uint32 l);
+
+/*
+ * stricmp() that guarantees to only work with low ASCII. The C runtime
+ *  stricmp() might try to apply a locale/codepage/etc, which we don't want.
+ */
+int __PHYSFS_stricmpASCII(const char *s1, const char *s2);
+
+/*
+ * strnicmp() that guarantees to only work with low ASCII. The C runtime
+ *  strnicmp() might try to apply a locale/codepage/etc, which we don't want.
+ */
+int __PHYSFS_strnicmpASCII(const char *s1, const char *s2, PHYSFS_uint32 l);
+
+
+/*
+ * The current allocator. Not valid before PHYSFS_init is called!
+ */
+extern PHYSFS_Allocator __PHYSFS_AllocatorHooks;
+
+/* convenience macro to make this less cumbersome internally... */
+#define allocator __PHYSFS_AllocatorHooks
+
+/*--------------------------------------------------------------------------*/
+/*--------------------------------------------------------------------------*/
+/*------------                                              ----------------*/
+/*------------  You MUST implement the following functions  ----------------*/
+/*------------        if porting to a new platform.         ----------------*/
+/*------------     (see platform/unix.c for an example)     ----------------*/
+/*------------                                              ----------------*/
+/*--------------------------------------------------------------------------*/
+/*--------------------------------------------------------------------------*/
+
+
+/*
+ * The dir separator; "/" on unix, "\\" on win32, ":" on MacOS, etc...
+ *  Obviously, this isn't a function, but it IS a null-terminated string.
+ */
+extern const char *__PHYSFS_platformDirSeparator;
+
+
+/*
+ * Initialize the platform. This is called when PHYSFS_init() is called from
+ *  the application. You can use this to (for example) determine what version
+ *  of Windows you're running.
+ *
+ * Return zero if there was a catastrophic failure (which prevents you from
+ *  functioning at all), and non-zero otherwise.
+ */
+int __PHYSFS_platformInit(void);
+
+
+/*
+ * Deinitialize the platform. This is called when PHYSFS_deinit() is called
+ *  from the application. You can use this to clean up anything you've
+ *  allocated in your platform driver.
+ *
+ * Return zero if there was a catastrophic failure (which prevents you from
+ *  functioning at all), and non-zero otherwise.
+ */
+int __PHYSFS_platformDeinit(void);
+
+
+/*
+ * Open a file for reading. (filename) is in platform-dependent notation. The
+ *  file pointer should be positioned on the first byte of the file.
+ *
+ * The return value will be some platform-specific datatype that is opaque to
+ *  the caller; it could be a (FILE *) under Unix, or a (HANDLE *) under win32.
+ *
+ * The same file can be opened for read multiple times, and each should have
+ *  a unique file handle; this is frequently employed to prevent race
+ *  conditions in the archivers.
+ *
+ * Call __PHYSFS_setError() and return (NULL) if the file can't be opened.
+ */
+void *__PHYSFS_platformOpenRead(const char *filename);
+
+
+/*
+ * Open a file for writing. (filename) is in platform-dependent notation. If
+ *  the file exists, it should be truncated to zero bytes, and if it doesn't
+ *  exist, it should be created as a zero-byte file. The file pointer should
+ *  be positioned on the first byte of the file.
+ *
+ * The return value will be some platform-specific datatype that is opaque to
+ *  the caller; it could be a (FILE *) under Unix, or a (HANDLE *) under win32,
+ *  etc.
+ *
+ * Opening a file for write multiple times has undefined results.
+ *
+ * Call __PHYSFS_setError() and return (NULL) if the file can't be opened.
+ */
+void *__PHYSFS_platformOpenWrite(const char *filename);
+
+
+/*
+ * Open a file for appending. (filename) is in platform-dependent notation. If
+ *  the file exists, the file pointer should be place just past the end of the
+ *  file, so that the first write will be one byte after the current end of
+ *  the file. If the file doesn't exist, it should be created as a zero-byte
+ *  file. The file pointer should be positioned on the first byte of the file.
+ *
+ * The return value will be some platform-specific datatype that is opaque to
+ *  the caller; it could be a (FILE *) under Unix, or a (HANDLE *) under win32,
+ *  etc.
+ *
+ * Opening a file for append multiple times has undefined results.
+ *
+ * Call __PHYSFS_setError() and return (NULL) if the file can't be opened.
+ */
+void *__PHYSFS_platformOpenAppend(const char *filename);
+
+
+/*
+ * Read more data from a platform-specific file handle. (opaque) should be
+ *  cast to whatever data type your platform uses. Read a maximum of (count)
+ *  objects of (size) 8-bit bytes to the area pointed to by (buffer). If there
+ *  isn't enough data available, return the number of full objects read, and
+ *  position the file pointer at the start of the first incomplete object.
+ *  On success, return (count) and position the file pointer one byte past
+ *  the end of the last read object. Return (-1) if there is a catastrophic
+ *  error, and call __PHYSFS_setError() to describe the problem; the file
+ *  pointer should not move in such a case.
+ */
+PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
+                                    PHYSFS_uint32 size, PHYSFS_uint32 count);
+
+/*
+ * Write more data to a platform-specific file handle. (opaque) should be
+ *  cast to whatever data type your platform uses. Write a maximum of (count)
+ *  objects of (size) 8-bit bytes from the area pointed to by (buffer). If
+ *  there isn't enough data available, return the number of full objects
+ *  written, and position the file pointer at the start of the first
+ *  incomplete object. Return (-1) if there is a catastrophic error, and call
+ *  __PHYSFS_setError() to describe the problem; the file pointer should not
+ *  move in such a case.
+ */
+PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
+                                     PHYSFS_uint32 size, PHYSFS_uint32 count);
+
+/*
+ * Set the file pointer to a new position. (opaque) should be cast to
+ *  whatever data type your platform uses. (pos) specifies the number
+ *  of 8-bit bytes to seek to from the start of the file. Seeking past the
+ *  end of the file is an error condition, and you should check for it.
+ *
+ * Not all file types can seek; this is to be expected by the caller.
+ *
+ * On error, call __PHYSFS_setError() and return zero. On success, return
+ *  a non-zero value.
+ */
+int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos);
+
+
+/*
+ * Get the file pointer's position, in an 8-bit byte offset from the start of
+ *  the file. (opaque) should be cast to whatever data type your platform
+ *  uses.
+ *
+ * Not all file types can "tell"; this is to be expected by the caller.
+ *
+ * On error, call __PHYSFS_setError() and return zero. On success, return
+ *  a non-zero value.
+ */
+PHYSFS_sint64 __PHYSFS_platformTell(void *opaque);
+
+
+/*
+ * Determine the current size of a file, in 8-bit bytes, from an open file.
+ *
+ * The caller expects that this information may not be available for all
+ *  file types on all platforms.
+ *
+ * Return -1 if you can't do it, and call __PHYSFS_setError(). Otherwise,
+ *  return the file length in 8-bit bytes.
+ */
+PHYSFS_sint64 __PHYSFS_platformFileLength(void *handle);
+
+/*
+ * Determine if a file is at EOF. (opaque) should be cast to whatever data
+ *  type your platform uses.
+ *
+ * The caller expects that there was a short read before calling this.
+ *
+ * Return non-zero if EOF, zero if it is _not_ EOF.
+ */
+int __PHYSFS_platformEOF(void *opaque);
+
+/*
+ * Flush any pending writes to disk. (opaque) should be cast to whatever data
+ *  type your platform uses. Be sure to check for errors; the caller expects
+ *  that this function can fail if there was a flushing error, etc.
+ *
+ *  Return zero on failure, non-zero on success.
+ */
+int __PHYSFS_platformFlush(void *opaque);
+
+/*
+ * Flush and close a file. (opaque) should be cast to whatever data type
+ *  your platform uses. Be sure to check for errors when closing; the
+ *  caller expects that this function can fail if there was a flushing
+ *  error, etc.
+ *
+ * You should clean up all resources associated with (opaque).
+ *
+ *  Return zero on failure, non-zero on success.
+ */
+int __PHYSFS_platformClose(void *opaque);
+
+/*
+ * Platform implementation of PHYSFS_getCdRomDirsCallback()...
+ *  CD directories are discovered and reported to the callback one at a time.
+ *  Pointers passed to the callback are assumed to be invalid to the
+ *  application after the callback returns, so you can free them or whatever.
+ *  Callback does not assume results will be sorted in any meaningful way.
+ */
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data);
+
+/*
+ * Calculate the base dir, if your platform needs special consideration.
+ *  Just return NULL if the standard routines will suffice. (see
+ *  calculateBaseDir() in physfs.c ...)
+ *  Caller will free() the retval if it's not NULL.
+ */
+char *__PHYSFS_platformCalcBaseDir(const char *argv0);
+
+/*
+ * Get the platform-specific user name.
+ *  Caller will free() the retval if it's not NULL. If it's NULL, the username
+ *  will default to "default".
+ */
+char *__PHYSFS_platformGetUserName(void);
+
+/*
+ * Get the platform-specific user dir.
+ *  Caller will free() the retval if it's not NULL. If it's NULL, the userdir
+ *  will default to basedir/username.
+ */
+char *__PHYSFS_platformGetUserDir(void);
+
+/*
+ * Return a number that uniquely identifies the current thread.
+ *  On a platform without threading, (1) will suffice. These numbers are
+ *  arbitrary; the only requirement is that no two threads have the same
+ *  number.
+ */
+PHYSFS_uint64 __PHYSFS_platformGetThreadID(void);
+
+/*
+ * Return non-zero if filename (in platform-dependent notation) exists.
+ *  Symlinks should NOT be followed; at this stage, we do not care what the
+ *  symlink points to. Please call __PHYSFS_SetError() with the details of
+ *  why the file does not exist, if it doesn't; you are in a better position
+ *  to know (path not found, bogus filename, file itself is missing, etc).
+ */
+int __PHYSFS_platformExists(const char *fname);
+
+/*
+ * Return the last modified time (in seconds since the epoch) of a file.
+ *  Returns -1 on failure. (fname) is in platform-dependent notation.
+ *  Symlinks should be followed; if what the symlink points to is missing,
+ *  then the retval is -1.
+ */
+PHYSFS_sint64 __PHYSFS_platformGetLastModTime(const char *fname);
+
+/*
+ * Return non-zero if filename (in platform-dependent notation) is a symlink.
+ */
+int __PHYSFS_platformIsSymLink(const char *fname);
+
+
+/*
+ * Return non-zero if filename (in platform-dependent notation) is a symlink.
+ *  Symlinks should be followed; if what the symlink points to is missing,
+ *  or isn't a directory, then the retval is false.
+ */
+int __PHYSFS_platformIsDirectory(const char *fname);
+
+
+/*
+ * Convert (dirName) to platform-dependent notation, then prepend (prepend)
+ *  and append (append) to the converted string.
+ *
+ *  So, on Win32, calling:
+ *     __PHYSFS_platformCvtToDependent("C:\", "my/files", NULL);
+ *  ...will return the string "C:\my\files".
+ *
+ * This can be implemented in a platform-specific manner, so you can get
+ *  get a speed boost that the default implementation can't, since
+ *  you can make assumptions about the size of strings, etc..
+ *
+ * Platforms that choose not to implement this may just call
+ *  __PHYSFS_convertToDependent() as a passthrough, which may fit the bill
+ *  already.
+ *
+ * Be sure to free() the return value when done with it.
+ */
+char *__PHYSFS_platformCvtToDependent(const char *prepend,
+                                      const char *dirName,
+                                      const char *append);
+
+
+/*
+ * Enumerate a directory of files. This follows the rules for the
+ *  PHYSFS_Archiver->enumerateFiles() method (see above), except that the
+ *  (dirName) that is passed to this function is converted to
+ *  platform-DEPENDENT notation by the caller. The PHYSFS_Archiver version
+ *  uses platform-independent notation. Note that ".", "..", and other
+ *  metaentries should always be ignored.
+ */
+void __PHYSFS_platformEnumerateFiles(const char *dirname,
+                                     int omitSymLinks,
+                                     PHYSFS_EnumFilesCallback callback,
+                                     const char *origdir,
+                                     void *callbackdata);
+
+
+/*
+ * Get the current working directory. The return value should be an
+ *  absolute path in platform-dependent notation. The caller will deallocate
+ *  the return value with the standard C runtime free() function when it
+ *  is done with it.
+ * On error, return NULL and set the error message.
+ */
+char *__PHYSFS_platformCurrentDir(void);
+
+
+/*
+ * Get the real physical path to a file. (path) is specified in
+ *  platform-dependent notation, as should your return value be.
+ *  All relative paths should be removed, leaving you with an absolute
+ *  path. Symlinks should be resolved, too, so that the returned value is
+ *  the most direct path to a file.
+ * The return value will be deallocated with the standard C runtime free()
+ *  function when the caller is done with it.
+ * On error, return NULL and set the error message.
+ */
+char *__PHYSFS_platformRealPath(const char *path);
+
+
+/*
+ * Make a directory in the actual filesystem. (path) is specified in
+ *  platform-dependent notation. On error, return zero and set the error
+ *  message. Return non-zero on success.
+ */
+int __PHYSFS_platformMkDir(const char *path);
+
+
+/*
+ * Remove a file or directory entry in the actual filesystem. (path) is
+ *  specified in platform-dependent notation. Note that this deletes files
+ *  _and_ directories, so you might need to do some determination.
+ *  Non-empty directories should report an error and not delete themselves
+ *  or their contents.
+ *
+ * Deleting a symlink should remove the link, not what it points to.
+ *
+ * On error, return zero and set the error message. Return non-zero on success.
+ */
+int __PHYSFS_platformDelete(const char *path);
+
+
+/*
+ * Create a platform-specific mutex. This can be whatever datatype your
+ *  platform uses for mutexes, but it is cast to a (void *) for abstractness.
+ *
+ * Return (NULL) if you couldn't create one. Systems without threads can
+ *  return any arbitrary non-NULL value.
+ */
+void *__PHYSFS_platformCreateMutex(void);
+
+/*
+ * Destroy a platform-specific mutex, and clean up any resources associated
+ *  with it. (mutex) is a value previously returned by
+ *  __PHYSFS_platformCreateMutex(). This can be a no-op on single-threaded
+ *  platforms.
+ */
+void __PHYSFS_platformDestroyMutex(void *mutex);
+
+/*
+ * Grab possession of a platform-specific mutex. Mutexes should be recursive;
+ *  that is, the same thread should be able to call this function multiple
+ *  times in a row without causing a deadlock. This function should block 
+ *  until a thread can gain possession of the mutex.
+ *
+ * Return non-zero if the mutex was grabbed, zero if there was an 
+ *  unrecoverable problem grabbing it (this should not be a matter of 
+ *  timing out! We're talking major system errors; block until the mutex 
+ *  is available otherwise.)
+ *
+ * _DO NOT_ call __PHYSFS_setError() in here! Since setError calls this
+ *  function, you'll cause an infinite recursion. This means you can't
+ *  use the BAIL_*MACRO* macros, either.
+ */
+int __PHYSFS_platformGrabMutex(void *mutex);
+
+/*
+ * Relinquish possession of the mutex when this method has been called 
+ *  once for each time that platformGrabMutex was called. Once possession has
+ *  been released, the next thread in line to grab the mutex (if any) may
+ *  proceed.
+ *
+ * _DO NOT_ call __PHYSFS_setError() in here! Since setError calls this
+ *  function, you'll cause an infinite recursion. This means you can't
+ *  use the BAIL_*MACRO* macros, either.
+ */
+void __PHYSFS_platformReleaseMutex(void *mutex);
+
+/*
+ * Called at the start of PHYSFS_init() to prepare the allocator, if the user
+ *  hasn't selected their own allocator via PHYSFS_setAllocator().
+ *  If the platform has a custom allocator, it should fill in the fields of
+ *  (a) with the proper function pointers and return non-zero.
+ * If the platform just wants to use malloc()/free()/etc, return zero
+ *  immediately and the higher level will handle it. The Init and Deinit
+ *  fields of (a) are optional...set them to NULL if you don't need them.
+ *  Everything else must be implemented. All rules follow those for
+ *  PHYSFS_setAllocator(). If Init isn't NULL, it will be called shortly
+ *  after this function returns non-zero.
+ */
+int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* end of physfs_internal.h ... */
+
diff --git a/src/unison/physfs-1.1.1/physfs_platforms.h b/src/unison/physfs-1.1.1/physfs_platforms.h
new file mode 100644 (file)
index 0000000..9f95a89
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef _INCL_PHYSFS_PLATFORMS
+#define _INCL_PHYSFS_PLATFORMS
+
+#ifndef __PHYSICSFS_INTERNAL__
+#error Do not include this header from your applications.
+#endif
+
+/*
+ * These only define the platforms to determine which files in the platforms
+ *  directory should be compiled. For example, technically BeOS can be called
+ *  a "unix" system, but since it doesn't use unix.c, we don't define
+ *  PHYSFS_PLATFORM_UNIX on that system.
+ */
+
+#if ((defined __BEOS__) || (defined __beos__))
+#  define PHYSFS_PLATFORM_BEOS
+#  define PHYSFS_PLATFORM_POSIX
+#elif (defined _WIN32_WCE) || (defined _WIN64_WCE)
+#  define PHYSFS_PLATFORM_POCKETPC
+#elif (((defined _WIN32) || (defined _WIN64)) && (!defined __CYGWIN__))
+#  define PHYSFS_PLATFORM_WINDOWS
+#elif (defined OS2)
+#  define PHYSFS_PLATFORM_OS2
+#elif ((defined __MACH__) && (defined __APPLE__))
+#  define PHYSFS_PLATFORM_MACOSX
+#  define PHYSFS_PLATFORM_POSIX
+#elif defined(macintosh)
+#  error Classic Mac OS support was dropped from PhysicsFS 2.0. Move to OS X.
+#elif defined(unix)
+#  define PHYSFS_PLATFORM_UNIX
+#  define PHYSFS_PLATFORM_POSIX
+#else
+#  error Unknown platform.
+#endif
+
+#endif  /* include-once blocker. */
+
diff --git a/src/unison/physfs-1.1.1/physfs_unicode.c b/src/unison/physfs-1.1.1/physfs_unicode.c
new file mode 100644 (file)
index 0000000..030bcc8
--- /dev/null
@@ -0,0 +1,459 @@
+#include "physfs.h"
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+
+/*
+ * From rfc3629, the UTF-8 spec:
+ *  http://www.ietf.org/rfc/rfc3629.txt
+ *
+ *   Char. number range  |        UTF-8 octet sequence
+ *      (hexadecimal)    |              (binary)
+ *   --------------------+---------------------------------------------
+ *   0000 0000-0000 007F | 0xxxxxxx
+ *   0000 0080-0000 07FF | 110xxxxx 10xxxxxx
+ *   0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
+ *   0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ */
+
+
+/*
+ * This may not be the best value, but it's one that isn't represented
+ *  in Unicode (0x10FFFF is the largest codepoint value). We return this
+ *  value from utf8codepoint() if there's bogus bits in the
+ *  stream. utf8codepoint() will turn this value into something
+ *  reasonable (like a question mark), for text that wants to try to recover,
+ *  whereas utf8valid() will use the value to determine if a string has bad
+ *  bits.
+ */
+#define UNICODE_BOGUS_CHAR_VALUE 0xFFFFFFFF
+
+/*
+ * This is the codepoint we currently return when there was bogus bits in a
+ *  UTF-8 string. May not fly in Asian locales?
+ */
+#define UNICODE_BOGUS_CHAR_CODEPOINT '?'
+
+static PHYSFS_uint32 utf8codepoint(const char **_str)
+{
+    const char *str = *_str;
+    PHYSFS_uint32 retval = 0;
+    PHYSFS_uint32 octet = (PHYSFS_uint32) ((PHYSFS_uint8) *str);
+    PHYSFS_uint32 octet2, octet3, octet4;
+
+    if (octet == 0)  /* null terminator, end of string. */
+        return 0;
+
+    else if (octet < 128)  /* one octet char: 0 to 127 */
+    {
+        (*_str)++;  /* skip to next possible start of codepoint. */
+        return(octet);
+    } /* else if */
+
+    else if ((octet > 127) && (octet < 192))  /* bad (starts with 10xxxxxx). */
+    {
+        /*
+         * Apparently each of these is supposed to be flagged as a bogus
+         *  char, instead of just resyncing to the next valid codepoint.
+         */
+        (*_str)++;  /* skip to next possible start of codepoint. */
+        return UNICODE_BOGUS_CHAR_VALUE;
+    } /* else if */
+
+    else if (octet < 224)  /* two octets */
+    {
+        octet -= (128+64);
+        octet2 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet2 & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        *_str += 2;  /* skip to next possible start of codepoint. */
+        retval = ((octet << 6) | (octet2 - 128));
+        if ((retval >= 0x80) && (retval <= 0x7FF))
+            return retval;
+    } /* else if */
+
+    else if (octet < 240)  /* three octets */
+    {
+        octet -= (128+64+32);
+        octet2 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet2 & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        octet3 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet3 & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        *_str += 3;  /* skip to next possible start of codepoint. */
+        retval = ( ((octet << 12)) | ((octet2-128) << 6) | ((octet3-128)) );
+
+        /* There are seven "UTF-16 surrogates" that are illegal in UTF-8. */
+        switch (retval)
+        {
+            case 0xD800:
+            case 0xDB7F:
+            case 0xDB80:
+            case 0xDBFF:
+            case 0xDC00:
+            case 0xDF80:
+            case 0xDFFF:
+                return UNICODE_BOGUS_CHAR_VALUE;
+        } /* switch */
+
+        /* 0xFFFE and 0xFFFF are illegal, too, so we check them at the edge. */
+        if ((retval >= 0x800) && (retval <= 0xFFFD))
+            return retval;
+    } /* else if */
+
+    else if (octet < 248)  /* four octets */
+    {
+        octet -= (128+64+32+16);
+        octet2 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet2 & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        octet3 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet3 & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        octet4 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet4 & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        *_str += 4;  /* skip to next possible start of codepoint. */
+        retval = ( ((octet << 18)) | ((octet2 - 128) << 12) |
+                   ((octet3 - 128) << 6) | ((octet4 - 128)) );
+        if ((retval >= 0x10000) && (retval <= 0x10FFFF))
+            return retval;
+    } /* else if */
+
+    /*
+     * Five and six octet sequences became illegal in rfc3629.
+     *  We throw the codepoint away, but parse them to make sure we move
+     *  ahead the right number of bytes and don't overflow the buffer.
+     */
+
+    else if (octet < 252)  /* five octets */
+    {
+        octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        *_str += 5;  /* skip to next possible start of codepoint. */
+        return UNICODE_BOGUS_CHAR_VALUE;
+    } /* else if */
+
+    else  /* six octets */
+    {
+        octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        *_str += 6;  /* skip to next possible start of codepoint. */
+        return UNICODE_BOGUS_CHAR_VALUE;
+    } /* else if */
+
+    return UNICODE_BOGUS_CHAR_VALUE;
+} /* utf8codepoint */
+
+
+void PHYSFS_utf8ToUcs4(const char *src, PHYSFS_uint32 *dst, PHYSFS_uint64 len)
+{
+    len -= sizeof (PHYSFS_uint32);   /* save room for null char. */
+    while (len >= sizeof (PHYSFS_uint32))
+    {
+        PHYSFS_uint32 cp = utf8codepoint(&src);
+        if (cp == 0)
+            break;
+        else if (cp == UNICODE_BOGUS_CHAR_VALUE)
+            cp = UNICODE_BOGUS_CHAR_CODEPOINT;
+        *(dst++) = cp;
+        len -= sizeof (PHYSFS_uint32);
+    } /* while */
+
+    *dst = 0;
+} /* PHYSFS_utf8ToUcs4 */
+
+
+void PHYSFS_utf8ToUcs2(const char *src, PHYSFS_uint16 *dst, PHYSFS_uint64 len)
+{
+    len -= sizeof (PHYSFS_uint16);   /* save room for null char. */
+    while (len >= sizeof (PHYSFS_uint16))
+    {
+        PHYSFS_uint32 cp = utf8codepoint(&src);
+        if (cp == 0)
+            break;
+        else if (cp == UNICODE_BOGUS_CHAR_VALUE)
+            cp = UNICODE_BOGUS_CHAR_CODEPOINT;
+
+        /* !!! BLUESKY: UTF-16 surrogates? */
+        if (cp > 0xFFFF)
+            cp = UNICODE_BOGUS_CHAR_CODEPOINT;
+
+        *(dst++) = cp;
+        len -= sizeof (PHYSFS_uint16);
+    } /* while */
+
+    *dst = 0;
+} /* PHYSFS_utf8ToUcs2 */
+
+static void utf8fromcodepoint(PHYSFS_uint32 cp, char **_dst, PHYSFS_uint64 *_len)
+{
+    char *dst = *_dst;
+    PHYSFS_uint64 len = *_len;
+
+    if (len == 0)
+        return;
+
+    if (cp > 0x10FFFF)
+        cp = UNICODE_BOGUS_CHAR_CODEPOINT;
+    else if ((cp == 0xFFFE) || (cp == 0xFFFF))  /* illegal values. */
+        cp = UNICODE_BOGUS_CHAR_CODEPOINT;
+    else
+    {
+        /* There are seven "UTF-16 surrogates" that are illegal in UTF-8. */
+        switch (cp)
+        {
+            case 0xD800:
+            case 0xDB7F:
+            case 0xDB80:
+            case 0xDBFF:
+            case 0xDC00:
+            case 0xDF80:
+            case 0xDFFF:
+                cp = UNICODE_BOGUS_CHAR_CODEPOINT;
+        } /* switch */
+    } /* else */
+
+    /* Do the encoding... */
+    if (cp < 0x80)
+    {
+        *(dst++) = (char) cp;
+        len--;
+    } /* if */
+
+    else if (cp < 0x800)
+    {
+        if (len < 2)
+            len = 0;
+        else
+        {
+            *(dst++) = (char) ((cp >> 6) | 128 | 64);
+            *(dst++) = (char) (cp & 0x3F) | 128;
+            len -= 2;
+        } /* else */
+    } /* else if */
+
+    else if (cp < 0x10000)
+    {
+        if (len < 3)
+            len = 0;
+        else
+        {
+            *(dst++) = (char) ((cp >> 12) | 128 | 64 | 32);
+            *(dst++) = (char) ((cp >> 6) & 0x3F) | 128;
+            *(dst++) = (char) (cp & 0x3F) | 128;
+            len -= 3;
+        } /* else */
+    } /* else if */
+
+    else
+    {
+        if (len < 4)
+            len = 0;
+        else
+        {
+            *(dst++) = (char) ((cp >> 18) | 128 | 64 | 32 | 16);
+            *(dst++) = (char) ((cp >> 12) & 0x3F) | 128;
+            *(dst++) = (char) ((cp >> 6) & 0x3F) | 128;
+            *(dst++) = (char) (cp & 0x3F) | 128;
+            len -= 4;
+        } /* else if */
+    } /* else */
+
+    *_dst = dst;
+    *_len = len;
+} /* utf8fromcodepoint */
+
+#define UTF8FROMTYPE(typ, src, dst, len) \
+    len--;  \
+    while (len) \
+    { \
+        const PHYSFS_uint32 cp = (PHYSFS_uint32) *(src++); \
+        if (cp == 0) break; \
+        utf8fromcodepoint(cp, &dst, &len); \
+    } \
+    *dst = '\0'; \
+
+void PHYSFS_utf8FromUcs4(const PHYSFS_uint32 *src, char *dst, PHYSFS_uint64 len)
+{
+    UTF8FROMTYPE(PHYSFS_uint32, src, dst, len);
+} /* PHYSFS_utf8FromUcs4 */
+
+void PHYSFS_utf8FromUcs2(const PHYSFS_uint16 *src, char *dst, PHYSFS_uint64 len)
+{
+    UTF8FROMTYPE(PHYSFS_uint64, src, dst, len);
+} /* PHYSFS_utf8FromUcs4 */
+
+/* latin1 maps to unicode codepoints directly, we just utf-8 encode it. */
+void PHYSFS_utf8FromLatin1(const char *src, char *dst, PHYSFS_uint64 len)
+{
+    UTF8FROMTYPE(PHYSFS_uint8, src, dst, len);
+} /* PHYSFS_utf8FromLatin1 */
+
+#undef UTF8FROMTYPE
+
+
+typedef struct CaseFoldMapping
+{
+    PHYSFS_uint32 from;
+    PHYSFS_uint32 to0;
+    PHYSFS_uint32 to1;
+    PHYSFS_uint32 to2;
+} CaseFoldMapping;
+
+typedef struct CaseFoldHashBucket
+{
+    const PHYSFS_uint8 count;
+    const CaseFoldMapping *list;
+} CaseFoldHashBucket;
+
+#include "physfs_casefolding.h"
+
+static void locate_case_fold_mapping(const PHYSFS_uint32 from,
+                                     PHYSFS_uint32 *to)
+{
+    PHYSFS_uint32 i;
+    const PHYSFS_uint8 hashed = ((from ^ (from >> 8)) & 0xFF);
+    const CaseFoldHashBucket *bucket = &case_fold_hash[hashed];
+    const CaseFoldMapping *mapping = bucket->list;
+
+    for (i = 0; i < bucket->count; i++, mapping++)
+    {
+        if (mapping->from == from)
+        {
+            to[0] = mapping->to0;
+            to[1] = mapping->to1;
+            to[2] = mapping->to2;
+            return;
+        } /* if */
+    } /* for */
+
+    /* Not found...there's no remapping for this codepoint. */
+    to[0] = from;
+    to[1] = 0;
+    to[2] = 0;
+} /* locate_case_fold_mapping */
+
+
+static int utf8codepointcmp(const PHYSFS_uint32 cp1, const PHYSFS_uint32 cp2)
+{
+    PHYSFS_uint32 folded1[3], folded2[3];
+    locate_case_fold_mapping(cp1, folded1);
+    locate_case_fold_mapping(cp2, folded2);
+    return ( (folded1[0] == folded2[0]) &&
+             (folded1[1] == folded2[1]) &&
+             (folded1[2] == folded2[2]) );
+} /* utf8codepointcmp */
+
+
+int __PHYSFS_utf8strcasecmp(const char *str1, const char *str2)
+{
+    while (1)
+    {
+        const PHYSFS_uint32 cp1 = utf8codepoint(&str1);
+        const PHYSFS_uint32 cp2 = utf8codepoint(&str2);
+        if (!utf8codepointcmp(cp1, cp2)) return 0;
+        if (cp1 == 0) return 1;
+    } /* while */
+
+    return 0;  /* shouldn't hit this. */
+} /* __PHYSFS_utf8strcasecmp */
+
+
+int __PHYSFS_utf8strnicmp(const char *str1, const char *str2, PHYSFS_uint32 n)
+{
+    while (n > 0)
+    {
+        const PHYSFS_uint32 cp1 = utf8codepoint(&str1);
+        const PHYSFS_uint32 cp2 = utf8codepoint(&str2);
+        if (!utf8codepointcmp(cp1, cp2)) return 0;
+        if (cp1 == 0) return 1;
+        n--;
+    } /* while */
+
+    return 1;  /* matched to n chars. */
+} /* __PHYSFS_utf8strnicmp */
+
+
+int __PHYSFS_stricmpASCII(const char *str1, const char *str2)
+{
+    while (1)
+    {
+        const char ch1 = *(str1++);
+        const char ch2 = *(str2++);
+        const char cp1 = ((ch1 >= 'A') && (ch1 <= 'Z')) ? (ch1+32) : ch1;
+        const char cp2 = ((ch2 >= 'A') && (ch2 <= 'Z')) ? (ch2+32) : ch2;
+        if (cp1 < cp2)
+            return -1;
+        else if (cp1 > cp2)
+            return 1;
+        else if (cp1 == 0)  /* they're both null chars? */
+            return 0;
+    } /* while */
+
+    return 0;  /* shouldn't hit this. */
+} /* __PHYSFS_stricmpASCII */
+
+
+int __PHYSFS_strnicmpASCII(const char *str1, const char *str2, PHYSFS_uint32 n)
+{
+    while (n-- > 0)
+    {
+        const char ch1 = *(str1++);
+        const char ch2 = *(str2++);
+        const char cp1 = ((ch1 >= 'A') && (ch1 <= 'Z')) ? (ch1+32) : ch1;
+        const char cp2 = ((ch2 >= 'A') && (ch2 <= 'Z')) ? (ch2+32) : ch2;
+        if (cp1 < cp2)
+            return -1;
+        else if (cp1 > cp2)
+            return 1;
+        else if (cp1 == 0)  /* they're both null chars? */
+            return 0;
+    } /* while */
+
+    return 0;
+} /* __PHYSFS_stricmpASCII */
+
+
+/* end of physfs_unicode.c ... */
+
diff --git a/src/unison/physfs-1.1.1/platform/beos.cpp b/src/unison/physfs-1.1.1/platform/beos.cpp
new file mode 100644 (file)
index 0000000..aac27eb
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * BeOS platform-dependent support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_platforms.h"
+
+#ifdef PHYSFS_PLATFORM_BEOS
+
+#include <be/kernel/OS.h>
+#include <be/app/Roster.h>
+#include <be/storage/Volume.h>
+#include <be/storage/VolumeRoster.h>
+#include <be/storage/Directory.h>
+#include <be/storage/Entry.h>
+#include <be/storage/Path.h>
+#include <be/kernel/fs_info.h>
+#include <be/device/scsi.h>
+#include <be/support/Locker.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "physfs_internal.h"
+
+
+int __PHYSFS_platformInit(void)
+{
+    return(1);  /* always succeed. */
+} /* __PHYSFS_platformInit */
+
+
+int __PHYSFS_platformDeinit(void)
+{
+    return(1);  /* always succeed. */
+} /* __PHYSFS_platformDeinit */
+
+
+static char *getMountPoint(const char *devname)
+{
+    BVolumeRoster mounts;
+    BVolume vol;
+
+    mounts.Rewind();
+    while (mounts.GetNextVolume(&vol) == B_NO_ERROR)
+    {
+        fs_info fsinfo;
+        fs_stat_dev(vol.Device(), &fsinfo);
+        if (strcmp(devname, fsinfo.device_name) == 0)
+        {
+            //char buf[B_FILE_NAME_LENGTH];
+            BDirectory directory;
+            BEntry entry;
+            BPath path;
+            status_t rc;
+            rc = vol.GetRootDirectory(&directory);
+            BAIL_IF_MACRO(rc < B_OK, strerror(rc), NULL);
+            rc = directory.GetEntry(&entry);
+            BAIL_IF_MACRO(rc < B_OK, strerror(rc), NULL);
+            rc = entry.GetPath(&path);
+            BAIL_IF_MACRO(rc < B_OK, strerror(rc), NULL);
+            const char *str = path.Path();
+            BAIL_IF_MACRO(str == NULL, ERR_OS_ERROR, NULL);  /* ?! */
+            char *retval = (char *) allocator.Malloc(strlen(str) + 1);
+            BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+            strcpy(retval, str);
+            return(retval);
+        } /* if */
+    } /* while */
+
+    return(NULL);
+} /* getMountPoint */
+
+
+    /*
+     * This function is lifted from Simple Directmedia Layer (SDL):
+     *  http://www.libsdl.org/
+     */
+static void tryDir(const char *d, PHYSFS_StringCallback callback, void *data)
+{
+    BDirectory dir;
+    dir.SetTo(d);
+    if (dir.InitCheck() != B_NO_ERROR)
+        return;
+
+    dir.Rewind();
+    BEntry entry;
+    while (dir.GetNextEntry(&entry) >= 0)
+    {
+        BPath path;
+        const char *name;
+        entry_ref e;
+
+        if (entry.GetPath(&path) != B_NO_ERROR)
+            continue;
+
+        name = path.Path();
+
+        if (entry.GetRef(&e) != B_NO_ERROR)
+            continue;
+
+        if (entry.IsDirectory())
+        {
+            if (strcmp(e.name, "floppy") != 0)
+                tryDir(name, callback, data);
+        } /* if */
+
+        else
+        {
+            bool add_it = false;
+            int devfd;
+            device_geometry g;
+
+            if (strcmp(e.name, "raw") == 0)  /* ignore partitions. */
+            {
+                int devfd = open(name, O_RDONLY);
+                if (devfd >= 0)
+                {
+                    if (ioctl(devfd, B_GET_GEOMETRY, &g, sizeof(g)) >= 0)
+                    {
+                        if (g.device_type == B_CD)
+                        {
+                            char *mntpnt = getMountPoint(name);
+                            if (mntpnt != NULL)
+                            {
+                                callback(data, mntpnt);
+                                allocator.Free(mntpnt);  /* !!! FIXME: lose this malloc! */
+                            } /* if */
+                        } /* if */
+                    } /* if */
+                } /* if */
+            } /* if */
+
+            close(devfd);
+        } /* else */
+    } /* while */
+} /* tryDir */
+
+
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
+{
+    tryDir("/dev/disk", cb, data);
+} /* __PHYSFS_platformDetectAvailableCDs */
+
+
+static team_id getTeamID(void)
+{
+    thread_info info;
+    thread_id tid = find_thread(NULL);
+    get_thread_info(tid, &info);
+    return(info.team);
+} /* getTeamID */
+
+
+char *__PHYSFS_platformCalcBaseDir(const char *argv0)
+{
+    /* in case there isn't a BApplication yet, we'll construct a roster. */
+    BRoster roster; 
+    app_info info;
+    status_t rc = roster.GetRunningAppInfo(getTeamID(), &info);
+    BAIL_IF_MACRO(rc < B_OK, strerror(rc), NULL);
+    BEntry entry(&(info.ref), true);
+    BPath path;
+    rc = entry.GetPath(&path);  /* (path) now has binary's path. */
+    assert(rc == B_OK);
+    rc = path.GetParent(&path); /* chop filename, keep directory. */
+    assert(rc == B_OK);
+    const char *str = path.Path();
+    assert(str != NULL);
+    char *retval = (char *) allocator.Malloc(strlen(str) + 1);
+    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+    strcpy(retval, str);
+    return(retval);
+} /* __PHYSFS_platformCalcBaseDir */
+
+
+PHYSFS_uint64 __PHYSFS_platformGetThreadID(void)
+{
+    return((PHYSFS_uint64) find_thread(NULL));
+} /* __PHYSFS_platformGetThreadID */
+
+
+char *__PHYSFS_platformRealPath(const char *path)
+{
+    BPath normalized(path, NULL, true);  /* force normalization of path. */
+    const char *resolved_path = normalized.Path();
+    BAIL_IF_MACRO(resolved_path == NULL, ERR_NO_SUCH_FILE, NULL);
+    char *retval = (char *) allocator.Malloc(strlen(resolved_path) + 1);
+    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+    strcpy(retval, resolved_path);
+    return(retval);
+} /* __PHYSFS_platformRealPath */
+
+
+char *__PHYSFS_platformCurrentDir(void)
+{
+    return(__PHYSFS_platformRealPath("."));  /* let BPath sort it out. */
+} /* __PHYSFS_platformCurrentDir */
+
+
+void *__PHYSFS_platformCreateMutex(void)
+{
+    return(new BLocker("PhysicsFS lock", true));
+} /* __PHYSFS_platformCreateMutex */
+
+
+void __PHYSFS_platformDestroyMutex(void *mutex)
+{
+    delete ((BLocker *) mutex);
+} /* __PHYSFS_platformDestroyMutex */
+
+
+int __PHYSFS_platformGrabMutex(void *mutex)
+{
+    return ((BLocker *) mutex)->Lock() ? 1 : 0;
+} /* __PHYSFS_platformGrabMutex */
+
+
+void __PHYSFS_platformReleaseMutex(void *mutex)
+{
+    ((BLocker *) mutex)->Unlock();
+} /* __PHYSFS_platformReleaseMutex */
+
+
+int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
+{
+    return(0);  /* just use malloc() and friends. */
+} /* __PHYSFS_platformSetDefaultAllocator */
+
+#endif  /* PHYSFS_PLATFORM_BEOS */
+
+/* end of beos.cpp ... */
+
diff --git a/src/unison/physfs-1.1.1/platform/macosx.c b/src/unison/physfs-1.1.1/platform/macosx.c
new file mode 100644 (file)
index 0000000..4dde270
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * Mac OS X support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_platforms.h"
+
+#ifdef PHYSFS_PLATFORM_MACOSX
+
+#include <Carbon/Carbon.h>
+#include <IOKit/storage/IOMedia.h>
+#include <IOKit/storage/IOCDMedia.h>
+#include <IOKit/storage/IODVDMedia.h>
+#include <sys/mount.h>
+
+/* Seems to get defined in some system header... */
+#ifdef Free
+#undef Free
+#endif
+
+#include "physfs_internal.h"
+
+
+/* Wrap PHYSFS_Allocator in a CFAllocator... */
+static CFAllocatorRef cfallocator = NULL;
+
+CFStringRef cfallocDesc(const void *info)
+{
+    return(CFStringCreateWithCString(cfallocator, "PhysicsFS",
+                                     kCFStringEncodingASCII));
+} /* cfallocDesc */
+
+
+static void *cfallocMalloc(CFIndex allocSize, CFOptionFlags hint, void *info)
+{
+    return allocator.Malloc(allocSize);
+} /* cfallocMalloc */
+
+
+static void cfallocFree(void *ptr, void *info)
+{
+    allocator.Free(ptr);
+} /* cfallocFree */
+
+
+static void *cfallocRealloc(void *ptr, CFIndex newsize,
+                            CFOptionFlags hint, void *info)
+{
+    if ((ptr == NULL) || (newsize <= 0))
+        return NULL;  /* ADC docs say you should always return NULL here. */
+    return allocator.Realloc(ptr, newsize);
+} /* cfallocRealloc */
+
+
+int __PHYSFS_platformInit(void)
+{
+    /* set up a CFAllocator, so Carbon can use the physfs allocator, too. */
+    CFAllocatorContext ctx;
+    memset(&ctx, '\0', sizeof (ctx));
+    ctx.copyDescription = cfallocDesc;
+    ctx.allocate = cfallocMalloc;
+    ctx.reallocate = cfallocRealloc;
+    ctx.deallocate = cfallocFree;
+    cfallocator = CFAllocatorCreate(kCFAllocatorUseContext, &ctx);
+    BAIL_IF_MACRO(cfallocator == NULL, ERR_OUT_OF_MEMORY, 0);
+    return(1);  /* success. */
+} /* __PHYSFS_platformInit */
+
+
+int __PHYSFS_platformDeinit(void)
+{
+    CFRelease(cfallocator);
+    cfallocator = NULL;
+    return(1);  /* always succeed. */
+} /* __PHYSFS_platformDeinit */
+
+
+/* CD-ROM detection code... */
+
+/*
+ * Code based on sample from Apple Developer Connection:
+ *  http://developer.apple.com/samplecode/Sample_Code/Devices_and_Hardware/Disks/VolumeToBSDNode/VolumeToBSDNode.c.htm
+ */
+
+static int darwinIsWholeMedia(io_service_t service)
+{
+    int retval = 0;
+    CFTypeRef wholeMedia;
+
+    if (!IOObjectConformsTo(service, kIOMediaClass))
+        return(0);
+        
+    wholeMedia = IORegistryEntryCreateCFProperty(service,
+                                                 CFSTR(kIOMediaWholeKey),
+                                                 cfallocator, 0);
+    if (wholeMedia == NULL)
+        return(0);
+
+    retval = CFBooleanGetValue(wholeMedia);
+    CFRelease(wholeMedia);
+
+    return retval;
+} /* darwinIsWholeMedia */
+
+
+static int darwinIsMountedDisc(char *bsdName, mach_port_t masterPort)
+{
+    int retval = 0;
+    CFMutableDictionaryRef matchingDict;
+    kern_return_t rc;
+    io_iterator_t iter;
+    io_service_t service;
+
+    if ((matchingDict = IOBSDNameMatching(masterPort, 0, bsdName)) == NULL)
+        return(0);
+
+    rc = IOServiceGetMatchingServices(masterPort, matchingDict, &iter);
+    if ((rc != KERN_SUCCESS) || (!iter))
+        return(0);
+
+    service = IOIteratorNext(iter);
+    IOObjectRelease(iter);
+    if (!service)
+        return(0);
+
+    rc = IORegistryEntryCreateIterator(service, kIOServicePlane,
+             kIORegistryIterateRecursively | kIORegistryIterateParents, &iter);
+    
+    if (!iter)
+        return(0);
+
+    if (rc != KERN_SUCCESS)
+    {
+        IOObjectRelease(iter);
+        return(0);
+    } /* if */
+
+    IOObjectRetain(service);  /* add an extra object reference... */
+
+    do
+    {
+        if (darwinIsWholeMedia(service))
+        {
+            if ( (IOObjectConformsTo(service, kIOCDMediaClass)) ||
+                 (IOObjectConformsTo(service, kIODVDMediaClass)) )
+            {
+                retval = 1;
+            } /* if */
+        } /* if */
+        IOObjectRelease(service);
+    } while ((service = IOIteratorNext(iter)) && (!retval));
+                
+    IOObjectRelease(iter);
+    IOObjectRelease(service);
+
+    return(retval);
+} /* darwinIsMountedDisc */
+
+
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
+{
+    const char *devPrefix = "/dev/";
+    const int prefixLen = strlen(devPrefix);
+    mach_port_t masterPort = 0;
+    struct statfs *mntbufp;
+    int i, mounts;
+
+    if (IOMasterPort(MACH_PORT_NULL, &masterPort) != KERN_SUCCESS)
+        BAIL_MACRO(ERR_OS_ERROR, ) /*return void*/;
+
+    mounts = getmntinfo(&mntbufp, MNT_WAIT);  /* NOT THREAD SAFE! */
+    for (i = 0; i < mounts; i++)
+    {
+        char *dev = mntbufp[i].f_mntfromname;
+        char *mnt = mntbufp[i].f_mntonname;
+        if (strncmp(dev, devPrefix, prefixLen) != 0)  /* a virtual device? */
+            continue;
+
+        dev += prefixLen;
+        if (darwinIsMountedDisc(dev, masterPort))
+            cb(data, mnt);
+    } /* for */
+} /* __PHYSFS_platformDetectAvailableCDs */
+
+
+static char *convertCFString(CFStringRef cfstr)
+{
+    CFIndex len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr),
+                                                    kCFStringEncodingUTF8) + 1;
+    char *retval = (char *) allocator.Malloc(len);
+    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+    if (CFStringGetCString(cfstr, retval, len, kCFStringEncodingUTF8))
+    {
+        /* shrink overallocated buffer if possible... */
+        CFIndex newlen = strlen(retval) + 1;
+        if (newlen < len)
+        {
+            void *ptr = allocator.Realloc(retval, newlen);
+            if (ptr != NULL)
+                retval = (char *) ptr;
+        } /* if */
+    } /* if */
+
+    else  /* probably shouldn't fail, but just in case... */
+    {
+        allocator.Free(retval);
+        BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
+    } /* else */
+
+    return(retval);
+} /* convertCFString */
+
+
+char *__PHYSFS_platformCalcBaseDir(const char *argv0)
+{
+    ProcessSerialNumber psn = { 0, kCurrentProcess };
+    FSRef fsref;
+    CFRange cfrange;
+    CFURLRef cfurl = NULL;
+    CFStringRef cfstr = NULL;
+    CFMutableStringRef cfmutstr = NULL;
+    char *retval = NULL;
+
+    BAIL_IF_MACRO(GetProcessBundleLocation(&psn, &fsref) != noErr, NULL, NULL);
+    cfurl = CFURLCreateFromFSRef(cfallocator, &fsref);
+    BAIL_IF_MACRO(cfurl == NULL, NULL, NULL);
+    cfstr = CFURLCopyFileSystemPath(cfurl, kCFURLPOSIXPathStyle);
+    CFRelease(cfurl);
+    BAIL_IF_MACRO(cfstr == NULL, NULL, NULL);
+    cfmutstr = CFStringCreateMutableCopy(cfallocator, 0, cfstr);
+    CFRelease(cfstr);
+    BAIL_IF_MACRO(cfmutstr == NULL, NULL, NULL);
+
+    /* Find last dirsep so we can chop the binary's filename from the path. */
+    cfrange = CFStringFind(cfmutstr, CFSTR("/"), kCFCompareBackwards);
+    if (cfrange.location == kCFNotFound)
+    {
+        assert(0);  /* shouldn't ever hit this... */
+        CFRelease(cfmutstr);
+        return(NULL);
+    } /* if */
+
+    /* chop the "/exename" from the end of the path string... */
+    cfrange.length = CFStringGetLength(cfmutstr) - cfrange.location;
+    CFStringDelete(cfmutstr, cfrange);
+
+    /* If we're an Application Bundle, chop everything but the base. */
+    cfrange = CFStringFind(cfmutstr, CFSTR("/Contents/MacOS"),
+                           kCFCompareCaseInsensitive |
+                           kCFCompareBackwards |
+                           kCFCompareAnchored);
+
+    if (cfrange.location != kCFNotFound)
+        CFStringDelete(cfmutstr, cfrange);  /* chop that, too. */
+
+    retval = convertCFString(cfmutstr);
+    CFRelease(cfmutstr);
+
+    return(retval);  /* whew. */
+} /* __PHYSFS_platformCalcBaseDir */
+
+
+/* !!! FIXME */
+#define osxerr(x) x
+
+char *__PHYSFS_platformRealPath(const char *path)
+{
+    /* The symlink and relative path resolving happens in FSPathMakeRef() */
+    FSRef fsref;
+    CFURLRef cfurl = NULL;
+    CFStringRef cfstr = NULL;
+    char *retval = NULL;
+    OSStatus rc = osxerr(FSPathMakeRef((UInt8 *) path, &fsref, NULL));
+    BAIL_IF_MACRO(rc != noErr, NULL, NULL);
+
+    /* Now get it to spit out a full path. */
+    cfurl = CFURLCreateFromFSRef(cfallocator, &fsref);
+    BAIL_IF_MACRO(cfurl == NULL, ERR_OUT_OF_MEMORY, NULL);
+    cfstr = CFURLCopyFileSystemPath(cfurl, kCFURLPOSIXPathStyle);
+    CFRelease(cfurl);
+    BAIL_IF_MACRO(cfstr == NULL, ERR_OUT_OF_MEMORY, NULL);
+    retval = convertCFString(cfstr);
+    CFRelease(cfstr);
+
+    return(retval);
+} /* __PHYSFS_platformRealPath */
+
+
+char *__PHYSFS_platformCurrentDir(void)
+{
+    return(__PHYSFS_platformRealPath("."));  /* let CFURL sort it out. */
+} /* __PHYSFS_platformCurrentDir */
+
+
+/* Platform allocator uses default CFAllocator at PHYSFS_init() time. */
+
+static CFAllocatorRef cfallocdef = NULL;
+
+static int macosxAllocatorInit(void)
+{
+    int retval = 0;
+    cfallocdef = CFAllocatorGetDefault();
+    retval = (cfallocdef != NULL);
+    if (retval)
+        CFRetain(cfallocdef);
+    return(retval);
+} /* macosxAllocatorInit */
+
+
+static void macosxAllocatorDeinit(void)
+{
+    if (cfallocdef != NULL)
+    {
+        CFRelease(cfallocdef);
+        cfallocdef = NULL;
+    } /* if */
+} /* macosxAllocatorDeinit */
+
+
+static void *macosxAllocatorMalloc(PHYSFS_uint64 s)
+{
+    BAIL_IF_MACRO(__PHYSFS_ui64FitsAddressSpace(s), ERR_OUT_OF_MEMORY, NULL);
+    return(CFAllocatorAllocate(cfallocdef, (CFIndex) s, 0));
+} /* macosxAllocatorMalloc */
+
+
+static void *macosxAllocatorRealloc(void *ptr, PHYSFS_uint64 s)
+{
+    BAIL_IF_MACRO(__PHYSFS_ui64FitsAddressSpace(s), ERR_OUT_OF_MEMORY, NULL);
+    return(CFAllocatorReallocate(cfallocdef, ptr, (CFIndex) s, 0));
+} /* macosxAllocatorRealloc */
+
+
+static void macosxAllocatorFree(void *ptr)
+{
+    CFAllocatorDeallocate(cfallocdef, ptr);
+} /* macosxAllocatorFree */
+
+
+int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
+{
+    allocator.Init = macosxAllocatorInit;
+    allocator.Deinit = macosxAllocatorDeinit;
+    allocator.Malloc = macosxAllocatorMalloc;
+    allocator.Realloc = macosxAllocatorRealloc;
+    allocator.Free = macosxAllocatorFree;
+    return(1);  /* return non-zero: we're supplying custom allocator. */
+} /* __PHYSFS_platformSetDefaultAllocator */
+
+
+PHYSFS_uint64 __PHYSFS_platformGetThreadID(void)
+{
+    return( (PHYSFS_uint64) ((size_t) MPCurrentTaskID()) );
+} /* __PHYSFS_platformGetThreadID */
+
+
+void *__PHYSFS_platformCreateMutex(void)
+{
+    MPCriticalRegionID m = NULL;
+    if (osxerr(MPCreateCriticalRegion(&m)) != noErr)
+        return NULL;
+    return m;
+} /* __PHYSFS_platformCreateMutex */
+
+
+void __PHYSFS_platformDestroyMutex(void *mutex)
+{
+    MPCriticalRegionID m = (MPCriticalRegionID) mutex;
+    MPDeleteCriticalRegion(m);
+} /* __PHYSFS_platformDestroyMutex */
+
+
+int __PHYSFS_platformGrabMutex(void *mutex)
+{
+    MPCriticalRegionID m = (MPCriticalRegionID) mutex;
+    if (MPEnterCriticalRegion(m, kDurationForever) != noErr)
+        return(0);
+    return(1);
+} /* __PHYSFS_platformGrabMutex */
+
+
+void __PHYSFS_platformReleaseMutex(void *mutex)
+{
+    MPCriticalRegionID m = (MPCriticalRegionID) mutex;
+    MPExitCriticalRegion(m);
+} /* __PHYSFS_platformReleaseMutex */
+
+#endif /* PHYSFS_PLATFORM_MACOSX */
+
+/* end of macosx.c ... */
+
diff --git a/src/unison/physfs-1.1.1/platform/os2.c b/src/unison/physfs-1.1.1/platform/os2.c
new file mode 100644 (file)
index 0000000..0fe2308
--- /dev/null
@@ -0,0 +1,702 @@
+/*
+ * OS/2 support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_platforms.h"
+
+#ifdef PHYSFS_PLATFORM_OS2
+
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSDATETIME
+#define INCL_DOSFILEMGR
+#define INCL_DOSMODULEMGR
+#define INCL_DOSERRORS
+#define INCL_DOSPROCESS
+#define INCL_DOSDEVICES
+#define INCL_DOSDEVIOCTL
+#define INCL_DOSMISC
+#include <os2.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+
+#include "physfs_internal.h"
+
+const char *__PHYSFS_platformDirSeparator = "\\";
+
+
+static const char *get_os2_error_string(APIRET rc)
+{
+    switch (rc)
+    {
+        case NO_ERROR: return(NULL);  /* not an error. */
+        case ERROR_INTERRUPT: return(NULL);  /* not an error. */
+        case ERROR_TIMEOUT: return(NULL);  /* not an error. */
+        case ERROR_NOT_ENOUGH_MEMORY: return(ERR_OUT_OF_MEMORY);
+        case ERROR_FILE_NOT_FOUND: return(ERR_NO_SUCH_FILE);
+        case ERROR_PATH_NOT_FOUND: return(ERR_NO_SUCH_PATH);
+        case ERROR_ACCESS_DENIED: return(ERR_ACCESS_DENIED);
+        case ERROR_NOT_DOS_DISK: return(ERR_NOT_A_DOS_DISK);
+        case ERROR_SHARING_VIOLATION: return(ERR_SHARING_VIOLATION);
+        case ERROR_CANNOT_MAKE: return(ERR_CANNOT_MAKE);
+        case ERROR_DEVICE_IN_USE: return(ERR_DEV_IN_USE);
+        case ERROR_OPEN_FAILED: return(ERR_OPEN_FAILED);
+        case ERROR_DISK_FULL: return(ERR_DISK_FULL);
+        case ERROR_PIPE_BUSY: return(ERR_PIPE_BUSY);
+        case ERROR_SHARING_BUFFER_EXCEEDED: return(ERR_SHARING_BUF_EXCEEDED);
+        case ERROR_FILENAME_EXCED_RANGE: return(ERR_BAD_FILENAME);
+        case ERROR_META_EXPANSION_TOO_LONG: return(ERR_BAD_FILENAME);
+        case ERROR_TOO_MANY_HANDLES: return(ERR_TOO_MANY_HANDLES);
+        case ERROR_TOO_MANY_OPEN_FILES: return(ERR_TOO_MANY_HANDLES);
+        case ERROR_NO_MORE_SEARCH_HANDLES: return(ERR_TOO_MANY_HANDLES);
+        case ERROR_SEEK_ON_DEVICE: return(ERR_SEEK_ERROR);
+        case ERROR_NEGATIVE_SEEK: return(ERR_SEEK_OUT_OF_RANGE);
+        /*!!! FIXME: Where did this go?  case ERROR_DEL_CURRENT_DIRECTORY: return(ERR_DEL_CWD);*/
+        case ERROR_WRITE_PROTECT: return(ERR_WRITE_PROTECT_ERROR);
+        case ERROR_WRITE_FAULT: return(ERR_WRITE_FAULT);
+        case ERROR_LOCK_VIOLATION: return(ERR_LOCK_VIOLATION);
+        case ERROR_GEN_FAILURE: return(ERR_GEN_FAILURE);
+        case ERROR_UNCERTAIN_MEDIA: return(ERR_UNCERTAIN_MEDIA);
+        case ERROR_PROTECTION_VIOLATION: return(ERR_PROT_VIOLATION);
+        case ERROR_BROKEN_PIPE: return(ERR_BROKEN_PIPE);
+
+        case ERROR_INVALID_PARAMETER:
+        case ERROR_INVALID_NAME:
+        case ERROR_INVALID_DRIVE:
+        case ERROR_INVALID_HANDLE:
+        case ERROR_INVALID_FUNCTION:
+        case ERROR_INVALID_LEVEL:
+        case ERROR_INVALID_CATEGORY:
+        case ERROR_DUPLICATE_NAME:
+        case ERROR_BUFFER_OVERFLOW:
+        case ERROR_BAD_LENGTH:
+        case ERROR_BAD_DRIVER_LEVEL:
+        case ERROR_DIRECT_ACCESS_HANDLE:
+        case ERROR_NOT_OWNER:
+            return(ERR_PHYSFS_BAD_OS_CALL);
+
+        default: return(ERR_OS2_GENERIC);
+    } /* switch */
+
+    return(NULL);
+} /* get_os2_error_string */
+
+
+static APIRET os2err(APIRET retval)
+{
+    char buf[128];
+    const char *err = get_os2_error_string(retval);
+    if (err == ERR_OS2_GENERIC)
+    {
+        snprintf(buf, sizeof (buf), ERR_OS2_GENERIC, (int) retval);
+        err = buf;
+    } /* if */
+
+    if (err != NULL)
+        __PHYSFS_setError(err);
+
+    return(retval);
+} /* os2err */
+
+
+/* (be gentle, this function isn't very robust.) */
+static void cvt_path_to_correct_case(char *buf)
+{
+    char *fname = buf + 3;            /* point to first element. */
+    char *ptr = strchr(fname, '\\');  /* find end of first element. */
+
+    buf[0] = toupper(buf[0]);  /* capitalize drive letter. */
+
+    /*
+     * Go through each path element, and enumerate its parent dir until
+     *  a case-insensitive match is found. If one is (and it SHOULD be)
+     *  then overwrite the original element with the correct case.
+     * If there's an error, or the path has vanished for some reason, it
+     *  won't hurt to have the original case, so we just keep going.
+     */
+    while (fname != NULL)
+    {
+        char spec[CCHMAXPATH];
+        FILEFINDBUF3 fb;
+        HDIR hdir = HDIR_CREATE;
+        ULONG count = 1;
+        APIRET rc;
+
+        *(fname - 1) = '\0';  /* isolate parent dir string. */
+
+        strcpy(spec, buf);      /* copy isolated parent dir... */
+        strcat(spec, "\\*.*");  /*  ...and add wildcard search spec. */
+
+        if (ptr != NULL)  /* isolate element to find (fname is the start). */
+            *ptr = '\0';
+
+        rc = DosFindFirst(spec, &hdir, FILE_DIRECTORY,
+                          &fb, sizeof (fb), &count, FIL_STANDARD);
+        if (rc == NO_ERROR)
+        {
+            while (count == 1)  /* while still entries to enumerate... */
+            {
+                if (__PHYSFS_stricmpASCII(fb.achName, fname) == 0)
+                {
+                    strcpy(fname, fb.achName);
+                    break;  /* there it is. Overwrite and stop searching. */
+                } /* if */
+
+                DosFindNext(hdir, &fb, sizeof (fb), &count);
+            } /* while */
+            DosFindClose(hdir);
+        } /* if */
+
+        *(fname - 1) = '\\';   /* unisolate parent dir. */
+        fname = ptr;           /* point to next element. */
+        if (ptr != NULL)
+        {
+            *ptr = '\\';       /* unisolate element. */
+            ptr = strchr(++fname, '\\');  /* find next element. */
+        } /* if */
+    } /* while */
+} /* cvt_file_to_correct_case */
+
+
+static char *baseDir = NULL;
+
+int __PHYSFS_platformInit(void)
+{
+    char buf[CCHMAXPATH];
+    APIRET rc;
+    PTIB ptib;
+    PPIB ppib;
+    PHYSFS_sint32 len;
+
+    assert(baseDir == NULL);
+    BAIL_IF_MACRO(os2err(DosGetInfoBlocks(&ptib, &ppib)) != NO_ERROR, NULL, 0);
+    rc = DosQueryModuleName(ppib->pib_hmte, sizeof (buf), (PCHAR) buf);
+    BAIL_IF_MACRO(os2err(rc) != NO_ERROR, NULL, 0);
+
+    /* chop off filename, leave path. */
+    for (len = strlen(buf) - 1; len >= 0; len--)
+    {
+        if (buf[len] == '\\')
+        {
+            buf[len] = '\0';
+            break;
+        } /* if */
+    } /* for */
+
+    assert(len > 0);  /* should have been a "x:\\" on the front on string. */
+
+    /* The string is capitalized! Figure out the REAL case... */
+    cvt_path_to_correct_case(buf);
+
+    baseDir = (char *) allocator.Malloc(len + 1);
+    BAIL_IF_MACRO(baseDir == NULL, ERR_OUT_OF_MEMORY, 0);
+    strcpy(baseDir, buf);
+    return(1);  /* success. */
+} /* __PHYSFS_platformInit */
+
+
+int __PHYSFS_platformDeinit(void)
+{
+    assert(baseDir != NULL);
+    allocator.Free(baseDir);
+    baseDir = NULL;
+    return(1);  /* success. */
+} /* __PHYSFS_platformDeinit */
+
+
+static int disc_is_inserted(ULONG drive)
+{
+    int rc;
+    char buf[20];
+    DosError(FERR_DISABLEHARDERR | FERR_DISABLEEXCEPTION);
+    rc = DosQueryFSInfo(drive + 1, FSIL_VOLSER, buf, sizeof (buf));
+    DosError(FERR_ENABLEHARDERR | FERR_ENABLEEXCEPTION);
+    return(rc == NO_ERROR);
+} /* is_cdrom_inserted */
+
+
+/* looks like "CD01" in ASCII (littleendian)...used for an ioctl. */
+#define CD01 0x31304443
+
+static int is_cdrom_drive(ULONG drive)
+{
+    PHYSFS_uint32 param, data;
+    ULONG ul1, ul2;
+    APIRET rc;
+    HFILE hfile = NULLHANDLE;
+    char drivename[3] = { 'A' + drive, ':', '\0' };
+
+    rc = DosOpen(drivename, &hfile, &ul1, 0, 0,
+                 OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW,
+                 OPEN_FLAGS_DASD | OPEN_FLAGS_FAIL_ON_ERROR |
+                 OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYNONE, NULL);
+    BAIL_IF_MACRO(rc != NO_ERROR, NULL, 0);
+
+    data = 0;
+    param = PHYSFS_swapULE32(CD01);
+    ul1 = ul2 = sizeof (PHYSFS_uint32);
+    rc = DosDevIOCtl(hfile, IOCTL_CDROMDISK, CDROMDISK_GETDRIVER,
+                     &param, sizeof (param), &ul1, &data, sizeof (data), &ul2);
+
+    DosClose(hfile);
+    return((rc == NO_ERROR) && (PHYSFS_swapULE32(data) == CD01));
+} /* is_cdrom_drive */
+
+
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
+{
+    ULONG dummy = 0;
+    ULONG drivemap = 0;
+    ULONG i, bit;
+    APIRET rc = DosQueryCurrentDisk(&dummy, &drivemap);
+    if (os2err(rc) != NO_ERROR)
+        return;
+
+    for (i = 0, bit = 1; i < 26; i++, bit <<= 1)
+    {
+        if (drivemap & bit)  /* this logical drive exists. */
+        {
+            if ((is_cdrom_drive(i)) && (disc_is_inserted(i)))
+            {
+                char drive[4] = "x:\\";
+                drive[0] = ('A' + i);
+                cb(data, drive);
+            } /* if */
+        } /* if */
+    } /* for */
+} /* __PHYSFS_platformDetectAvailableCDs */
+
+
+char *__PHYSFS_platformCalcBaseDir(const char *argv0)
+{
+    char *retval = (char *) allocator.Malloc(strlen(baseDir) + 1);
+    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+    strcpy(retval, baseDir); /* calculated at init time. */
+    return(retval);
+} /* __PHYSFS_platformCalcBaseDir */
+
+
+char *__PHYSFS_platformGetUserName(void)
+{
+    return(NULL);  /* (*shrug*) */
+} /* __PHYSFS_platformGetUserName */
+
+
+char *__PHYSFS_platformGetUserDir(void)
+{
+    return(__PHYSFS_platformCalcBaseDir(NULL));
+} /* __PHYSFS_platformGetUserDir */
+
+
+int __PHYSFS_platformExists(const char *fname)
+{
+    FILESTATUS3 fs;
+    APIRET rc = DosQueryPathInfo(fname, FIL_STANDARD, &fs, sizeof (fs));
+    return(os2err(rc) == NO_ERROR);
+} /* __PHYSFS_platformExists */
+
+
+int __PHYSFS_platformIsSymLink(const char *fname)
+{
+    return(0);  /* no symlinks in OS/2. */
+} /* __PHYSFS_platformIsSymlink */
+
+
+int __PHYSFS_platformIsDirectory(const char *fname)
+{
+    FILESTATUS3 fs;
+    APIRET rc = DosQueryPathInfo(fname, FIL_STANDARD, &fs, sizeof (fs));
+    BAIL_IF_MACRO(os2err(rc) != NO_ERROR, NULL, 0)
+    return((fs.attrFile & FILE_DIRECTORY) != 0);
+} /* __PHYSFS_platformIsDirectory */
+
+
+/* !!! FIXME: can we lose the malloc here? */
+char *__PHYSFS_platformCvtToDependent(const char *prepend,
+                                      const char *dirName,
+                                      const char *append)
+{
+    int len = ((prepend) ? strlen(prepend) : 0) +
+              ((append) ? strlen(append) : 0) +
+              strlen(dirName) + 1;
+    char *retval = allocator.Malloc(len);
+    char *p;
+
+    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+    if (prepend)
+        strcpy(retval, prepend);
+    else
+        retval[0] = '\0';
+
+    strcat(retval, dirName);
+
+    if (append)
+        strcat(retval, append);
+
+    for (p = strchr(retval, '/'); p != NULL; p = strchr(p + 1, '/'))
+        *p = '\\';
+
+    return(retval);
+} /* __PHYSFS_platformCvtToDependent */
+
+
+void __PHYSFS_platformEnumerateFiles(const char *dirname,
+                                     int omitSymLinks,
+                                     PHYSFS_EnumFilesCallback callback,
+                                     const char *origdir,
+                                     void *callbackdata)
+{
+    char spec[CCHMAXPATH];
+    FILEFINDBUF3 fb;
+    HDIR hdir = HDIR_CREATE;
+    ULONG count = 1;
+    APIRET rc;
+
+    if (strlen(dirname) > sizeof (spec) - 5)
+    {
+        __PHYSFS_setError(ERR_BAD_FILENAME);
+        return;
+    } /* if */
+
+    strcpy(spec, dirname);
+    strcat(spec, (spec[strlen(spec) - 1] != '\\') ? "\\*.*" : "*.*");
+
+    rc = DosFindFirst(spec, &hdir,
+                      FILE_DIRECTORY | FILE_ARCHIVED |
+                      FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM,
+                      &fb, sizeof (fb), &count, FIL_STANDARD);
+
+    if (os2err(rc) != NO_ERROR)
+        return;
+
+    while (count == 1)
+    {
+        if ((strcmp(fb.achName, ".") != 0) && (strcmp(fb.achName, "..") != 0))
+            callback(callbackdata, origdir, fb.achName);
+
+        DosFindNext(hdir, &fb, sizeof (fb), &count);
+    } /* while */
+
+    DosFindClose(hdir);
+} /* __PHYSFS_platformEnumerateFiles */
+
+
+char *__PHYSFS_platformCurrentDir(void)
+{
+    char *retval;
+    ULONG currentDisk;
+    ULONG dummy;
+    ULONG pathSize = 0;
+    APIRET rc;
+    BYTE byte;
+
+    rc = DosQueryCurrentDisk(&currentDisk, &dummy);
+    BAIL_IF_MACRO(os2err(rc) != NO_ERROR, NULL, NULL);
+
+    /* The first call just tells us how much space we need for the string. */
+    rc = DosQueryCurrentDir(currentDisk, &byte, &pathSize);
+    pathSize++; /* Add space for null terminator. */
+    retval = (char *) allocator.Malloc(pathSize + 3);  /* plus "x:\\" */
+    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+    /* Actually get the string this time. */
+    rc = DosQueryCurrentDir(currentDisk, (PBYTE) (retval + 3), &pathSize);
+    if (os2err(rc) != NO_ERROR)
+    {
+        allocator.Free(retval);
+        return(NULL);
+    } /* if */
+
+    retval[0] = ('A' + (currentDisk - 1));
+    retval[1] = ':';
+    retval[2] = '\\';
+    return(retval);
+} /* __PHYSFS_platformCurrentDir */
+
+
+char *__PHYSFS_platformRealPath(const char *path)
+{
+    char buf[CCHMAXPATH];
+    char *retval;
+    APIRET rc = DosQueryPathInfo(path, FIL_QUERYFULLNAME, buf, sizeof (buf));
+    BAIL_IF_MACRO(os2err(rc) != NO_ERROR, NULL, NULL);
+    retval = (char *) allocator.Malloc(strlen(buf) + 1);
+    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+    strcpy(retval, buf);
+    return(retval);
+} /* __PHYSFS_platformRealPath */
+
+
+int __PHYSFS_platformMkDir(const char *path)
+{
+    return(os2err(DosCreateDir(path, NULL)) == NO_ERROR);
+} /* __PHYSFS_platformMkDir */
+
+
+void *__PHYSFS_platformOpenRead(const char *filename)
+{
+    ULONG actionTaken = 0;
+    HFILE hfile = NULLHANDLE;
+
+    /*
+     * File must be opened SHARE_DENYWRITE and ACCESS_READONLY, otherwise
+     *  DosQueryFileInfo() will fail if we try to get a file length, etc.
+     */
+    os2err(DosOpen(filename, &hfile, &actionTaken, 0, FILE_NORMAL,
+                   OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW,
+                   OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NO_LOCALITY |
+                   OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYWRITE |
+                   OPEN_ACCESS_READONLY, NULL));
+
+    return((void *) hfile);
+} /* __PHYSFS_platformOpenRead */
+
+
+void *__PHYSFS_platformOpenWrite(const char *filename)
+{
+    ULONG actionTaken = 0;
+    HFILE hfile = NULLHANDLE;
+
+    /*
+     * File must be opened SHARE_DENYWRITE and ACCESS_READWRITE, otherwise
+     *  DosQueryFileInfo() will fail if we try to get a file length, etc.
+     */
+    os2err(DosOpen(filename, &hfile, &actionTaken, 0, FILE_NORMAL,
+                   OPEN_ACTION_REPLACE_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW,
+                   OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NO_LOCALITY |
+                   OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYWRITE |
+                   OPEN_ACCESS_READWRITE, NULL));
+
+    return((void *) hfile);
+} /* __PHYSFS_platformOpenWrite */
+
+
+void *__PHYSFS_platformOpenAppend(const char *filename)
+{
+    ULONG dummy = 0;
+    HFILE hfile = NULLHANDLE;
+    APIRET rc;
+
+    /*
+     * File must be opened SHARE_DENYWRITE and ACCESS_READWRITE, otherwise
+     *  DosQueryFileInfo() will fail if we try to get a file length, etc.
+     */
+    rc = os2err(DosOpen(filename, &hfile, &dummy, 0, FILE_NORMAL,
+                   OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW,
+                   OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NO_LOCALITY |
+                   OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYWRITE |
+                   OPEN_ACCESS_READWRITE, NULL));
+
+    if (rc == NO_ERROR)
+    {
+        if (os2err(DosSetFilePtr(hfile, 0, FILE_END, &dummy)) != NO_ERROR)
+        {
+            DosClose(hfile);
+            hfile = NULLHANDLE;
+        } /* if */
+    } /* if */
+
+    return((void *) hfile);
+} /* __PHYSFS_platformOpenAppend */
+
+
+PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
+                                    PHYSFS_uint32 size, PHYSFS_uint32 count)
+{
+    HFILE hfile = (HFILE) opaque;
+    PHYSFS_sint64 retval;
+    ULONG br;
+
+    for (retval = 0; retval < count; retval++)
+    {
+        os2err(DosRead(hfile, buffer, size, &br));
+        if (br < size)
+        {
+            DosSetFilePtr(hfile, -br, FILE_CURRENT, &br); /* try to cleanup. */
+            return(retval);
+        } /* if */
+
+        buffer = (void *) ( ((char *) buffer) + size );
+    } /* for */
+
+    return(retval);
+} /* __PHYSFS_platformRead */
+
+
+PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
+                                     PHYSFS_uint32 size, PHYSFS_uint32 count)
+{
+    HFILE hfile = (HFILE) opaque;
+    PHYSFS_sint64 retval;
+    ULONG bw;
+
+    for (retval = 0; retval < count; retval++)
+    {
+        os2err(DosWrite(hfile, buffer, size, &bw));
+        if (bw < size)
+        {
+            DosSetFilePtr(hfile, -bw, FILE_CURRENT, &bw); /* try to cleanup. */
+            return(retval);
+        } /* if */
+
+        buffer = (void *) ( ((char *) buffer) + size );
+    } /* for */
+
+    return(retval);
+} /* __PHYSFS_platformWrite */
+
+
+int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos)
+{
+    ULONG dummy;
+    HFILE hfile = (HFILE) opaque;
+    LONG dist = (LONG) pos;
+
+    /* hooray for 32-bit filesystem limits!  :) */
+    BAIL_IF_MACRO((PHYSFS_uint64) dist != pos, ERR_SEEK_OUT_OF_RANGE, 0);
+
+    return(os2err(DosSetFilePtr(hfile, dist, FILE_BEGIN, &dummy)) == NO_ERROR);
+} /* __PHYSFS_platformSeek */
+
+
+PHYSFS_sint64 __PHYSFS_platformTell(void *opaque)
+{
+    ULONG pos;
+    HFILE hfile = (HFILE) opaque;
+    APIRET rc = os2err(DosSetFilePtr(hfile, 0, FILE_CURRENT, &pos));
+    BAIL_IF_MACRO(rc != NO_ERROR, NULL, -1);
+    return((PHYSFS_sint64) pos);
+} /* __PHYSFS_platformTell */
+
+
+PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
+{
+    FILESTATUS3 fs;
+    HFILE hfile = (HFILE) opaque;
+    APIRET rc = DosQueryFileInfo(hfile, FIL_STANDARD, &fs, sizeof (fs));
+    BAIL_IF_MACRO(os2err(rc) != NO_ERROR, NULL, -1);
+    return((PHYSFS_sint64) fs.cbFile);
+} /* __PHYSFS_platformFileLength */
+
+
+int __PHYSFS_platformEOF(void *opaque)
+{
+    PHYSFS_sint64 len, pos;
+
+    len = __PHYSFS_platformFileLength(opaque);
+    BAIL_IF_MACRO(len == -1, NULL, 1);  /* (*shrug*) */
+    pos = __PHYSFS_platformTell(opaque);
+    BAIL_IF_MACRO(pos == -1, NULL, 1);  /* (*shrug*) */
+
+    return(pos >= len);
+} /* __PHYSFS_platformEOF */
+
+
+int __PHYSFS_platformFlush(void *opaque)
+{
+    return(os2err(DosResetBuffer((HFILE) opaque) == NO_ERROR));
+} /* __PHYSFS_platformFlush */
+
+
+int __PHYSFS_platformClose(void *opaque)
+{
+    return(os2err(DosClose((HFILE) opaque) == NO_ERROR));
+} /* __PHYSFS_platformClose */
+
+
+int __PHYSFS_platformDelete(const char *path)
+{
+    if (__PHYSFS_platformIsDirectory(path))
+        return(os2err(DosDeleteDir(path)) == NO_ERROR);
+
+    return(os2err(DosDelete(path) == NO_ERROR));
+} /* __PHYSFS_platformDelete */
+
+
+PHYSFS_sint64 __PHYSFS_platformGetLastModTime(const char *fname)
+{
+    PHYSFS_sint64 retval;
+    struct tm tm;
+    FILESTATUS3 fs;
+    APIRET rc = DosQueryPathInfo(fname, FIL_STANDARD, &fs, sizeof (fs));
+    BAIL_IF_MACRO(os2err(rc) != NO_ERROR, NULL, -1);
+
+    /* Convert to a format that mktime() can grok... */
+    tm.tm_sec = ((PHYSFS_uint32) fs.ftimeLastWrite.twosecs) * 2;
+    tm.tm_min = fs.ftimeLastWrite.minutes;
+    tm.tm_hour = fs.ftimeLastWrite.hours;
+    tm.tm_mday = fs.fdateLastWrite.day;
+    tm.tm_mon = fs.fdateLastWrite.month;
+    tm.tm_year = ((PHYSFS_uint32) fs.fdateLastWrite.year) + 80;
+    tm.tm_wday = -1 /*st_localtz.wDayOfWeek*/;
+    tm.tm_yday = -1;
+    tm.tm_isdst = -1;
+
+    /* Convert to a format PhysicsFS can grok... */
+    retval = (PHYSFS_sint64) mktime(&tm);
+    BAIL_IF_MACRO(retval == -1, strerror(errno), -1);
+    return(retval);
+} /* __PHYSFS_platformGetLastModTime */
+
+
+PHYSFS_uint64 __PHYSFS_platformGetThreadID(void)
+{
+    PTIB ptib;
+    PPIB ppib;
+
+    /*
+     * Allegedly, this API never fails, but we'll punt and return a
+     *  default value (zero might as well do) if it does.
+     */
+    BAIL_IF_MACRO(os2err(DosGetInfoBlocks(&ptib, &ppib)) != NO_ERROR, 0, 0);
+    return((PHYSFS_uint64) ptib->tib_ordinal);
+} /* __PHYSFS_platformGetThreadID */
+
+
+void *__PHYSFS_platformCreateMutex(void)
+{
+    HMTX hmtx = NULLHANDLE;
+    os2err(DosCreateMutexSem(NULL, &hmtx, 0, 0));
+    return((void *) hmtx);
+} /* __PHYSFS_platformCreateMutex */
+
+
+void __PHYSFS_platformDestroyMutex(void *mutex)
+{
+    DosCloseMutexSem((HMTX) mutex);
+} /* __PHYSFS_platformDestroyMutex */
+
+
+int __PHYSFS_platformGrabMutex(void *mutex)
+{
+    /* Do _NOT_ call os2err() (which sets the physfs error msg) in here! */
+    return(DosRequestMutexSem((HMTX) mutex, SEM_INDEFINITE_WAIT) == NO_ERROR);
+} /* __PHYSFS_platformGrabMutex */
+
+
+void __PHYSFS_platformReleaseMutex(void *mutex)
+{
+    DosReleaseMutexSem((HMTX) mutex);
+} /* __PHYSFS_platformReleaseMutex */
+
+
+/* !!! FIXME: Don't use C runtime for allocators? */
+int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
+{
+    return(0);  /* just use malloc() and friends. */
+} /* __PHYSFS_platformSetDefaultAllocator */
+
+#endif  /* PHYSFS_PLATFORM_OS2 */
+
+/* end of os2.c ... */
+
diff --git a/src/unison/physfs-1.1.1/platform/pocketpc.c b/src/unison/physfs-1.1.1/platform/pocketpc.c
new file mode 100644 (file)
index 0000000..badb0db
--- /dev/null
@@ -0,0 +1,608 @@
+/*
+ * PocketPC support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_platforms.h"
+
+#ifdef PHYSFS_PLATFORM_POCKETPC
+
+#include <stdio.h>
+#include <windows.h>
+
+#include "physfs_internal.h"
+
+#define INVALID_FILE_ATTRIBUTES  0xFFFFFFFF
+#define INVALID_SET_FILE_POINTER 0xFFFFFFFF
+typedef struct
+{
+    HANDLE handle;
+    int readonly;
+} winCEfile;
+
+
+const char *__PHYSFS_platformDirSeparator = "\\";
+static char *userDir = NULL;
+
+/*
+ * Figure out what the last failing Win32 API call was, and
+ *  generate a human-readable string for the error message.
+ *
+ * The return value is a static buffer that is overwritten with
+ *  each call to this function.
+ */
+static const char *win32strerror(void)
+{
+    static TCHAR msgbuf[255];
+    TCHAR *ptr = msgbuf;
+
+    FormatMessage(
+        FORMAT_MESSAGE_FROM_SYSTEM |
+        FORMAT_MESSAGE_IGNORE_INSERTS,
+        NULL,
+        GetLastError(),
+        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
+        msgbuf,
+        sizeof (msgbuf) / sizeof (TCHAR),
+        NULL 
+        );
+
+    /* chop off newlines. */
+    for (ptr = msgbuf; *ptr; ptr++)
+    {
+        if ((*ptr == '\n') || (*ptr == '\r'))
+        {
+            *ptr = ' ';
+            break;
+        } /* if */
+    } /* for */
+
+    return((const char *) msgbuf);
+} /* win32strerror */
+
+
+/* !!! FIXME: need to check all of these for NULLs. */
+#define UTF8_TO_UNICODE_STACK_MACRO(w_assignto, str) { \
+    if (str == NULL) \
+        w_assignto = NULL; \
+    else { \
+        const PHYSFS_uint64 len = (PHYSFS_uint64) ((strlen(str) * 4) + 1); \
+        w_assignto = (char *) __PHYSFS_smallAlloc(len); \
+        PHYSFS_uc2fromutf8(str, (PHYSFS_uint16 *) w_assignto, len); \
+    } \
+} \
+
+
+static char *getExePath()
+{
+    DWORD buflen;
+    int success = 0;
+    TCHAR *ptr = NULL;
+    TCHAR *retval = (TCHAR*) allocator.Malloc(sizeof (TCHAR) * (MAX_PATH + 1));
+    char *charretval;
+    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+    retval[0] = _T('\0');
+    /* !!! FIXME: don't preallocate here? */
+    /* !!! FIXME: use smallAlloc? */
+    buflen = GetModuleFileName(NULL, retval, MAX_PATH + 1);
+    if (buflen <= 0)
+        __PHYSFS_setError(win32strerror());
+    else
+    {
+        retval[buflen] = '\0';  /* does API always null-terminate this? */
+        ptr = retval+buflen;
+        while( ptr != retval )
+        {
+            if( *ptr != _T('\\') )
+                *ptr-- = _T('\0');
+            else
+                break;
+        } /* while */
+        success = 1;
+    } /* else */
+
+    if (!success)
+    {
+        allocator.Free(retval);
+        return(NULL);  /* physfs error message will be set, above. */
+    } /* if */
+
+    buflen = (buflen * 4) + 1;
+    charretval = (char *) allocator.Malloc(buflen);
+    if (charretval != NULL)
+        PHYSFS_utf8fromucs2((const PHYSFS_uint16 *) retval, charretval, buflen);
+    allocator.Free(retval);
+    return(charretval);   /* w00t. */
+} /* getExePath */
+
+
+int __PHYSFS_platformInit(void)
+{
+    userDir = getExePath();
+    BAIL_IF_MACRO(userDir == NULL, NULL, 0); /* failed? */
+    return(1);  /* always succeed. */
+} /* __PHYSFS_platformInit */
+
+
+int __PHYSFS_platformDeinit(void)
+{
+    allocator.Free(userDir);
+    return(1);  /* always succeed. */
+} /* __PHYSFS_platformDeinit */
+
+
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
+{
+    /* no-op on this platform. */
+} /* __PHYSFS_platformDetectAvailableCDs */
+
+
+char *__PHYSFS_platformCalcBaseDir(const char *argv0)
+{
+    return(getExePath());
+} /* __PHYSFS_platformCalcBaseDir */
+
+
+char *__PHYSFS_platformGetUserName(void)
+{
+    BAIL_MACRO(ERR_NOT_IMPLEMENTED, NULL);
+} /* __PHYSFS_platformGetUserName */
+
+
+char *__PHYSFS_platformGetUserDir(void)
+{
+    return userDir;
+    BAIL_MACRO(ERR_NOT_IMPLEMENTED, NULL);
+} /* __PHYSFS_platformGetUserDir */
+
+
+PHYSFS_uint64 __PHYSFS_platformGetThreadID(void)
+{
+    return(1);  /* single threaded. */
+} /* __PHYSFS_platformGetThreadID */
+
+
+int __PHYSFS_platformExists(const char *fname)
+{
+    int retval = 0;
+    wchar_t *w_fname = NULL;
+
+    UTF8_TO_UNICODE_STACK_MACRO(w_fname, fname);
+    if (w_fname != NULL)
+        retval = (GetFileAttributes(w_fname) != INVALID_FILE_ATTRIBUTES);
+    __PHYSFS_smallFree(w_fname);
+
+    return(retval);
+} /* __PHYSFS_platformExists */
+
+
+int __PHYSFS_platformIsSymLink(const char *fname)
+{
+    BAIL_MACRO(ERR_NOT_IMPLEMENTED, 0);
+} /* __PHYSFS_platformIsSymlink */
+
+
+int __PHYSFS_platformIsDirectory(const char *fname)
+{
+    int retval = 0;
+    wchar_t *w_fname = NULL;
+
+    UTF8_TO_UNICODE_STACK_MACRO(w_fname, fname);
+    if (w_fname != NULL)
+        retval = ((GetFileAttributes(w_fname) & FILE_ATTRIBUTE_DIRECTORY) != 0);
+    __PHYSFS_smallFree(w_fname);
+
+    return(retval);
+} /* __PHYSFS_platformIsDirectory */
+
+
+char *__PHYSFS_platformCvtToDependent(const char *prepend,
+                                      const char *dirName,
+                                      const char *append)
+{
+    int len = ((prepend) ? strlen(prepend) : 0) +
+    ((append) ? strlen(append) : 0) +
+    strlen(dirName) + 1;
+    char *retval = (char *) allocator.Malloc(len);
+    char *p;
+
+    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+    if (prepend)
+        strcpy(retval, prepend);
+    else
+        retval[0] = '\0';
+
+    strcat(retval, dirName);
+
+    if (append)
+        strcat(retval, append);
+
+    for (p = strchr(retval, '/'); p != NULL; p = strchr(p + 1, '/'))
+        *p = '\\';
+
+    return(retval);
+} /* __PHYSFS_platformCvtToDependent */
+
+
+static int doEnumCallback(const wchar_t *w_fname)
+{
+    const PHYSFS_uint64 len = (PHYSFS_uint64) ((wcslen(w_fname) * 4) + 1);
+    char *str = (char *) __PHYSFS_smallAlloc(len);
+    PHYSFS_utf8fromucs2((const PHYSFS_uint16 *) w_fname, str, len);
+    callback(callbackdata, origdir, str);
+    __PHYSFS_smallFree(str);
+    return 1;
+} /* doEnumCallback */
+
+
+void __PHYSFS_platformEnumerateFiles(const char *dirname,
+                                     int omitSymLinks,
+                                     PHYSFS_EnumFilesCallback callback,
+                                     const char *origdir,
+                                     void *callbackdata)
+{
+    HANDLE dir;
+    WIN32_FIND_DATA ent;
+    char *SearchPath;
+    wchar_t *w_SearchPath;
+    size_t len = strlen(dirname);
+
+    /* Allocate a new string for path, maybe '\\', "*", and NULL terminator */
+    SearchPath = (char *) __PHYSFS_smallAlloc(len + 3);
+    BAIL_IF_MACRO(SearchPath == NULL, ERR_OUT_OF_MEMORY, NULL);    
+
+    /* Copy current dirname */
+    strcpy(SearchPath, dirname);
+
+    /* if there's no '\\' at the end of the path, stick one in there. */
+    if (SearchPath[len - 1] != '\\')
+    {
+        SearchPath[len++] = '\\';
+        SearchPath[len] = '\0';
+    } /* if */
+
+    /* Append the "*" to the end of the string */
+    strcat(SearchPath, "*");
+
+    UTF8_TO_UNICODE_STACK_MACRO(w_SearchPath, SearchPath);
+    __PHYSFS_smallFree(SearchPath);
+    dir = FindFirstFile(w_SearchPath, &ent);
+    __PHYSFS_smallFree(w_SearchPath);
+
+    if (dir == INVALID_HANDLE_VALUE)
+        return;
+
+    do
+    {
+        const char *str = NULL;
+
+        if (wcscmp(ent.cFileName, L".") == 0)
+            continue;
+
+        if (wcscmp(ent.cFileName, L"..") == 0)
+            continue;
+
+        if (!doEnumCallback(ent.cFileName))
+            break;
+    } while (FindNextFile(dir, &ent) != 0);
+
+    FindClose(dir);
+} /* __PHYSFS_platformEnumerateFiles */
+
+
+char *__PHYSFS_platformCurrentDir(void)
+{
+    return("\\");
+} /* __PHYSFS_platformCurrentDir */
+
+
+char *__PHYSFS_platformRealPath(const char *path)
+{
+    char *retval = (char *) allocator.Malloc(strlen(path) + 1);
+    strcpy(retval,path);
+    return(retval);
+} /* __PHYSFS_platformRealPath */
+
+
+int __PHYSFS_platformMkDir(const char *path)
+{
+    int retval = 0;
+    wchar_t *w_path = NULL;
+    UTF8_TO_UNICODE_STACK_MACRO(w_path, path);
+    if (w_path != NULL)
+    {
+        retval = CreateDirectory(w_path, NULL);
+        __PHYSFS_smallFree(w_fname);
+    } /* if */
+    return(retval);
+} /* __PHYSFS_platformMkDir */
+
+
+static void *doOpen(const char *fname, DWORD mode, DWORD creation, int rdonly)
+{
+    HANDLE fileHandle;
+    winCEfile *retval;
+    wchar_t *w_fname = NULL;
+
+    UTF8_TO_UNICODE_STACK_MACRO(w_fname, fname);
+    fileHandle = CreateFile(w_fname, mode, FILE_SHARE_READ, NULL,
+                            creation, FILE_ATTRIBUTE_NORMAL, NULL);
+    __PHYSFS_smallFree(w_fname);
+
+    BAIL_IF_MACRO(fileHandle == INVALID_HANDLE_VALUE, win32strerror(), NULL);
+
+    retval = (winCEfile *) allocator.Malloc(sizeof (winCEfile));
+    if (retval == NULL)
+    {
+        CloseHandle(fileHandle);
+        BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
+    } /* if */
+
+    retval->readonly = rdonly;
+    retval->handle = fileHandle;
+    return(retval);
+} /* doOpen */
+
+
+void *__PHYSFS_platformOpenRead(const char *filename)
+{
+    return(doOpen(filename, GENERIC_READ, OPEN_EXISTING, 1));
+} /* __PHYSFS_platformOpenRead */
+
+
+void *__PHYSFS_platformOpenWrite(const char *filename)
+{
+    return(doOpen(filename, GENERIC_WRITE, CREATE_ALWAYS, 0));
+} /* __PHYSFS_platformOpenWrite */
+
+
+void *__PHYSFS_platformOpenAppend(const char *filename)
+{
+    void *retval = doOpen(filename, GENERIC_WRITE, OPEN_ALWAYS, 0);
+    if (retval != NULL)
+    {
+        HANDLE h = ((winCEfile *) retval)->handle;
+        if (SetFilePointer(h, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
+        {
+            const char *err = win32strerror();
+            CloseHandle(h);
+            allocator.Free(retval);
+            BAIL_MACRO(err, NULL);
+        } /* if */
+    } /* if */
+
+    return(retval);
+
+} /* __PHYSFS_platformOpenAppend */
+
+
+PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
+                                    PHYSFS_uint32 size, PHYSFS_uint32 count)
+{
+    HANDLE Handle = ((winCEfile *) opaque)->handle;
+    DWORD CountOfBytesRead;
+    PHYSFS_sint64 retval;
+
+    /* Read data from the file */
+    /*!!! - uint32 might be a greater # than DWORD */
+    if (!ReadFile(Handle, buffer, count * size, &CountOfBytesRead, NULL))
+    {
+        retval = -1;
+    } /* if */
+    else
+    {
+        /* Return the number of "objects" read. */
+        /* !!! - What if not the right amount of bytes was read to make an object? */
+        retval = CountOfBytesRead / size;
+    } /* else */
+
+    return(retval);
+
+} /* __PHYSFS_platformRead */
+
+
+PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
+                                     PHYSFS_uint32 size, PHYSFS_uint32 count)
+{
+    HANDLE Handle = ((winCEfile *) opaque)->handle;
+    DWORD CountOfBytesWritten;
+    PHYSFS_sint64 retval;
+
+    /* Read data from the file */
+    /*!!! - uint32 might be a greater # than DWORD */
+    if (!WriteFile(Handle, buffer, count * size, &CountOfBytesWritten, NULL))
+    {
+        retval = -1;
+    } /* if */
+    else
+    {
+        /* Return the number of "objects" read. */
+        /*!!! - What if not the right number of bytes was written? */
+        retval = CountOfBytesWritten / size;
+    } /* else */
+
+    return(retval);
+
+} /* __PHYSFS_platformWrite */
+
+
+int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos)
+{
+    HANDLE Handle = ((winCEfile *) opaque)->handle;
+    DWORD HighOrderPos;
+    DWORD rc;
+
+    /* Get the high order 32-bits of the position */
+    //HighOrderPos = HIGHORDER_UINT64(pos);
+    HighOrderPos = (unsigned long)(pos>>32);
+
+    /*!!! SetFilePointer needs a signed 64-bit value. */
+    /* Move pointer "pos" count from start of file */
+    rc = SetFilePointer(Handle, (unsigned long)(pos&0x00000000ffffffff),
+                        &HighOrderPos, FILE_BEGIN);
+
+    if ((rc == INVALID_SET_FILE_POINTER) && (GetLastError() != NO_ERROR))
+    {
+        BAIL_MACRO(win32strerror(), 0);
+    }
+
+    return(1);  /* No error occured */
+} /* __PHYSFS_platformSeek */
+
+
+PHYSFS_sint64 __PHYSFS_platformTell(void *opaque)
+{
+    HANDLE Handle = ((winCEfile *) opaque)->handle;
+    DWORD HighPos = 0;
+    DWORD LowPos;
+    PHYSFS_sint64 retval;
+
+    /* Get current position */
+    LowPos = SetFilePointer(Handle, 0, &HighPos, FILE_CURRENT);
+    if ((LowPos == INVALID_SET_FILE_POINTER) && (GetLastError() != NO_ERROR))
+    {
+        BAIL_MACRO(win32strerror(), 0);
+    } /* if */
+    else
+    {
+        /* Combine the high/low order to create the 64-bit position value */
+        retval = (((PHYSFS_uint64) HighPos) << 32) | LowPos;
+        //assert(retval >= 0);
+    } /* else */
+
+    return(retval);
+} /* __PHYSFS_platformTell */
+
+
+PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
+{
+    HANDLE Handle = ((winCEfile *) opaque)->handle;
+    DWORD SizeHigh;
+    DWORD SizeLow;
+    PHYSFS_sint64 retval;
+
+    SizeLow = GetFileSize(Handle, &SizeHigh);
+    if ((SizeLow == INVALID_SET_FILE_POINTER) && (GetLastError() != NO_ERROR))
+    {
+        BAIL_MACRO(win32strerror(), -1);
+    } /* if */
+    else
+    {
+        /* Combine the high/low order to create the 64-bit position value */
+        retval = (((PHYSFS_uint64) SizeHigh) << 32) | SizeLow;
+        //assert(retval >= 0);
+    } /* else */
+
+    return(retval);
+} /* __PHYSFS_platformFileLength */
+
+
+int __PHYSFS_platformEOF(void *opaque)
+{
+    PHYSFS_sint64 FilePosition;
+    int retval = 0;
+
+    /* Get the current position in the file */
+    if ((FilePosition = __PHYSFS_platformTell(opaque)) != 0)
+    {
+        /* Non-zero if EOF is equal to the file length */
+        retval = FilePosition == __PHYSFS_platformFileLength(opaque);
+    } /* if */
+
+    return(retval);
+} /* __PHYSFS_platformEOF */
+
+
+int __PHYSFS_platformFlush(void *opaque)
+{
+    winCEfile *fh = ((winCEfile *) opaque);
+    if (!fh->readonly)
+        BAIL_IF_MACRO(!FlushFileBuffers(fh->handle), win32strerror(), 0);
+
+    return(1);
+} /* __PHYSFS_platformFlush */
+
+
+int __PHYSFS_platformClose(void *opaque)
+{
+    HANDLE Handle = ((winCEfile *) opaque)->handle;
+    BAIL_IF_MACRO(!CloseHandle(Handle), win32strerror(), 0);
+    allocator.Free(opaque);
+    return(1);
+} /* __PHYSFS_platformClose */
+
+
+int __PHYSFS_platformDelete(const char *path)
+{
+    wchar_t *w_path = NULL;
+    UTF8_TO_UNICODE_STACK_MACRO(w_path, path);
+
+    /* If filename is a folder */
+    if (GetFileAttributes(w_path) == FILE_ATTRIBUTE_DIRECTORY)
+    {
+        int retval = !RemoveDirectory(w_path);
+        __PHYSFS_smallFree(w_path);
+        BAIL_IF_MACRO(retval, win32strerror(), 0);
+    } /* if */
+    else
+    {
+        int retval = !DeleteFile(w_path);
+        __PHYSFS_smallFree(w_path);
+        BAIL_IF_MACRO(retval, win32strerror(), 0);
+    } /* else */
+
+    return(1);  /* if you got here, it worked. */
+} /* __PHYSFS_platformDelete */
+
+
+/*
+ * !!! FIXME: why aren't we using Critical Sections instead of Mutexes?
+ * !!! FIXME:  mutexes on Windows are for cross-process sync. CritSects are
+ * !!! FIXME:  mutexes for threads in a single process and are faster.
+ */
+void *__PHYSFS_platformCreateMutex(void)
+{
+    return((void *) CreateMutex(NULL, FALSE, NULL));
+} /* __PHYSFS_platformCreateMutex */
+
+
+void __PHYSFS_platformDestroyMutex(void *mutex)
+{
+    CloseHandle((HANDLE) mutex);
+} /* __PHYSFS_platformDestroyMutex */
+
+
+int __PHYSFS_platformGrabMutex(void *mutex)
+{
+    return(WaitForSingleObject((HANDLE) mutex, INFINITE) != WAIT_FAILED);
+} /* __PHYSFS_platformGrabMutex */
+
+
+void __PHYSFS_platformReleaseMutex(void *mutex)
+{
+    ReleaseMutex((HANDLE) mutex);
+} /* __PHYSFS_platformReleaseMutex */
+
+
+PHYSFS_sint64 __PHYSFS_platformGetLastModTime(const char *fname)
+{
+    BAIL_MACRO(ERR_NOT_IMPLEMENTED, -1);
+} /* __PHYSFS_platformGetLastModTime */
+
+
+/* !!! FIXME: Don't use C runtime for allocators? */
+int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
+{
+    return(0);  /* just use malloc() and friends. */
+} /* __PHYSFS_platformSetDefaultAllocator */
+
+#endif  /* PHYSFS_PLATFORM_POCKETPC */
+
+/* end of pocketpc.c ... */
+
diff --git a/src/unison/physfs-1.1.1/platform/posix.c b/src/unison/physfs-1.1.1/platform/posix.c
new file mode 100644 (file)
index 0000000..0051255
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ * Posix-esque support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_platforms.h"
+
+#ifdef PHYSFS_PLATFORM_POSIX
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <pwd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef PHYSFS_HAVE_LLSEEK
+#include <linux/unistd.h>
+#endif
+
+#include "physfs_internal.h"
+
+
+const char *__PHYSFS_platformDirSeparator = "/";
+
+
+char *__PHYSFS_platformCopyEnvironmentVariable(const char *varname)
+{
+    const char *envr = getenv(varname);
+    char *retval = NULL;
+
+    if (envr != NULL)
+    {
+        retval = (char *) allocator.Malloc(strlen(envr) + 1);
+        if (retval != NULL)
+            strcpy(retval, envr);
+    } /* if */
+
+    return(retval);
+} /* __PHYSFS_platformCopyEnvironmentVariable */
+
+
+static char *getUserNameByUID(void)
+{
+    uid_t uid = getuid();
+    struct passwd *pw;
+    char *retval = NULL;
+
+    pw = getpwuid(uid);
+    if ((pw != NULL) && (pw->pw_name != NULL))
+    {
+        retval = (char *) allocator.Malloc(strlen(pw->pw_name) + 1);
+        if (retval != NULL)
+            strcpy(retval, pw->pw_name);
+    } /* if */
+    
+    return(retval);
+} /* getUserNameByUID */
+
+
+static char *getUserDirByUID(void)
+{
+    uid_t uid = getuid();
+    struct passwd *pw;
+    char *retval = NULL;
+
+    pw = getpwuid(uid);
+    if ((pw != NULL) && (pw->pw_dir != NULL))
+    {
+        retval = (char *) allocator.Malloc(strlen(pw->pw_dir) + 1);
+        if (retval != NULL)
+            strcpy(retval, pw->pw_dir);
+    } /* if */
+    
+    return(retval);
+} /* getUserDirByUID */
+
+
+char *__PHYSFS_platformGetUserName(void)
+{
+    char *retval = getUserNameByUID();
+    if (retval == NULL)
+        retval = __PHYSFS_platformCopyEnvironmentVariable("USER");
+    return(retval);
+} /* __PHYSFS_platformGetUserName */
+
+
+char *__PHYSFS_platformGetUserDir(void)
+{
+    char *retval = __PHYSFS_platformCopyEnvironmentVariable("HOME");
+    if (retval == NULL)
+        retval = getUserDirByUID();
+    return(retval);
+} /* __PHYSFS_platformGetUserDir */
+
+
+int __PHYSFS_platformExists(const char *fname)
+{
+    struct stat statbuf;
+    BAIL_IF_MACRO(lstat(fname, &statbuf) == -1, strerror(errno), 0);
+    return(1);
+} /* __PHYSFS_platformExists */
+
+
+int __PHYSFS_platformIsSymLink(const char *fname)
+{
+    struct stat statbuf;
+    BAIL_IF_MACRO(lstat(fname, &statbuf) == -1, strerror(errno), 0);
+    return( (S_ISLNK(statbuf.st_mode)) ? 1 : 0 );
+} /* __PHYSFS_platformIsSymlink */
+
+
+int __PHYSFS_platformIsDirectory(const char *fname)
+{
+    struct stat statbuf;
+    BAIL_IF_MACRO(stat(fname, &statbuf) == -1, strerror(errno), 0);
+    return( (S_ISDIR(statbuf.st_mode)) ? 1 : 0 );
+} /* __PHYSFS_platformIsDirectory */
+
+
+char *__PHYSFS_platformCvtToDependent(const char *prepend,
+                                      const char *dirName,
+                                      const char *append)
+{
+    int len = ((prepend) ? strlen(prepend) : 0) +
+              ((append) ? strlen(append) : 0) +
+              strlen(dirName) + 1;
+    char *retval = (char *) allocator.Malloc(len);
+
+    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+    /* platform-independent notation is Unix-style already.  :)  */
+
+    if (prepend)
+        strcpy(retval, prepend);
+    else
+        retval[0] = '\0';
+
+    strcat(retval, dirName);
+
+    if (append)
+        strcat(retval, append);
+
+    return(retval);
+} /* __PHYSFS_platformCvtToDependent */
+
+
+
+void __PHYSFS_platformEnumerateFiles(const char *dirname,
+                                     int omitSymLinks,
+                                     PHYSFS_EnumFilesCallback callback,
+                                     const char *origdir,
+                                     void *callbackdata)
+{
+    DIR *dir;
+    struct dirent *ent;
+    int bufsize = 0;
+    char *buf = NULL;
+    int dlen = 0;
+
+    if (omitSymLinks)  /* !!! FIXME: this malloc sucks. */
+    {
+        dlen = strlen(dirname);
+        bufsize = dlen + 256;
+        buf = (char *) allocator.Malloc(bufsize);
+        if (buf == NULL)
+            return;
+        strcpy(buf, dirname);
+        if (buf[dlen - 1] != '/')
+        {
+            buf[dlen++] = '/';
+            buf[dlen] = '\0';
+        } /* if */
+    } /* if */
+
+    errno = 0;
+    dir = opendir(dirname);
+    if (dir == NULL)
+    {
+        allocator.Free(buf);
+        return;
+    } /* if */
+
+    while ((ent = readdir(dir)) != NULL)
+    {
+        if (strcmp(ent->d_name, ".") == 0)
+            continue;
+
+        if (strcmp(ent->d_name, "..") == 0)
+            continue;
+
+        if (omitSymLinks)
+        {
+            char *p;
+            int len = strlen(ent->d_name) + dlen + 1;
+            if (len > bufsize)
+            {
+                p = (char *) allocator.Realloc(buf, len);
+                if (p == NULL)
+                    continue;
+                buf = p;
+                bufsize = len;
+            } /* if */
+
+            strcpy(buf + dlen, ent->d_name);
+            if (__PHYSFS_platformIsSymLink(buf))
+                continue;
+        } /* if */
+
+        callback(callbackdata, origdir, ent->d_name);
+    } /* while */
+
+    allocator.Free(buf);
+    closedir(dir);
+} /* __PHYSFS_platformEnumerateFiles */
+
+
+int __PHYSFS_platformMkDir(const char *path)
+{
+    int rc;
+    errno = 0;
+    rc = mkdir(path, S_IRWXU);
+    BAIL_IF_MACRO(rc == -1, strerror(errno), 0);
+    return(1);
+} /* __PHYSFS_platformMkDir */
+
+
+static void *doOpen(const char *filename, int mode)
+{
+    int fd;
+    int *retval;
+    errno = 0;
+
+    fd = open(filename, mode, S_IRUSR | S_IWUSR);
+    BAIL_IF_MACRO(fd < 0, strerror(errno), NULL);
+
+    retval = (int *) allocator.Malloc(sizeof (int));
+    if (retval == NULL)
+    {
+        close(fd);
+        BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
+    } /* if */
+
+    *retval = fd;
+    return((void *) retval);
+} /* doOpen */
+
+
+void *__PHYSFS_platformOpenRead(const char *filename)
+{
+    return(doOpen(filename, O_RDONLY));
+} /* __PHYSFS_platformOpenRead */
+
+
+void *__PHYSFS_platformOpenWrite(const char *filename)
+{
+    return(doOpen(filename, O_WRONLY | O_CREAT | O_TRUNC));
+} /* __PHYSFS_platformOpenWrite */
+
+
+void *__PHYSFS_platformOpenAppend(const char *filename)
+{
+    return(doOpen(filename, O_WRONLY | O_CREAT | O_APPEND));
+} /* __PHYSFS_platformOpenAppend */
+
+
+PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
+                                    PHYSFS_uint32 size, PHYSFS_uint32 count)
+{
+    int fd = *((int *) opaque);
+    int max = size * count;
+    int rc = read(fd, buffer, max);
+
+    BAIL_IF_MACRO(rc == -1, strerror(errno), rc);
+    assert(rc <= max);
+
+    if ((rc < max) && (size > 1))
+        lseek(fd, -(rc % size), SEEK_CUR); /* rollback to object boundary. */
+
+    return(rc / size);
+} /* __PHYSFS_platformRead */
+
+
+PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
+                                     PHYSFS_uint32 size, PHYSFS_uint32 count)
+{
+    int fd = *((int *) opaque);
+    int max = size * count;
+    int rc = write(fd, (void *) buffer, max);
+
+    BAIL_IF_MACRO(rc == -1, strerror(errno), rc);
+    assert(rc <= max);
+
+    if ((rc < max) && (size > 1))
+        lseek(fd, -(rc % size), SEEK_CUR); /* rollback to object boundary. */
+
+    return(rc / size);
+} /* __PHYSFS_platformWrite */
+
+
+int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos)
+{
+    int fd = *((int *) opaque);
+
+    #ifdef PHYSFS_HAVE_LLSEEK
+      unsigned long offset_high = ((pos >> 32) & 0xFFFFFFFF);
+      unsigned long offset_low = (pos & 0xFFFFFFFF);
+      loff_t retoffset;
+      int rc = llseek(fd, offset_high, offset_low, &retoffset, SEEK_SET);
+      BAIL_IF_MACRO(rc == -1, strerror(errno), 0);
+    #else
+      BAIL_IF_MACRO(lseek(fd, (int) pos, SEEK_SET) == -1, strerror(errno), 0);
+    #endif
+
+    return(1);
+} /* __PHYSFS_platformSeek */
+
+
+PHYSFS_sint64 __PHYSFS_platformTell(void *opaque)
+{
+    int fd = *((int *) opaque);
+    PHYSFS_sint64 retval;
+
+    #ifdef PHYSFS_HAVE_LLSEEK
+      loff_t retoffset;
+      int rc = llseek(fd, 0, &retoffset, SEEK_CUR);
+      BAIL_IF_MACRO(rc == -1, strerror(errno), -1);
+      retval = (PHYSFS_sint64) retoffset;
+    #else
+      retval = (PHYSFS_sint64) lseek(fd, 0, SEEK_CUR);
+      BAIL_IF_MACRO(retval == -1, strerror(errno), -1);
+    #endif
+
+    return(retval);
+} /* __PHYSFS_platformTell */
+
+
+PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
+{
+    int fd = *((int *) opaque);
+    struct stat statbuf;
+    BAIL_IF_MACRO(fstat(fd, &statbuf) == -1, strerror(errno), -1);
+    return((PHYSFS_sint64) statbuf.st_size);
+} /* __PHYSFS_platformFileLength */
+
+
+int __PHYSFS_platformEOF(void *opaque)
+{
+    PHYSFS_sint64 pos = __PHYSFS_platformTell(opaque);
+    PHYSFS_sint64 len = __PHYSFS_platformFileLength(opaque);
+    return(pos >= len);
+} /* __PHYSFS_platformEOF */
+
+
+int __PHYSFS_platformFlush(void *opaque)
+{
+    int fd = *((int *) opaque);
+    BAIL_IF_MACRO(fsync(fd) == -1, strerror(errno), 0);
+    return(1);
+} /* __PHYSFS_platformFlush */
+
+
+int __PHYSFS_platformClose(void *opaque)
+{
+    int fd = *((int *) opaque);
+    BAIL_IF_MACRO(close(fd) == -1, strerror(errno), 0);
+    allocator.Free(opaque);
+    return(1);
+} /* __PHYSFS_platformClose */
+
+
+int __PHYSFS_platformDelete(const char *path)
+{
+    BAIL_IF_MACRO(remove(path) == -1, strerror(errno), 0);
+    return(1);
+} /* __PHYSFS_platformDelete */
+
+
+PHYSFS_sint64 __PHYSFS_platformGetLastModTime(const char *fname)
+{
+    struct stat statbuf;
+    BAIL_IF_MACRO(stat(fname, &statbuf) < 0, strerror(errno), -1);
+    return statbuf.st_mtime;
+} /* __PHYSFS_platformGetLastModTime */
+
+#endif  /* PHYSFS_PLATFORM_POSIX */
+
+/* end of posix.c ... */
+
diff --git a/src/unison/physfs-1.1.1/platform/unix.c b/src/unison/physfs-1.1.1/platform/unix.c
new file mode 100644 (file)
index 0000000..2b47cc9
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ * Unix support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_platforms.h"
+
+#ifdef PHYSFS_PLATFORM_UNIX
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <dirent.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/mount.h>
+
+#if (!defined PHYSFS_NO_PTHREADS_SUPPORT)
+#include <pthread.h>
+#endif
+
+#ifdef PHYSFS_HAVE_SYS_UCRED_H
+#  ifdef PHYSFS_HAVE_MNTENT_H
+#    undef PHYSFS_HAVE_MNTENT_H /* don't do both... */
+#  endif
+#  include <sys/ucred.h>
+#endif
+
+#ifdef PHYSFS_HAVE_MNTENT_H
+#include <mntent.h>
+#endif
+
+#include "physfs_internal.h"
+
+
+int __PHYSFS_platformInit(void)
+{
+    return(1);  /* always succeed. */
+} /* __PHYSFS_platformInit */
+
+
+int __PHYSFS_platformDeinit(void)
+{
+    return(1);  /* always succeed. */
+} /* __PHYSFS_platformDeinit */
+
+
+#ifdef PHYSFS_NO_CDROM_SUPPORT
+
+/* Stub version for platforms without CD-ROM support. */
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
+{
+} /* __PHYSFS_platformDetectAvailableCDs */
+
+#elif (defined PHYSFS_HAVE_SYS_UCRED_H)
+
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
+{
+    int i;
+    struct statfs *mntbufp = NULL;
+    int mounts = getmntinfo(&mntbufp, MNT_WAIT);
+
+    for (i = 0; i < mounts; i++)
+    {
+        int add_it = 0;
+
+        if (strcmp(mntbufp[i].f_fstypename, "iso9660") == 0)
+            add_it = 1;
+        else if (strcmp( mntbufp[i].f_fstypename, "cd9660") == 0)
+            add_it = 1;
+
+        /* add other mount types here */
+
+        if (add_it)
+            cb(data, mntbufp[i].f_mntonname);
+    } /* for */
+} /* __PHYSFS_platformDetectAvailableCDs */
+
+#elif (defined PHYSFS_HAVE_MNTENT_H)
+
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
+{
+    FILE *mounts = NULL;
+    struct mntent *ent = NULL;
+
+    mounts = setmntent("/etc/mtab", "r");
+    BAIL_IF_MACRO(mounts == NULL, ERR_IO_ERROR, /*return void*/);
+
+    while ( (ent = getmntent(mounts)) != NULL )
+    {
+        int add_it = 0;
+        if (strcmp(ent->mnt_type, "iso9660") == 0)
+            add_it = 1;
+
+        /* add other mount types here */
+
+        if (add_it)
+            cb(data, ent->mnt_dir);
+    } /* while */
+
+    endmntent(mounts);
+
+} /* __PHYSFS_platformDetectAvailableCDs */
+
+#endif
+
+
+/* this is in posix.c ... */
+extern char *__PHYSFS_platformCopyEnvironmentVariable(const char *varname);
+
+
+/*
+ * See where program (bin) resides in the $PATH specified by (envr).
+ *  returns a copy of the first element in envr that contains it, or NULL
+ *  if it doesn't exist or there were other problems. PHYSFS_SetError() is
+ *  called if we have a problem.
+ *
+ * (envr) will be scribbled over, and you are expected to allocator.Free() the
+ *  return value when you're done with it.
+ */
+static char *findBinaryInPath(const char *bin, char *envr)
+{
+    size_t alloc_size = 0;
+    char *exe = NULL;
+    char *start = envr;
+    char *ptr;
+
+    BAIL_IF_MACRO(bin == NULL, ERR_INVALID_ARGUMENT, NULL);
+    BAIL_IF_MACRO(envr == NULL, ERR_INVALID_ARGUMENT, NULL);
+
+    do
+    {
+        size_t size;
+        ptr = strchr(start, ':');  /* find next $PATH separator. */
+        if (ptr)
+            *ptr = '\0';
+
+        size = strlen(start) + strlen(bin) + 2;
+        if (size > alloc_size)
+        {
+            char *x = (char *) allocator.Realloc(exe, size);
+            if (x == NULL)
+            {
+                if (exe != NULL)
+                    allocator.Free(exe);
+                BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
+            } /* if */
+
+            alloc_size = size;
+            exe = x;
+        } /* if */
+
+        /* build full binary path... */
+        strcpy(exe, start);
+        if ((exe[0] == '\0') || (exe[strlen(exe) - 1] != '/'))
+            strcat(exe, "/");
+        strcat(exe, bin);
+
+        if (access(exe, X_OK) == 0)  /* Exists as executable? We're done. */
+        {
+            strcpy(exe, start);  /* i'm lazy. piss off. */
+            return(exe);
+        } /* if */
+
+        start = ptr + 1;  /* start points to beginning of next element. */
+    } while (ptr != NULL);
+
+    if (exe != NULL)
+        allocator.Free(exe);
+
+    return(NULL);  /* doesn't exist in path. */
+} /* findBinaryInPath */
+
+
+char *__PHYSFS_platformCalcBaseDir(const char *argv0)
+{
+    const char *PROC_SELF_EXE = "/proc/self/exe";
+    char *retval = NULL;
+    char *envr = NULL;
+    struct stat stbuf;
+
+    /* fast path: default behaviour can handle this. */
+    if ( (argv0 != NULL) && (strchr(argv0, '/') != NULL) )
+        return(NULL);  /* higher level will parse out real path from argv0. */
+
+    /*
+     * Try to avoid using argv0 unless forced to. If there's a Linux-like
+     *  /proc filesystem, you can get the full path to the current process from
+     *  the /proc/self/exe symlink.
+     */
+    if ((lstat(PROC_SELF_EXE, &stbuf) != -1) && (S_ISLNK(stbuf.st_mode)))
+    {
+        const size_t len = stbuf.st_size;
+        char *buf = (char *) allocator.Malloc(len+1);
+        if (buf != NULL)  /* if NULL, maybe you'll get lucky later. */
+        {
+            if (readlink(PROC_SELF_EXE, buf, len) != len)
+                allocator.Free(buf);
+            else
+            {
+                buf[len] = '\0';  /* readlink doesn't null-terminate. */
+                retval = buf;  /* we're good to go. */
+            } /* else */
+        } /* if */
+    } /* if */
+
+    if ((retval == NULL) && (argv0 != NULL))
+    {
+        /* If there's no dirsep on argv0, then look through $PATH for it. */
+        envr = __PHYSFS_platformCopyEnvironmentVariable("PATH");
+        BAIL_IF_MACRO(!envr, NULL, NULL);
+        retval = findBinaryInPath(argv0, envr);
+        allocator.Free(envr);
+    } /* if */
+
+    return(retval);
+} /* __PHYSFS_platformCalcBaseDir */
+
+
+char *__PHYSFS_platformRealPath(const char *path)
+{
+    char resolved_path[MAXPATHLEN];
+    char *retval = NULL;
+
+    errno = 0;
+    BAIL_IF_MACRO(!realpath(path, resolved_path), strerror(errno), NULL);
+    retval = (char *) allocator.Malloc(strlen(resolved_path) + 1);
+    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+    strcpy(retval, resolved_path);
+
+    return(retval);
+} /* __PHYSFS_platformRealPath */
+
+
+char *__PHYSFS_platformCurrentDir(void)
+{
+    /*
+     * This can't just do platformRealPath("."), since that would eventually
+     *  just end up calling back into here.
+     */
+
+    int allocSize = 0;
+    char *retval = NULL;
+    char *ptr;
+
+    do
+    {
+        allocSize += 100;
+        ptr = (char *) allocator.Realloc(retval, allocSize);
+        if (ptr == NULL)
+        {
+            if (retval != NULL)
+                allocator.Free(retval);
+            BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
+        } /* if */
+
+        retval = ptr;
+        ptr = getcwd(retval, allocSize);
+    } while (ptr == NULL && errno == ERANGE);
+
+    if (ptr == NULL && errno)
+    {
+            /*
+             * getcwd() failed for some reason, for example current
+             * directory not existing.
+             */
+        if (retval != NULL)
+            allocator.Free(retval);
+        BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
+    } /* if */
+
+    return(retval);
+} /* __PHYSFS_platformCurrentDir */
+
+
+int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
+{
+    return(0);  /* just use malloc() and friends. */
+} /* __PHYSFS_platformSetDefaultAllocator */
+
+
+#if (defined PHYSFS_NO_PTHREADS_SUPPORT)
+
+PHYSFS_uint64 __PHYSFS_platformGetThreadID(void) { return(0x0001); }
+void *__PHYSFS_platformCreateMutex(void) { return((void *) 0x0001); }
+void __PHYSFS_platformDestroyMutex(void *mutex) {}
+int __PHYSFS_platformGrabMutex(void *mutex) { return(1); }
+void __PHYSFS_platformReleaseMutex(void *mutex) {}
+
+#else
+
+typedef struct
+{
+    pthread_mutex_t mutex;
+    pthread_t owner;
+    PHYSFS_uint32 count;
+} PthreadMutex;
+
+/* Just in case; this is a panic value. */
+#if ((!defined SIZEOF_INT) || (SIZEOF_INT <= 0))
+#  define SIZEOF_INT 4
+#endif
+
+#if (SIZEOF_INT == 4)
+#  define PHTREAD_TO_UI64(thr) ( (PHYSFS_uint64) ((PHYSFS_uint32) (thr)) )
+#elif (SIZEOF_INT == 2)
+#  define PHTREAD_TO_UI64(thr) ( (PHYSFS_uint64) ((PHYSFS_uint16) (thr)) )
+#elif (SIZEOF_INT == 1)
+#  define PHTREAD_TO_UI64(thr) ( (PHYSFS_uint64) ((PHYSFS_uint8) (thr)) )
+#else
+#  define PHTREAD_TO_UI64(thr) ((PHYSFS_uint64) (thr))
+#endif
+
+PHYSFS_uint64 __PHYSFS_platformGetThreadID(void)
+{
+    return(PHTREAD_TO_UI64(pthread_self()));
+} /* __PHYSFS_platformGetThreadID */
+
+
+void *__PHYSFS_platformCreateMutex(void)
+{
+    int rc;
+    PthreadMutex *m = (PthreadMutex *) allocator.Malloc(sizeof (PthreadMutex));
+    BAIL_IF_MACRO(m == NULL, ERR_OUT_OF_MEMORY, NULL);
+    rc = pthread_mutex_init(&m->mutex, NULL);
+    if (rc != 0)
+    {
+        allocator.Free(m);
+        BAIL_MACRO(strerror(rc), NULL);
+    } /* if */
+
+    m->count = 0;
+    m->owner = (pthread_t) 0xDEADBEEF;
+    return((void *) m);
+} /* __PHYSFS_platformCreateMutex */
+
+
+void __PHYSFS_platformDestroyMutex(void *mutex)
+{
+    PthreadMutex *m = (PthreadMutex *) mutex;
+
+    /* Destroying a locked mutex is a bug, but we'll try to be helpful. */
+    if ((m->owner == pthread_self()) && (m->count > 0))
+        pthread_mutex_unlock(&m->mutex);
+
+    pthread_mutex_destroy(&m->mutex);
+    allocator.Free(m);
+} /* __PHYSFS_platformDestroyMutex */
+
+
+int __PHYSFS_platformGrabMutex(void *mutex)
+{
+    PthreadMutex *m = (PthreadMutex *) mutex;
+    pthread_t tid = pthread_self();
+    if (m->owner != tid)
+    {
+        if (pthread_mutex_lock(&m->mutex) != 0)
+            return(0);
+        m->owner = tid;
+    } /* if */
+
+    m->count++;
+    return(1);
+} /* __PHYSFS_platformGrabMutex */
+
+
+void __PHYSFS_platformReleaseMutex(void *mutex)
+{
+    PthreadMutex *m = (PthreadMutex *) mutex;
+    if (m->owner == pthread_self())
+    {
+        if (--m->count == 0)
+        {
+            m->owner = (pthread_t) 0xDEADBEEF;
+            pthread_mutex_unlock(&m->mutex);
+        } /* if */
+    } /* if */
+} /* __PHYSFS_platformReleaseMutex */
+
+#endif /* !PHYSFS_NO_PTHREADS_SUPPORT */
+
+#endif /* PHYSFS_PLATFORM_UNIX */
+
+/* end of unix.c ... */
+
diff --git a/src/unison/physfs-1.1.1/platform/windows.c b/src/unison/physfs-1.1.1/platform/windows.c
new file mode 100644 (file)
index 0000000..c9f9ee8
--- /dev/null
@@ -0,0 +1,1395 @@
+/*
+ * Windows support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon, and made sane by Gregory S. Read.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_platforms.h"
+
+#ifdef PHYSFS_PLATFORM_WINDOWS
+
+/* Forcibly disable UNICODE, since we manage this ourselves. */
+#ifdef UNICODE
+#undef UNICODE
+#endif
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+
+#include "physfs_internal.h"
+
+#define LOWORDER_UINT64(pos) (PHYSFS_uint32) \
+    (pos & 0x00000000FFFFFFFF)
+#define HIGHORDER_UINT64(pos) (PHYSFS_uint32) \
+    (((pos & 0xFFFFFFFF00000000) >> 32) & 0x00000000FFFFFFFF)
+
+/*
+ * Users without the platform SDK don't have this defined.  The original docs
+ *  for SetFilePointer() just said to compare with 0xFFFFFFFF, so this should
+ *  work as desired.
+ */
+#define PHYSFS_INVALID_SET_FILE_POINTER  0xFFFFFFFF
+
+/* just in case... */
+#define PHYSFS_INVALID_FILE_ATTRIBUTES   0xFFFFFFFF
+
+/* Not defined before the Vista SDK. */
+#define PHYSFS_IO_REPARSE_TAG_SYMLINK    0xA000000C
+
+
+#define UTF8_TO_UNICODE_STACK_MACRO(w_assignto, str) { \
+    if (str == NULL) \
+        w_assignto = NULL; \
+    else { \
+        const PHYSFS_uint64 len = (PHYSFS_uint64) ((strlen(str) * 4) + 1); \
+        w_assignto = (WCHAR *) __PHYSFS_smallAlloc(len); \
+        if (w_assignto != NULL) \
+            PHYSFS_utf8ToUcs2(str, (PHYSFS_uint16 *) w_assignto, len); \
+    } \
+} \
+
+static PHYSFS_uint64 wStrLen(const WCHAR *wstr)
+{
+    PHYSFS_uint64 len = 0;
+    while (*(wstr++))
+        len++;
+    return(len);
+} /* wStrLen */
+
+static char *unicodeToUtf8Heap(const WCHAR *w_str)
+{
+    char *retval = NULL;
+    if (w_str != NULL)
+    {
+        void *ptr = NULL;
+        const PHYSFS_uint64 len = (wStrLen(w_str) * 4) + 1;
+        retval = allocator.Malloc(len);
+        BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+        PHYSFS_utf8FromUcs2((const PHYSFS_uint16 *) w_str, retval, len);
+        ptr = allocator.Realloc(retval, strlen(retval) + 1); /* shrink. */
+        if (ptr != NULL)
+            retval = (char *) ptr;
+    } /* if */
+    return(retval);
+} /* unicodeToUtf8Heap */
+
+
+static char *codepageToUtf8Heap(const char *cpstr)
+{
+    char *retval = NULL;
+    if (cpstr != NULL)
+    {
+        const int len = (int) (strlen(cpstr) + 1);
+        WCHAR *wbuf = (WCHAR *) __PHYSFS_smallAlloc(len * sizeof (WCHAR));
+        BAIL_IF_MACRO(wbuf == NULL, ERR_OUT_OF_MEMORY, NULL);
+        MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, cpstr, len, wbuf, len);
+        retval = (char *) allocator.Malloc(len * 4);
+        if (retval == NULL)
+            __PHYSFS_setError(ERR_OUT_OF_MEMORY);
+        else
+            PHYSFS_utf8FromUcs2(wbuf, retval, len * 4);
+        __PHYSFS_smallFree(wbuf);
+    } /* if */
+    return(retval);
+} /* codepageToUtf8Heap */
+
+
+typedef struct
+{
+    HANDLE handle;
+    int readonly;
+} WinApiFile;
+
+
+static char *userDir = NULL;
+static int osHasUnicode = 0;
+
+
+/* pointers for APIs that may not exist on some Windows versions... */
+static HANDLE libKernel32 = NULL;
+static HANDLE libUserEnv = NULL;
+static HANDLE libAdvApi32 = NULL;
+static DWORD (WINAPI *pGetModuleFileNameW)(HMODULE, LPWCH, DWORD);
+static BOOL (WINAPI *pGetUserProfileDirectoryW)(HANDLE, LPWSTR, LPDWORD);
+static BOOL (WINAPI *pGetUserNameW)(LPWSTR, LPDWORD);
+static DWORD (WINAPI *pGetFileAttributesW)(LPCWSTR);
+static HANDLE (WINAPI *pFindFirstFileW)(LPCWSTR, LPWIN32_FIND_DATAW);
+static BOOL (WINAPI *pFindNextFileW)(HANDLE, LPWIN32_FIND_DATAW);
+static DWORD (WINAPI *pGetCurrentDirectoryW)(DWORD, LPWSTR);
+static BOOL (WINAPI *pDeleteFileW)(LPCWSTR);
+static BOOL (WINAPI *pRemoveDirectoryW)(LPCWSTR);
+static BOOL (WINAPI *pCreateDirectoryW)(LPCWSTR, LPSECURITY_ATTRIBUTES);
+static BOOL (WINAPI *pGetFileAttributesExA)
+    (LPCSTR, GET_FILEEX_INFO_LEVELS, LPVOID);
+static BOOL (WINAPI *pGetFileAttributesExW)
+    (LPCWSTR, GET_FILEEX_INFO_LEVELS, LPVOID);
+static DWORD (WINAPI *pFormatMessageW)
+    (DWORD, LPCVOID, DWORD, DWORD, LPWSTR, DWORD, va_list *);
+static HANDLE (WINAPI *pCreateFileW)
+    (LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE);
+
+
+/*
+ * Fallbacks for missing Unicode functions on Win95/98/ME. These are filled
+ *  into the function pointers if looking up the real Unicode entry points
+ *  in the system DLLs fails, so they're never used on WinNT/XP/Vista/etc.
+ * They make an earnest effort to convert to/from UTF-8 and UCS-2 to 
+ *  the user's current codepage.
+ */
+
+static BOOL WINAPI fallbackGetUserNameW(LPWSTR buf, LPDWORD len)
+{
+    const DWORD cplen = *len;
+    char *cpstr = __PHYSFS_smallAlloc(cplen);
+    BOOL retval = GetUserNameA(cpstr, len);
+    if (buf != NULL)
+        MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, cpstr, cplen, buf, *len);
+    __PHYSFS_smallFree(cpstr);
+    return(retval);
+} /* fallbackGetUserNameW */
+
+static DWORD WINAPI fallbackFormatMessageW(DWORD dwFlags, LPCVOID lpSource,
+                                           DWORD dwMessageId, DWORD dwLangId,
+                                           LPWSTR lpBuf, DWORD nSize,
+                                           va_list *Arguments)
+{
+    char *cpbuf = (char *) __PHYSFS_smallAlloc(nSize);
+    DWORD retval = FormatMessageA(dwFlags, lpSource, dwMessageId, dwLangId,
+                                  cpbuf, nSize, Arguments);
+    if (retval > 0)
+        MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,cpbuf,retval,lpBuf,nSize);
+    __PHYSFS_smallFree(cpbuf);
+    return(retval);
+} /* fallbackFormatMessageW */
+
+static DWORD WINAPI fallbackGetModuleFileNameW(HMODULE hMod, LPWCH lpBuf,
+                                               DWORD nSize)
+{
+    char *cpbuf = (char *) __PHYSFS_smallAlloc(nSize);
+    DWORD retval = GetModuleFileNameA(hMod, cpbuf, nSize);
+    if (retval > 0)
+        MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,cpbuf,retval,lpBuf,nSize);
+    __PHYSFS_smallFree(cpbuf);
+    return(retval);
+} /* fallbackGetModuleFileNameW */
+
+static DWORD WINAPI fallbackGetFileAttributesW(LPCWSTR fname)
+{
+    DWORD retval = 0;
+    const int buflen = (int) (wStrLen(fname) + 1);
+    char *cpstr = (char *) __PHYSFS_smallAlloc(buflen);
+    WideCharToMultiByte(CP_ACP, 0, fname, buflen, cpstr, buflen, NULL, NULL);
+    retval = GetFileAttributesA(cpstr);
+    __PHYSFS_smallFree(cpstr);
+    return(retval);
+} /* fallbackGetFileAttributesW */
+
+static DWORD WINAPI fallbackGetCurrentDirectoryW(DWORD buflen, LPWSTR buf)
+{
+    DWORD retval = 0;
+    char *cpbuf = NULL;
+    if (buf != NULL)
+        cpbuf = (char *) __PHYSFS_smallAlloc(buflen);
+    retval = GetCurrentDirectoryA(buflen, cpbuf);
+    if (cpbuf != NULL)
+    {
+        MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,cpbuf,retval,buf,buflen);
+        __PHYSFS_smallFree(cpbuf);
+    } /* if */
+    return(retval);
+} /* fallbackGetCurrentDirectoryW */
+
+static BOOL WINAPI fallbackRemoveDirectoryW(LPCWSTR dname)
+{
+    BOOL retval = 0;
+    const int buflen = (int) (wStrLen(dname) + 1);
+    char *cpstr = (char *) __PHYSFS_smallAlloc(buflen);
+    WideCharToMultiByte(CP_ACP, 0, dname, buflen, cpstr, buflen, NULL, NULL);
+    retval = RemoveDirectoryA(cpstr);
+    __PHYSFS_smallFree(cpstr);
+    return(retval);
+} /* fallbackRemoveDirectoryW */
+
+static BOOL WINAPI fallbackCreateDirectoryW(LPCWSTR dname, 
+                                            LPSECURITY_ATTRIBUTES attr)
+{
+    BOOL retval = 0;
+    const int buflen = (int) (wStrLen(dname) + 1);
+    char *cpstr = (char *) __PHYSFS_smallAlloc(buflen);
+    WideCharToMultiByte(CP_ACP, 0, dname, buflen, cpstr, buflen, NULL, NULL);
+    retval = CreateDirectoryA(cpstr, attr);
+    __PHYSFS_smallFree(cpstr);
+    return(retval);
+} /* fallbackCreateDirectoryW */
+
+static BOOL WINAPI fallbackDeleteFileW(LPCWSTR fname)
+{
+    BOOL retval = 0;
+    const int buflen = (int) (wStrLen(fname) + 1);
+    char *cpstr = (char *) __PHYSFS_smallAlloc(buflen);
+    WideCharToMultiByte(CP_ACP, 0, fname, buflen, cpstr, buflen, NULL, NULL);
+    retval = DeleteFileA(cpstr);
+    __PHYSFS_smallFree(cpstr);
+    return(retval);
+} /* fallbackDeleteFileW */
+
+static HANDLE WINAPI fallbackCreateFileW(LPCWSTR fname, 
+                DWORD dwDesiredAccess, DWORD dwShareMode,
+                LPSECURITY_ATTRIBUTES lpSecurityAttrs,
+                DWORD dwCreationDisposition,
+                DWORD dwFlagsAndAttrs, HANDLE hTemplFile)
+{
+    HANDLE retval;
+    const int buflen = (int) (wStrLen(fname) + 1);
+    char *cpstr = (char *) __PHYSFS_smallAlloc(buflen);
+    WideCharToMultiByte(CP_ACP, 0, fname, buflen, cpstr, buflen, NULL, NULL);
+    retval = CreateFileA(cpstr, dwDesiredAccess, dwShareMode, lpSecurityAttrs,
+                         dwCreationDisposition, dwFlagsAndAttrs, hTemplFile);
+    __PHYSFS_smallFree(cpstr);
+    return(retval);
+} /* fallbackCreateFileW */
+
+
+/* A blatant abuse of pointer casting... */
+static int symLookup(HMODULE dll, void **addr, const char *sym)
+{
+    return( (*addr = GetProcAddress(dll, sym)) != NULL );
+} /* symLookup */
+
+
+static int findApiSymbols(void)
+{
+    HMODULE dll = NULL;
+
+    #define LOOKUP_NOFALLBACK(x, reallyLook) { \
+        if (reallyLook) \
+            symLookup(dll, (void **) &p##x, #x); \
+        else \
+            p##x = NULL; \
+    }
+
+    #define LOOKUP(x, reallyLook) { \
+        if ((!reallyLook) || (!symLookup(dll, (void **) &p##x, #x))) \
+            p##x = fallback##x; \
+    }
+
+    /* Apparently Win9x HAS the Unicode entry points, they just don't WORK. */
+    /*  ...so don't look them up unless we're on NT+. (see osHasUnicode.) */
+
+    dll = libUserEnv = LoadLibraryA("userenv.dll");
+    if (dll != NULL)
+        LOOKUP_NOFALLBACK(GetUserProfileDirectoryW, osHasUnicode);
+
+    /* !!! FIXME: what do they call advapi32.dll on Win64? */
+    dll = libAdvApi32 = LoadLibraryA("advapi32.dll");
+    if (dll != NULL)
+        LOOKUP(GetUserNameW, osHasUnicode);
+
+    /* !!! FIXME: what do they call kernel32.dll on Win64? */
+    dll = libKernel32 = LoadLibraryA("kernel32.dll");
+    if (dll != NULL)
+    {
+        LOOKUP_NOFALLBACK(GetFileAttributesExA, 1);
+        LOOKUP_NOFALLBACK(GetFileAttributesExW, osHasUnicode);
+        LOOKUP_NOFALLBACK(FindFirstFileW, osHasUnicode);
+        LOOKUP_NOFALLBACK(FindNextFileW, osHasUnicode);
+        LOOKUP(GetModuleFileNameW, osHasUnicode);
+        LOOKUP(FormatMessageW, osHasUnicode);
+        LOOKUP(GetFileAttributesW, osHasUnicode);
+        LOOKUP(GetCurrentDirectoryW, osHasUnicode);
+        LOOKUP(CreateDirectoryW, osHasUnicode);
+        LOOKUP(RemoveDirectoryW, osHasUnicode);
+        LOOKUP(CreateFileW, osHasUnicode);
+        LOOKUP(DeleteFileW, osHasUnicode);
+    } /* if */
+
+    #undef LOOKUP_NOFALLBACK
+    #undef LOOKUP
+
+    return(1);
+} /* findApiSymbols */
+
+
+const char *__PHYSFS_platformDirSeparator = "\\";
+
+
+/*
+ * Figure out what the last failing Windows API call was, and
+ *  generate a human-readable string for the error message.
+ *
+ * The return value is a static buffer that is overwritten with
+ *  each call to this function.
+ */
+static const char *winApiStrError(void)
+{
+    static char utf8buf[255];
+    WCHAR msgbuf[255];
+    WCHAR *ptr;
+    DWORD rc = pFormatMessageW(
+                    FORMAT_MESSAGE_FROM_SYSTEM |
+                    FORMAT_MESSAGE_IGNORE_INSERTS,
+                    NULL, GetLastError(),
+                    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                    msgbuf, __PHYSFS_ARRAYLEN(msgbuf),
+                    NULL);
+
+    /* chop off newlines. */
+    for (ptr = msgbuf; *ptr; ptr++)
+    {
+        if ((*ptr == '\n') || (*ptr == '\r'))
+        {
+            *ptr = '\0';
+            break;
+        } /* if */
+    } /* for */
+
+    /* may truncate, but oh well. */
+    PHYSFS_utf8FromUcs2((PHYSFS_uint16 *) msgbuf, utf8buf, sizeof (utf8buf));
+    return((const char *) utf8buf);
+} /* winApiStrError */
+
+
+static char *getExePath(void)
+{
+    DWORD buflen = 64;
+    int success = 0;
+    LPWSTR modpath = NULL;
+    char *retval = NULL;
+
+    while (1)
+    {
+        DWORD rc;
+        void *ptr;
+
+        if ( !(ptr = allocator.Realloc(modpath, buflen*sizeof(WCHAR))) )
+        {
+            allocator.Free(modpath);
+            BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
+        } /* if */
+        modpath = (LPWSTR) ptr;
+
+        rc = pGetModuleFileNameW(NULL, modpath, buflen);
+        if (rc == 0)
+        {
+            allocator.Free(modpath);
+            BAIL_MACRO(winApiStrError(), NULL);
+        } /* if */
+
+        if (rc < buflen)
+        {
+            buflen = rc;
+            break;
+        } /* if */
+
+        buflen *= 2;
+    } /* while */
+
+    if (buflen > 0)  /* just in case... */
+    {
+        WCHAR *ptr = (modpath + buflen) - 1;
+        while (ptr != modpath)
+        {
+            if (*ptr == '\\')
+                break;
+            ptr--;
+        } /* while */
+
+        if ((ptr == modpath) && (*ptr != '\\'))
+            __PHYSFS_setError(ERR_GETMODFN_NO_DIR);
+        else
+        {
+            *(ptr + 1) = '\0';  /* chop off filename. */
+            retval = unicodeToUtf8Heap(modpath);
+        } /* else */
+    } /* else */
+    allocator.Free(modpath);
+
+    return(retval);   /* w00t. */
+} /* getExePath */
+
+
+/*
+ * Try to make use of GetUserProfileDirectoryW(), which isn't available on
+ *  some common variants of Win32. If we can't use this, we just punt and
+ *  use the physfs base dir for the user dir, too.
+ *
+ * On success, module-scope variable (userDir) will have a pointer to
+ *  a malloc()'d string of the user's profile dir, and a non-zero value is
+ *  returned. If we can't determine the profile dir, (userDir) will
+ *  be NULL, and zero is returned.
+ */
+static int determineUserDir(void)
+{
+    if (userDir != NULL)
+        return(1);  /* already good to go. */
+
+    /*
+     * GetUserProfileDirectoryW() is only available on NT 4.0 and later.
+     *  This means Win95/98/ME (and CE?) users have to do without, so for
+     *  them, we'll default to the base directory when we can't get the
+     *  function pointer. Since this is originally an NT API, we don't
+        *  offer a non-Unicode fallback.
+     */
+    if (pGetUserProfileDirectoryW != NULL)
+    {
+        HANDLE accessToken = NULL;       /* Security handle to process */
+        HANDLE processHandle = GetCurrentProcess();
+        if (OpenProcessToken(processHandle, TOKEN_QUERY, &accessToken))
+        {
+            DWORD psize = 0;
+            WCHAR dummy = 0;
+            LPWSTR wstr = NULL;
+            BOOL rc = 0;
+
+            /*
+             * Should fail. Will write the size of the profile path in
+             *  psize. Also note that the second parameter can't be
+             *  NULL or the function fails.
+             */        
+               rc = pGetUserProfileDirectoryW(accessToken, &dummy, &psize);
+            assert(!rc);  /* !!! FIXME: handle this gracefully. */
+
+            /* Allocate memory for the profile directory */
+            wstr = (LPWSTR) __PHYSFS_smallAlloc(psize * sizeof (WCHAR));
+            if (wstr != NULL)
+            {
+                if (pGetUserProfileDirectoryW(accessToken, wstr, &psize))
+                    userDir = unicodeToUtf8Heap(wstr);
+                __PHYSFS_smallFree(wstr);
+            } /* else */
+        } /* if */
+
+        CloseHandle(accessToken);
+    } /* if */
+
+    if (userDir == NULL)  /* couldn't get profile for some reason. */
+    {
+        /* Might just be a non-NT system; resort to the basedir. */
+        userDir = getExePath();
+        BAIL_IF_MACRO(userDir == NULL, NULL, 0); /* STILL failed?! */
+    } /* if */
+
+    return(1);  /* We made it: hit the showers. */
+} /* determineUserDir */
+
+
+static BOOL mediaInDrive(const char *drive)
+{
+    UINT oldErrorMode;
+    DWORD tmp;
+    BOOL retval;
+
+    /* Prevent windows warning message appearing when checking media size */
+    oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+    
+    /* If this function succeeds, there's media in the drive */
+    retval = GetVolumeInformationA(drive, NULL, 0, NULL, NULL, &tmp, NULL, 0);
+
+    /* Revert back to old windows error handler */
+    SetErrorMode(oldErrorMode);
+
+    return(retval);
+} /* mediaInDrive */
+
+
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
+{
+    /* !!! FIXME: Can CD drives be non-drive letter paths? */
+    /* !!! FIXME:  (so can they be Unicode paths?) */
+    char drive_str[4] = "x:\\";
+    char ch;
+    for (ch = 'A'; ch <= 'Z'; ch++)
+    {
+        drive_str[0] = ch;
+        if (GetDriveType(drive_str) == DRIVE_CDROM && mediaInDrive(drive_str))
+            cb(data, drive_str);
+    } /* for */
+} /* __PHYSFS_platformDetectAvailableCDs */
+
+
+char *__PHYSFS_platformCalcBaseDir(const char *argv0)
+{
+    if ((argv0 != NULL) && (strchr(argv0, '\\') != NULL))
+        return(NULL); /* default behaviour can handle this. */
+
+    return(getExePath());
+} /* __PHYSFS_platformCalcBaseDir */
+
+
+char *__PHYSFS_platformGetUserName(void)
+{
+    DWORD bufsize = 0;
+    char *retval = NULL;
+    
+    if (pGetUserNameW(NULL, &bufsize) == 0)  /* This SHOULD fail. */
+    {
+        LPWSTR wbuf = (LPWSTR) __PHYSFS_smallAlloc(bufsize * sizeof (WCHAR));
+        BAIL_IF_MACRO(wbuf == NULL, ERR_OUT_OF_MEMORY, NULL);
+        if (pGetUserNameW(wbuf, &bufsize) == 0)  /* ?! */
+            __PHYSFS_setError(winApiStrError());
+        else
+            retval = unicodeToUtf8Heap(wbuf);
+        __PHYSFS_smallFree(wbuf);
+    } /* if */
+
+    return(retval);
+} /* __PHYSFS_platformGetUserName */
+
+
+char *__PHYSFS_platformGetUserDir(void)
+{
+    char *retval = (char *) allocator.Malloc(strlen(userDir) + 1);
+    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+    strcpy(retval, userDir); /* calculated at init time. */
+    return(retval);
+} /* __PHYSFS_platformGetUserDir */
+
+
+PHYSFS_uint64 __PHYSFS_platformGetThreadID(void)
+{
+    return((PHYSFS_uint64) GetCurrentThreadId());
+} /* __PHYSFS_platformGetThreadID */
+
+
+static int doPlatformExists(LPWSTR wpath)
+{
+    BAIL_IF_MACRO
+    (
+        pGetFileAttributesW(wpath) == PHYSFS_INVALID_FILE_ATTRIBUTES,
+        winApiStrError(), 0
+    );
+    return(1);
+} /* doPlatformExists */
+
+
+int __PHYSFS_platformExists(const char *fname)
+{
+    int retval = 0;
+    LPWSTR wpath;
+    UTF8_TO_UNICODE_STACK_MACRO(wpath, fname);
+    BAIL_IF_MACRO(wpath == NULL, ERR_OUT_OF_MEMORY, 0);
+    retval = doPlatformExists(wpath);
+    __PHYSFS_smallFree(wpath);
+    return(retval);
+} /* __PHYSFS_platformExists */
+
+
+static int isSymlinkAttrs(const DWORD attr, const DWORD tag)
+{
+    return ( (attr & FILE_ATTRIBUTE_REPARSE_POINT) && 
+             (tag == PHYSFS_IO_REPARSE_TAG_SYMLINK) );
+} /* isSymlinkAttrs */
+
+
+int __PHYSFS_platformIsSymLink(const char *fname)
+{
+    /* !!! FIXME:
+     * Windows Vista can have NTFS symlinks. Can older Windows releases have
+     *  them when talking to a network file server? What happens when you
+     *  mount a NTFS partition on XP that was plugged into a Vista install
+     *  that made a symlink?
+     */
+
+    int retval = 0;
+    LPWSTR wpath;
+    HANDLE dir;
+    WIN32_FIND_DATAW entw;
+
+    /* no unicode entry points? Probably no symlinks. */
+    BAIL_IF_MACRO(pFindFirstFileW == NULL, NULL, 0);
+
+    UTF8_TO_UNICODE_STACK_MACRO(wpath, fname);
+    BAIL_IF_MACRO(wpath == NULL, ERR_OUT_OF_MEMORY, 0);
+
+    /* !!! FIXME: filter wildcard chars? */
+    dir = pFindFirstFileW(wpath, &entw);
+    if (dir != INVALID_HANDLE_VALUE)
+    {
+        retval = isSymlinkAttrs(entw.dwFileAttributes, entw.dwReserved0);
+        FindClose(dir);
+    } /* if */
+
+    __PHYSFS_smallFree(wpath);
+    return(retval);
+} /* __PHYSFS_platformIsSymlink */
+
+
+int __PHYSFS_platformIsDirectory(const char *fname)
+{
+    int retval = 0;
+    LPWSTR wpath;
+    UTF8_TO_UNICODE_STACK_MACRO(wpath, fname);
+    BAIL_IF_MACRO(wpath == NULL, ERR_OUT_OF_MEMORY, 0);
+    retval = ((pGetFileAttributesW(wpath) & FILE_ATTRIBUTE_DIRECTORY) != 0);
+    __PHYSFS_smallFree(wpath);
+    return(retval);
+} /* __PHYSFS_platformIsDirectory */
+
+
+char *__PHYSFS_platformCvtToDependent(const char *prepend,
+                                      const char *dirName,
+                                      const char *append)
+{
+    int len = ((prepend) ? strlen(prepend) : 0) +
+              ((append) ? strlen(append) : 0) +
+              strlen(dirName) + 1;
+    char *retval = (char *) allocator.Malloc(len);
+    char *p;
+
+    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+    if (prepend)
+        strcpy(retval, prepend);
+    else
+        retval[0] = '\0';
+
+    strcat(retval, dirName);
+
+    if (append)
+        strcat(retval, append);
+
+    for (p = strchr(retval, '/'); p != NULL; p = strchr(p + 1, '/'))
+        *p = '\\';
+
+    return(retval);
+} /* __PHYSFS_platformCvtToDependent */
+
+
+void __PHYSFS_platformEnumerateFiles(const char *dirname,
+                                     int omitSymLinks,
+                                     PHYSFS_EnumFilesCallback callback,
+                                     const char *origdir,
+                                     void *callbackdata)
+{
+    const int unicode = (pFindFirstFileW != NULL) && (pFindNextFileW != NULL);
+    HANDLE dir = INVALID_HANDLE_VALUE;
+    WIN32_FIND_DATA ent;
+    WIN32_FIND_DATAW entw;
+    size_t len = strlen(dirname);
+    char *searchPath = NULL;
+    WCHAR *wSearchPath = NULL;
+    char *utf8 = NULL;
+
+    /* Allocate a new string for path, maybe '\\', "*", and NULL terminator */
+    searchPath = (char *) __PHYSFS_smallAlloc(len + 3);
+    if (searchPath == NULL)
+        return;
+
+    /* Copy current dirname */
+    strcpy(searchPath, dirname);
+
+    /* if there's no '\\' at the end of the path, stick one in there. */
+    if (searchPath[len - 1] != '\\')
+    {
+        searchPath[len++] = '\\';
+        searchPath[len] = '\0';
+    } /* if */
+
+    /* Append the "*" to the end of the string */
+    strcat(searchPath, "*");
+
+    UTF8_TO_UNICODE_STACK_MACRO(wSearchPath, searchPath);
+    if (wSearchPath == NULL)
+        return;  /* oh well. */
+
+    if (unicode)
+        dir = pFindFirstFileW(wSearchPath, &entw);
+    else
+    {
+        const int len = (int) (wStrLen(wSearchPath) + 1);
+        char *cp = (char *) __PHYSFS_smallAlloc(len);
+        if (cp != NULL)
+        {
+            WideCharToMultiByte(CP_ACP, 0, wSearchPath, len, cp, len, 0, 0);
+            dir = FindFirstFileA(cp, &ent);
+            __PHYSFS_smallFree(cp);
+        } /* if */
+    } /* else */
+
+    __PHYSFS_smallFree(wSearchPath);
+    __PHYSFS_smallFree(searchPath);
+    if (dir == INVALID_HANDLE_VALUE)
+        return;
+
+    if (unicode)
+    {
+        do
+        {
+            const DWORD attr = entw.dwFileAttributes;
+            const DWORD tag = entw.dwReserved0;
+            const WCHAR *fn = entw.cFileName;
+            if ((fn[0] == '.') && (fn[1] == '\0'))
+                continue;
+            if ((fn[0] == '.') && (fn[1] == '.') && (fn[2] == '\0'))
+                continue;
+            if ((omitSymLinks) && (isSymlinkAttrs(attr, tag)))
+                continue;
+
+            utf8 = unicodeToUtf8Heap(fn);
+            if (utf8 != NULL)
+            {
+                callback(callbackdata, origdir, utf8);
+                allocator.Free(utf8);
+            } /* if */
+        } while (pFindNextFileW(dir, &entw) != 0);
+    } /* if */
+
+    else  /* ANSI fallback. */
+    {
+        do
+        {
+            const DWORD attr = ent.dwFileAttributes;
+            const DWORD tag = ent.dwReserved0;
+            const char *fn = ent.cFileName;
+            if ((fn[0] == '.') && (fn[1] == '\0'))
+                continue;
+            if ((fn[0] == '.') && (fn[1] == '.') && (fn[2] == '\0'))
+                continue;
+            if ((omitSymLinks) && (isSymlinkAttrs(attr, tag)))
+                continue;
+
+            utf8 = codepageToUtf8Heap(fn);
+            if (utf8 != NULL)
+            {
+                callback(callbackdata, origdir, utf8);
+                allocator.Free(utf8);
+            } /* if */
+        } while (FindNextFileA(dir, &ent) != 0);
+    } /* else */
+
+    FindClose(dir);
+} /* __PHYSFS_platformEnumerateFiles */
+
+
+char *__PHYSFS_platformCurrentDir(void)
+{
+    char *retval = NULL;
+    WCHAR *wbuf = NULL;
+    DWORD buflen = 0;
+
+    buflen = pGetCurrentDirectoryW(buflen, NULL);
+    wbuf = (WCHAR *) __PHYSFS_smallAlloc((buflen + 2) * sizeof (WCHAR));
+    BAIL_IF_MACRO(wbuf == NULL, ERR_OUT_OF_MEMORY, NULL);
+    pGetCurrentDirectoryW(buflen, wbuf);
+
+    if (wbuf[buflen - 2] == '\\')
+        wbuf[buflen-1] = '\0';  /* just in case... */
+    else
+    {
+        wbuf[buflen - 1] = '\\'; 
+        wbuf[buflen] = '\0'; 
+    } /* else */
+
+    retval = unicodeToUtf8Heap(wbuf);
+    __PHYSFS_smallFree(wbuf);
+    return(retval);
+} /* __PHYSFS_platformCurrentDir */
+
+
+/* this could probably use a cleanup. */
+char *__PHYSFS_platformRealPath(const char *path)
+{
+    /* !!! FIXME: try GetFullPathName() instead? */
+    /* this function should be UTF-8 clean. */
+    char *retval = NULL;
+    char *p = NULL;
+
+    BAIL_IF_MACRO(path == NULL, ERR_INVALID_ARGUMENT, NULL);
+    BAIL_IF_MACRO(*path == '\0', ERR_INVALID_ARGUMENT, NULL);
+
+    retval = (char *) allocator.Malloc(MAX_PATH);
+    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
+
+        /*
+         * If in \\server\path format, it's already an absolute path.
+         *  We'll need to check for "." and ".." dirs, though, just in case.
+         */
+    if ((path[0] == '\\') && (path[1] == '\\'))
+        strcpy(retval, path);
+
+    else
+    {
+        char *currentDir = __PHYSFS_platformCurrentDir();
+        if (currentDir == NULL)
+        {
+            allocator.Free(retval);
+            BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
+        } /* if */
+
+        if (path[1] == ':')   /* drive letter specified? */
+        {
+            /*
+             * Apparently, "D:mypath" is the same as "D:\\mypath" if
+             *  D: is not the current drive. However, if D: is the
+             *  current drive, then "D:mypath" is a relative path. Ugh.
+             */
+            if (path[2] == '\\')  /* maybe an absolute path? */
+                strcpy(retval, path);
+            else  /* definitely an absolute path. */
+            {
+                if (path[0] == currentDir[0]) /* current drive; relative. */
+                {
+                    strcpy(retval, currentDir);
+                    strcat(retval, path + 2);
+                } /* if */
+
+                else  /* not current drive; absolute. */
+                {
+                    retval[0] = path[0];
+                    retval[1] = ':';
+                    retval[2] = '\\';
+                    strcpy(retval + 3, path + 2);
+                } /* else */
+            } /* else */
+        } /* if */
+
+        else  /* no drive letter specified. */
+        {
+            if (path[0] == '\\')  /* absolute path. */
+            {
+                retval[0] = currentDir[0];
+                retval[1] = ':';
+                strcpy(retval + 2, path);
+            } /* if */
+            else
+            {
+                strcpy(retval, currentDir);
+                strcat(retval, path);
+            } /* else */
+        } /* else */
+
+        allocator.Free(currentDir);
+    } /* else */
+
+    /* (whew.) Ok, now take out "." and ".." path entries... */
+
+    p = retval;
+    while ( (p = strstr(p, "\\.")) != NULL)
+    {
+        /* it's a "." entry that doesn't end the string. */
+        if (p[2] == '\\')
+            memmove(p + 1, p + 3, strlen(p + 3) + 1);
+
+        /* it's a "." entry that ends the string. */
+        else if (p[2] == '\0')
+            p[0] = '\0';
+
+        /* it's a ".." entry. */
+        else if (p[2] == '.')
+        {
+            char *prevEntry = p - 1;
+            while ((prevEntry != retval) && (*prevEntry != '\\'))
+                prevEntry--;
+
+            if (prevEntry == retval)  /* make it look like a "." entry. */
+                memmove(p + 1, p + 2, strlen(p + 2) + 1);
+            else
+            {
+                if (p[3] != '\0') /* doesn't end string. */
+                    *prevEntry = '\0';
+                else /* ends string. */
+                    memmove(prevEntry + 1, p + 4, strlen(p + 4) + 1);
+
+                p = prevEntry;
+            } /* else */
+        } /* else if */
+
+        else
+        {
+            p++;  /* look past current char. */
+        } /* else */
+    } /* while */
+
+    /* shrink the retval's memory block if possible... */
+    p = (char *) allocator.Realloc(retval, strlen(retval) + 1);
+    if (p != NULL)
+        retval = p;
+
+    return(retval);
+} /* __PHYSFS_platformRealPath */
+
+
+int __PHYSFS_platformMkDir(const char *path)
+{
+    WCHAR *wpath;
+    DWORD rc;
+    UTF8_TO_UNICODE_STACK_MACRO(wpath, path);
+    rc = pCreateDirectoryW(wpath, NULL);
+    __PHYSFS_smallFree(wpath);
+    BAIL_IF_MACRO(rc == 0, winApiStrError(), 0);
+    return(1);
+} /* __PHYSFS_platformMkDir */
+
+
+ /*
+  * Get OS info and save the important parts.
+  *
+  * Returns non-zero if successful, otherwise it returns zero on failure.
+  */
+ static int getOSInfo(void)
+ {
+     OSVERSIONINFO osVerInfo;     /* Information about the OS */
+     osVerInfo.dwOSVersionInfoSize = sizeof(osVerInfo);
+     BAIL_IF_MACRO(!GetVersionEx(&osVerInfo), winApiStrError(), 0);
+     osHasUnicode = (osVerInfo.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS);
+     return(1);
+ } /* getOSInfo */
+
+
+int __PHYSFS_platformInit(void)
+{
+    BAIL_IF_MACRO(!getOSInfo(), NULL, 0);
+    BAIL_IF_MACRO(!findApiSymbols(), NULL, 0);
+    BAIL_IF_MACRO(!determineUserDir(), NULL, 0);
+    return(1);  /* It's all good */
+} /* __PHYSFS_platformInit */
+
+
+int __PHYSFS_platformDeinit(void)
+{
+    HANDLE *libs[] = { &libKernel32, &libUserEnv, &libAdvApi32, NULL };
+    int i;
+
+    allocator.Free(userDir);
+    userDir = NULL;
+
+    for (i = 0; libs[i] != NULL; i++)
+    {
+        const HANDLE lib = *(libs[i]);
+        if (lib)
+            FreeLibrary(lib);
+        *(libs[i]) = NULL;
+    } /* for */
+
+    return(1); /* It's all good */
+} /* __PHYSFS_platformDeinit */
+
+
+static void *doOpen(const char *fname, DWORD mode, DWORD creation, int rdonly)
+{
+    HANDLE fileHandle;
+    WinApiFile *retval;
+    WCHAR *wfname;
+
+    UTF8_TO_UNICODE_STACK_MACRO(wfname, fname);
+    BAIL_IF_MACRO(wfname == NULL, ERR_OUT_OF_MEMORY, NULL);
+    fileHandle = pCreateFileW(wfname, mode, FILE_SHARE_READ, NULL,
+                              creation, FILE_ATTRIBUTE_NORMAL, NULL);
+    __PHYSFS_smallFree(wfname);
+
+    BAIL_IF_MACRO
+    (
+        fileHandle == INVALID_HANDLE_VALUE,
+        winApiStrError(), NULL
+    );
+
+    retval = (WinApiFile *) allocator.Malloc(sizeof (WinApiFile));
+    if (retval == NULL)
+    {
+        CloseHandle(fileHandle);
+        BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
+    } /* if */
+
+    retval->readonly = rdonly;
+    retval->handle = fileHandle;
+    return(retval);
+} /* doOpen */
+
+
+void *__PHYSFS_platformOpenRead(const char *filename)
+{
+    return(doOpen(filename, GENERIC_READ, OPEN_EXISTING, 1));
+} /* __PHYSFS_platformOpenRead */
+
+
+void *__PHYSFS_platformOpenWrite(const char *filename)
+{
+    return(doOpen(filename, GENERIC_WRITE, CREATE_ALWAYS, 0));
+} /* __PHYSFS_platformOpenWrite */
+
+
+void *__PHYSFS_platformOpenAppend(const char *filename)
+{
+    void *retval = doOpen(filename, GENERIC_WRITE, OPEN_ALWAYS, 0);
+    if (retval != NULL)
+    {
+        HANDLE h = ((WinApiFile *) retval)->handle;
+        DWORD rc = SetFilePointer(h, 0, NULL, FILE_END);
+        if (rc == PHYSFS_INVALID_SET_FILE_POINTER)
+        {
+            const char *err = winApiStrError();
+            CloseHandle(h);
+            allocator.Free(retval);
+            BAIL_MACRO(err, NULL);
+        } /* if */
+    } /* if */
+
+    return(retval);
+} /* __PHYSFS_platformOpenAppend */
+
+
+PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
+                                    PHYSFS_uint32 size, PHYSFS_uint32 count)
+{
+    HANDLE Handle = ((WinApiFile *) opaque)->handle;
+    DWORD CountOfBytesRead;
+    PHYSFS_sint64 retval;
+
+    /* Read data from the file */
+    /* !!! FIXME: uint32 might be a greater # than DWORD */
+    if(!ReadFile(Handle, buffer, count * size, &CountOfBytesRead, NULL))
+    {
+        BAIL_MACRO(winApiStrError(), -1);
+    } /* if */
+    else
+    {
+        /* Return the number of "objects" read. */
+        /* !!! FIXME: What if not the right amount of bytes was read to make an object? */
+        retval = CountOfBytesRead / size;
+    } /* else */
+
+    return(retval);
+} /* __PHYSFS_platformRead */
+
+
+PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
+                                     PHYSFS_uint32 size, PHYSFS_uint32 count)
+{
+    HANDLE Handle = ((WinApiFile *) opaque)->handle;
+    DWORD CountOfBytesWritten;
+    PHYSFS_sint64 retval;
+
+    /* Read data from the file */
+    /* !!! FIXME: uint32 might be a greater # than DWORD */
+    if(!WriteFile(Handle, buffer, count * size, &CountOfBytesWritten, NULL))
+    {
+        BAIL_MACRO(winApiStrError(), -1);
+    } /* if */
+    else
+    {
+        /* Return the number of "objects" read. */
+        /* !!! FIXME: What if not the right number of bytes was written? */
+        retval = CountOfBytesWritten / size;
+    } /* else */
+
+    return(retval);
+} /* __PHYSFS_platformWrite */
+
+
+int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos)
+{
+    HANDLE Handle = ((WinApiFile *) opaque)->handle;
+    DWORD HighOrderPos;
+    DWORD *pHighOrderPos;
+    DWORD rc;
+
+    /* Get the high order 32-bits of the position */
+    HighOrderPos = HIGHORDER_UINT64(pos);
+
+    /*
+     * MSDN: "If you do not need the high-order 32 bits, this
+     *         pointer must be set to NULL."
+     */
+    pHighOrderPos = (HighOrderPos) ? &HighOrderPos : NULL;
+
+    /*
+     * !!! FIXME: MSDN: "Windows Me/98/95:  If the pointer
+     * !!! FIXME:  lpDistanceToMoveHigh is not NULL, then it must
+     * !!! FIXME:  point to either 0, INVALID_SET_FILE_POINTER, or
+     * !!! FIXME:  the sign extension of the value of lDistanceToMove.
+     * !!! FIXME:  Any other value will be rejected."
+     */
+
+    /* Move pointer "pos" count from start of file */
+    rc = SetFilePointer(Handle, LOWORDER_UINT64(pos),
+                        pHighOrderPos, FILE_BEGIN);
+
+    if ( (rc == PHYSFS_INVALID_SET_FILE_POINTER) &&
+         (GetLastError() != NO_ERROR) )
+    {
+        BAIL_MACRO(winApiStrError(), 0);
+    } /* if */
+    
+    return(1);  /* No error occured */
+} /* __PHYSFS_platformSeek */
+
+
+PHYSFS_sint64 __PHYSFS_platformTell(void *opaque)
+{
+    HANDLE Handle = ((WinApiFile *) opaque)->handle;
+    DWORD HighPos = 0;
+    DWORD LowPos;
+    PHYSFS_sint64 retval;
+
+    /* Get current position */
+    LowPos = SetFilePointer(Handle, 0, &HighPos, FILE_CURRENT);
+    if ( (LowPos == PHYSFS_INVALID_SET_FILE_POINTER) &&
+         (GetLastError() != NO_ERROR) )
+    {
+        BAIL_MACRO(winApiStrError(), 0);
+    } /* if */
+    else
+    {
+        /* Combine the high/low order to create the 64-bit position value */
+        retval = (((PHYSFS_uint64) HighPos) << 32) | LowPos;
+        assert(retval >= 0);
+    } /* else */
+
+    return(retval);
+} /* __PHYSFS_platformTell */
+
+
+PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
+{
+    HANDLE Handle = ((WinApiFile *) opaque)->handle;
+    DWORD SizeHigh;
+    DWORD SizeLow;
+    PHYSFS_sint64 retval;
+
+    SizeLow = GetFileSize(Handle, &SizeHigh);
+    if ( (SizeLow == PHYSFS_INVALID_SET_FILE_POINTER) &&
+         (GetLastError() != NO_ERROR) )
+    {
+        BAIL_MACRO(winApiStrError(), -1);
+    } /* if */
+    else
+    {
+        /* Combine the high/low order to create the 64-bit position value */
+        retval = (((PHYSFS_uint64) SizeHigh) << 32) | SizeLow;
+        assert(retval >= 0);
+    } /* else */
+
+    return(retval);
+} /* __PHYSFS_platformFileLength */
+
+
+int __PHYSFS_platformEOF(void *opaque)
+{
+    PHYSFS_sint64 FilePosition;
+    int retval = 0;
+
+    /* Get the current position in the file */
+    if ((FilePosition = __PHYSFS_platformTell(opaque)) != 0)
+    {
+        /* Non-zero if EOF is equal to the file length */
+        retval = FilePosition == __PHYSFS_platformFileLength(opaque);
+    } /* if */
+
+    return(retval);
+} /* __PHYSFS_platformEOF */
+
+
+int __PHYSFS_platformFlush(void *opaque)
+{
+    WinApiFile *fh = ((WinApiFile *) opaque);
+    if (!fh->readonly)
+        BAIL_IF_MACRO(!FlushFileBuffers(fh->handle), winApiStrError(), 0);
+
+    return(1);
+} /* __PHYSFS_platformFlush */
+
+
+int __PHYSFS_platformClose(void *opaque)
+{
+    HANDLE Handle = ((WinApiFile *) opaque)->handle;
+    BAIL_IF_MACRO(!CloseHandle(Handle), winApiStrError(), 0);
+    allocator.Free(opaque);
+    return(1);
+} /* __PHYSFS_platformClose */
+
+
+static int doPlatformDelete(LPWSTR wpath)
+{
+    /* If filename is a folder */
+    if (pGetFileAttributesW(wpath) == FILE_ATTRIBUTE_DIRECTORY)
+    {
+        BAIL_IF_MACRO(!pRemoveDirectoryW(wpath), winApiStrError(), 0);
+    } /* if */
+    else
+    {
+        BAIL_IF_MACRO(!pDeleteFileW(wpath), winApiStrError(), 0);
+    } /* else */
+
+    return(1);   /* if you made it here, it worked. */
+} /* doPlatformDelete */
+
+
+int __PHYSFS_platformDelete(const char *path)
+{
+    int retval = 0;
+    LPWSTR wpath;
+    UTF8_TO_UNICODE_STACK_MACRO(wpath, path);
+    BAIL_IF_MACRO(wpath == NULL, ERR_OUT_OF_MEMORY, 0);
+    retval = doPlatformDelete(wpath);
+    __PHYSFS_smallFree(wpath);
+    return(retval);
+} /* __PHYSFS_platformDelete */
+
+
+/*
+ * !!! FIXME: why aren't we using Critical Sections instead of Mutexes?
+ * !!! FIXME:  mutexes on Windows are for cross-process sync. CritSects are
+ * !!! FIXME:  mutexes for threads in a single process and are faster.
+ */
+void *__PHYSFS_platformCreateMutex(void)
+{
+    return((void *) CreateMutex(NULL, FALSE, NULL));
+} /* __PHYSFS_platformCreateMutex */
+
+
+void __PHYSFS_platformDestroyMutex(void *mutex)
+{
+    CloseHandle((HANDLE) mutex);
+} /* __PHYSFS_platformDestroyMutex */
+
+
+int __PHYSFS_platformGrabMutex(void *mutex)
+{
+    return(WaitForSingleObject((HANDLE) mutex, INFINITE) != WAIT_FAILED);
+} /* __PHYSFS_platformGrabMutex */
+
+
+void __PHYSFS_platformReleaseMutex(void *mutex)
+{
+    ReleaseMutex((HANDLE) mutex);
+} /* __PHYSFS_platformReleaseMutex */
+
+
+static PHYSFS_sint64 FileTimeToPhysfsTime(const FILETIME *ft)
+{
+    SYSTEMTIME st_utc;
+    SYSTEMTIME st_localtz;
+    TIME_ZONE_INFORMATION tzi;
+    DWORD tzid;
+    PHYSFS_sint64 retval;
+    struct tm tm;
+
+    BAIL_IF_MACRO(!FileTimeToSystemTime(ft, &st_utc), winApiStrError(), -1);
+    tzid = GetTimeZoneInformation(&tzi);
+    BAIL_IF_MACRO(tzid == TIME_ZONE_ID_INVALID, winApiStrError(), -1);
+
+    /* (This API is unsupported and fails on non-NT systems. */
+    if (!SystemTimeToTzSpecificLocalTime(&tzi, &st_utc, &st_localtz))
+    {
+        /* do it by hand. Grumble... */
+        ULARGE_INTEGER ui64;
+        FILETIME new_ft;
+        ui64.LowPart = ft->dwLowDateTime;
+        ui64.HighPart = ft->dwHighDateTime;
+
+        if (tzid == TIME_ZONE_ID_STANDARD)
+            tzi.Bias += tzi.StandardBias;
+        else if (tzid == TIME_ZONE_ID_DAYLIGHT)
+            tzi.Bias += tzi.DaylightBias;
+
+        /* convert from minutes to 100-nanosecond increments... */
+        ui64.QuadPart -= (((LONGLONG) tzi.Bias) * (600000000));
+
+        /* Move it back into a FILETIME structure... */
+        new_ft.dwLowDateTime = ui64.LowPart;
+        new_ft.dwHighDateTime = ui64.HighPart;
+
+        /* Convert to something human-readable... */
+        if (!FileTimeToSystemTime(&new_ft, &st_localtz))
+            BAIL_MACRO(winApiStrError(), -1);
+    } /* if */
+
+    /* Convert to a format that mktime() can grok... */
+    tm.tm_sec = st_localtz.wSecond;
+    tm.tm_min = st_localtz.wMinute;
+    tm.tm_hour = st_localtz.wHour;
+    tm.tm_mday = st_localtz.wDay;
+    tm.tm_mon = st_localtz.wMonth - 1;
+    tm.tm_year = st_localtz.wYear - 1900;
+    tm.tm_wday = -1 /*st_localtz.wDayOfWeek*/;
+    tm.tm_yday = -1;
+    tm.tm_isdst = -1;
+
+    /* Convert to a format PhysicsFS can grok... */
+    retval = (PHYSFS_sint64) mktime(&tm);
+    BAIL_IF_MACRO(retval == -1, strerror(errno), -1);
+    return(retval);
+} /* FileTimeToPhysfsTime */
+
+
+PHYSFS_sint64 __PHYSFS_platformGetLastModTime(const char *fname)
+{
+    PHYSFS_sint64 retval = -1;
+    WIN32_FILE_ATTRIBUTE_DATA attr;
+    int rc = 0;
+
+    memset(&attr, '\0', sizeof (attr));
+
+    /* GetFileAttributesEx didn't show up until Win98 and NT4. */
+    if ((pGetFileAttributesExW != NULL) || (pGetFileAttributesExA != NULL))
+    {
+        WCHAR *wstr;
+        UTF8_TO_UNICODE_STACK_MACRO(wstr, fname);
+        if (wstr != NULL) /* if NULL, maybe the fallback will work. */
+        {
+            if (pGetFileAttributesExW != NULL)  /* NT/XP/Vista/etc system. */
+                rc = pGetFileAttributesExW(wstr, GetFileExInfoStandard, &attr);
+            else  /* Win98/ME system */
+            {
+                const int len = (int) (wStrLen(wstr) + 1);
+                char *cp = (char *) __PHYSFS_smallAlloc(len);
+                if (cp != NULL)
+                {
+                    WideCharToMultiByte(CP_ACP, 0, wstr, len, cp, len, 0, 0);
+                    rc = pGetFileAttributesExA(cp, GetFileExInfoStandard, &attr);
+                    __PHYSFS_smallFree(cp);
+                } /* if */
+            } /* else */
+            __PHYSFS_smallFree(wstr);
+        } /* if */
+    } /* if */
+
+    if (rc)  /* had API entry point and it worked. */
+    {
+        /* 0 return value indicates an error or not supported */
+        if ( (attr.ftLastWriteTime.dwHighDateTime != 0) ||
+             (attr.ftLastWriteTime.dwLowDateTime != 0) )
+        {
+            retval = FileTimeToPhysfsTime(&attr.ftLastWriteTime);
+        } /* if */
+    } /* if */
+
+    /* GetFileTime() has been in the Win32 API since the start. */
+    if (retval == -1)  /* try a fallback... */
+    {
+        FILETIME ft;
+        BOOL rc;
+        const char *err;
+        WinApiFile *f = (WinApiFile *) __PHYSFS_platformOpenRead(fname);
+        BAIL_IF_MACRO(f == NULL, NULL, -1)
+        rc = GetFileTime(f->handle, NULL, NULL, &ft);
+        err = winApiStrError();
+        CloseHandle(f->handle);
+        allocator.Free(f);
+        BAIL_IF_MACRO(!rc, err, -1);
+        retval = FileTimeToPhysfsTime(&ft);
+    } /* if */
+
+    return(retval);
+} /* __PHYSFS_platformGetLastModTime */
+
+
+/* !!! FIXME: Don't use C runtime for allocators? */
+int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
+{
+    return(0);  /* just use malloc() and friends. */
+} /* __PHYSFS_platformSetDefaultAllocator */
+
+#endif  /* PHYSFS_PLATFORM_WINDOWS */
+
+/* end of windows.c ... */
+
+
diff --git a/src/unison/physfs-1.1.1/test/test_physfs.c b/src/unison/physfs-1.1.1/test/test_physfs.c
new file mode 100644 (file)
index 0000000..33c3f74
--- /dev/null
@@ -0,0 +1,1222 @@
+/**
+ * Test program for PhysicsFS. May only work on Unix.
+ *
+ * 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 <errno.h>
+#include <string.h>
+
+#if (defined __MWERKS__)
+#include <SIOUX.h>
+#endif
+
+#if (defined PHYSFS_HAVE_READLINE)
+#include <unistd.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+#endif
+
+#include <time.h>
+
+#include "physfs.h"
+
+#define TEST_VERSION_MAJOR  1
+#define TEST_VERSION_MINOR  1
+#define TEST_VERSION_PATCH  1
+
+static FILE *history_file = NULL;
+static PHYSFS_uint32 do_buffer_size = 0;
+
+static void output_versions(void)
+{
+    PHYSFS_Version compiled;
+    PHYSFS_Version linked;
+
+    PHYSFS_VERSION(&compiled);
+    PHYSFS_getLinkedVersion(&linked);
+
+    printf("test_physfs version %d.%d.%d.\n"
+           " Compiled against PhysicsFS version %d.%d.%d,\n"
+           " and linked against %d.%d.%d.\n\n",
+            TEST_VERSION_MAJOR, TEST_VERSION_MINOR, TEST_VERSION_PATCH,
+            (int) compiled.major, (int) compiled.minor, (int) compiled.patch,
+            (int) linked.major, (int) linked.minor, (int) linked.patch);
+} /* output_versions */
+
+
+static void output_archivers(void)
+{
+    const PHYSFS_ArchiveInfo **rc = PHYSFS_supportedArchiveTypes();
+    const PHYSFS_ArchiveInfo **i;
+
+    printf("Supported archive types:\n");
+    if (*rc == NULL)
+        printf(" * Apparently, NONE!\n");
+    else
+    {
+        for (i = rc; *i != NULL; i++)
+        {
+            printf(" * %s: %s\n    Written by %s.\n    %s\n",
+                    (*i)->extension, (*i)->description,
+                    (*i)->author, (*i)->url);
+        } /* for */
+    } /* else */
+
+    printf("\n");
+} /* output_archivers */
+
+
+static int cmd_quit(char *args)
+{
+    return(0);
+} /* cmd_quit */
+
+
+static int cmd_init(char *args)
+{
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    if (PHYSFS_init(args))
+        printf("Successful.\n");
+    else
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+
+    return(1);
+} /* cmd_init */
+
+
+static int cmd_deinit(char *args)
+{
+    if (PHYSFS_deinit())
+        printf("Successful.\n");
+    else
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+
+    return(1);
+} /* cmd_deinit */
+
+
+static int cmd_addarchive(char *args)
+{
+    char *ptr = strrchr(args, ' ');
+    int appending = atoi(ptr + 1);
+    *ptr = '\0';
+
+    if (*args == '\"')
+    {
+        args++;
+        *(ptr - 1) = '\0';
+    } /* if */
+
+    /*printf("[%s], [%d]\n", args, appending);*/
+
+    if (PHYSFS_addToSearchPath(args, appending))
+        printf("Successful.\n");
+    else
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+
+    return(1);
+} /* cmd_addarchive */
+
+
+static int cmd_mount(char *args)
+{
+    char *ptr;
+    char *mntpoint = NULL;
+    int appending = 0;
+
+    if (*args == '\"')
+    {
+        args++;
+        ptr = strchr(args, '\"');
+        if (ptr == NULL)
+        {
+            printf("missing string terminator in argument.\n");
+            return(1);
+        } /* if */
+        *(ptr) = '\0';
+    } /* if */
+    else
+    {
+        ptr = strchr(args, ' ');
+        *ptr = '\0';
+    } /* else */
+
+    mntpoint = ptr + 1;
+    if (*mntpoint == '\"')
+    {
+        mntpoint++;
+        ptr = strchr(mntpoint, '\"');
+        if (ptr == NULL)
+        {
+            printf("missing string terminator in argument.\n");
+            return(1);
+        } /* if */
+        *(ptr) = '\0';
+    } /* if */
+    else
+    {
+        ptr = strchr(mntpoint, ' ');
+        *(ptr) = '\0';
+    } /* else */
+    appending = atoi(ptr + 1);
+
+    /*printf("[%s], [%s], [%d]\n", args, mntpoint, appending);*/
+
+    if (PHYSFS_mount(args, mntpoint, appending))
+        printf("Successful.\n");
+    else
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+
+    return(1);
+} /* cmd_mount */
+
+
+static int cmd_removearchive(char *args)
+{
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    if (PHYSFS_removeFromSearchPath(args))
+        printf("Successful.\n");
+    else
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+
+    return(1);
+} /* cmd_removearchive */
+
+
+static int cmd_enumerate(char *args)
+{
+    char **rc;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    rc = PHYSFS_enumerateFiles(args);
+
+    if (rc == NULL)
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+    else
+    {
+        int file_count;
+        char **i;
+        for (i = rc, file_count = 0; *i != NULL; i++, file_count++)
+            printf("%s\n", *i);
+
+        printf("\n total (%d) files.\n", file_count);
+        PHYSFS_freeList(rc);
+    } /* else */
+
+    return(1);
+} /* cmd_enumerate */
+
+
+static int cmd_getdirsep(char *args)
+{
+    printf("Directory separator is [%s].\n", PHYSFS_getDirSeparator());
+    return(1);
+} /* cmd_getdirsep */
+
+
+static int cmd_getlasterror(char *args)
+{
+    printf("last error is [%s].\n", PHYSFS_getLastError());
+    return(1);
+} /* cmd_getlasterror */
+
+
+static int cmd_getcdromdirs(char *args)
+{
+    char **rc = PHYSFS_getCdRomDirs();
+
+    if (rc == NULL)
+        printf("Failure. Reason: [%s].\n", PHYSFS_getLastError());
+    else
+    {
+        int dir_count;
+        char **i;
+        for (i = rc, dir_count = 0; *i != NULL; i++, dir_count++)
+            printf("%s\n", *i);
+
+        printf("\n total (%d) drives.\n", dir_count);
+        PHYSFS_freeList(rc);
+    } /* else */
+
+    return(1);
+} /* cmd_getcdromdirs */
+
+
+static int cmd_getsearchpath(char *args)
+{
+    char **rc = PHYSFS_getSearchPath();
+
+    if (rc == NULL)
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+    else
+    {
+        int dir_count;
+        char **i;
+        for (i = rc, dir_count = 0; *i != NULL; i++, dir_count++)
+            printf("%s\n", *i);
+
+        printf("\n total (%d) directories.\n", dir_count);
+        PHYSFS_freeList(rc);
+    } /* else */
+
+    return(1);
+} /* cmd_getcdromdirs */
+
+
+static int cmd_getbasedir(char *args)
+{
+    printf("Base dir is [%s].\n", PHYSFS_getBaseDir());
+    return(1);
+} /* cmd_getbasedir */
+
+
+static int cmd_getuserdir(char *args)
+{
+    printf("User dir is [%s].\n", PHYSFS_getUserDir());
+    return(1);
+} /* cmd_getuserdir */
+
+
+static int cmd_getwritedir(char *args)
+{
+    printf("Write dir is [%s].\n", PHYSFS_getWriteDir());
+    return(1);
+} /* cmd_getwritedir */
+
+
+static int cmd_setwritedir(char *args)
+{
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    if (PHYSFS_setWriteDir(args))
+        printf("Successful.\n");
+    else
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+
+    return(1);
+} /* cmd_setwritedir */
+
+
+static int cmd_permitsyms(char *args)
+{
+    int num;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    num = atoi(args);
+    PHYSFS_permitSymbolicLinks(num);
+    printf("Symlinks are now %s.\n", num ? "permitted" : "forbidden");
+    return(1);
+} /* cmd_permitsyms */
+
+
+static int cmd_setbuffer(char *args)
+{
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    do_buffer_size = (unsigned int) atoi(args);
+    if (do_buffer_size)
+    {
+        printf("Further tests will set a (%lu) size buffer.\n",
+                (unsigned long) do_buffer_size);
+    } /* if */
+
+    else
+    {
+        printf("Further tests will NOT use a buffer.\n");
+    } /* else */
+
+    return(1);
+} /* cmd_setbuffer */
+
+
+static int cmd_stressbuffer(char *args)
+{
+    int num;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    num = atoi(args);
+    if (num < 0)
+        printf("buffer must be greater than or equal to zero.\n");
+    else
+    {
+        PHYSFS_File *f;
+        int rndnum;
+
+        printf("Stress testing with (%d) byte buffer...\n", num);
+        f = PHYSFS_openWrite("test.txt");
+        if (f == NULL)
+            printf("Couldn't open test.txt for writing: %s.\n", PHYSFS_getLastError());
+        else
+        {
+            int i, j;
+            char buf[37];
+            char buf2[37];
+
+            if (!PHYSFS_setBuffer(f, num))
+            {
+                printf("PHYSFS_setBuffer() failed: %s.\n", PHYSFS_getLastError());
+                PHYSFS_close(f);
+                PHYSFS_delete("test.txt");
+                return(1);
+            } /* if */
+
+            strcpy(buf, "abcdefghijklmnopqrstuvwxyz0123456789");
+            srand((unsigned int) time(NULL));
+
+            for (i = 0; i < 10; i++)
+            {
+                for (j = 0; j < 10000; j++)
+                {
+                    PHYSFS_uint32 right = 1 + (PHYSFS_uint32) (35.0 * rand() / (RAND_MAX + 1.0));
+                    PHYSFS_uint32 left = 36 - right;
+                    if (PHYSFS_write(f, buf, left, 1) != 1)
+                    {
+                        printf("PHYSFS_write() failed: %s.\n", PHYSFS_getLastError());
+                        PHYSFS_close(f);
+                        return(1);
+                    } /* if */
+
+                    rndnum = 1 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
+                    if (rndnum == 42)
+                    {
+                        if (!PHYSFS_flush(f))
+                        {
+                            printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
+                            PHYSFS_close(f);
+                            return(1);
+                        } /* if */
+                    } /* if */
+
+                    if (PHYSFS_write(f, buf + left, 1, right) != right)
+                    {
+                        printf("PHYSFS_write() failed: %s.\n", PHYSFS_getLastError());
+                        PHYSFS_close(f);
+                        return(1);
+                    } /* if */
+
+                    rndnum = 1 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
+                    if (rndnum == 42)
+                    {
+                        if (!PHYSFS_flush(f))
+                        {
+                            printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
+                            PHYSFS_close(f);
+                            return(1);
+                        } /* if */
+                    } /* if */
+                } /* for */
+
+                if (!PHYSFS_flush(f))
+                {
+                    printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
+                    PHYSFS_close(f);
+                    return(1);
+                } /* if */
+
+            } /* for */
+
+            if (!PHYSFS_close(f))
+            {
+                printf("PHYSFS_close() failed: %s.\n", PHYSFS_getLastError());
+                return(1);  /* oh well. */
+            } /* if */
+
+            printf(" ... test file written ...\n");
+            f = PHYSFS_openRead("test.txt");
+            if (f == NULL)
+            {
+                printf("Failed to reopen stress file for reading: %s.\n", PHYSFS_getLastError());
+                return(1);
+            } /* if */
+
+            if (!PHYSFS_setBuffer(f, num))
+            {
+                printf("PHYSFS_setBuffer() failed: %s.\n", PHYSFS_getLastError());
+                PHYSFS_close(f);
+                return(1);
+            } /* if */
+
+            for (i = 0; i < 10; i++)
+            {
+                for (j = 0; j < 10000; j++)
+                {
+                    PHYSFS_uint32 right = 1 + (PHYSFS_uint32) (35.0 * rand() / (RAND_MAX + 1.0));
+                    PHYSFS_uint32 left = 36 - right;
+                    if (PHYSFS_read(f, buf2, left, 1) != 1)
+                    {
+                        printf("PHYSFS_read() failed: %s.\n", PHYSFS_getLastError());
+                        PHYSFS_close(f);
+                        return(1);
+                    } /* if */
+
+                    rndnum = 1 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
+                    if (rndnum == 42)
+                    {
+                        if (!PHYSFS_flush(f))
+                        {
+                            printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
+                            PHYSFS_close(f);
+                            return(1);
+                        } /* if */
+                    } /* if */
+
+                    if (PHYSFS_read(f, buf2 + left, 1, right) != right)
+                    {
+                        printf("PHYSFS_read() failed: %s.\n", PHYSFS_getLastError());
+                        PHYSFS_close(f);
+                        return(1);
+                    } /* if */
+
+                    rndnum = 1 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
+                    if (rndnum == 42)
+                    {
+                        if (!PHYSFS_flush(f))
+                        {
+                            printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
+                            PHYSFS_close(f);
+                            return(1);
+                        } /* if */
+                    } /* if */
+
+                    if (memcmp(buf, buf2, 36) != 0)
+                    {
+                        printf("readback is mismatched on iterations (%d, %d).\n", i, j);
+                        printf("wanted: [");
+                        for (i = 0; i < 36; i++)
+                            printf("%c", buf[i]);
+                        printf("]\n");
+
+                        printf("   got: [");
+                        for (i = 0; i < 36; i++)
+                            printf("%c", buf2[i]);
+                        printf("]\n");
+                        PHYSFS_close(f);
+                        return(1);
+                    } /* if */
+                } /* for */
+
+                if (!PHYSFS_flush(f))
+                {
+                    printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
+                    PHYSFS_close(f);
+                    return(1);
+                } /* if */
+
+            } /* for */
+
+            printf(" ... test file read ...\n");
+
+            if (!PHYSFS_eof(f))
+                printf("PHYSFS_eof() returned true! That's wrong.\n");
+
+            if (!PHYSFS_close(f))
+            {
+                printf("PHYSFS_close() failed: %s.\n", PHYSFS_getLastError());
+                return(1);  /* oh well. */
+            } /* if */
+
+            PHYSFS_delete("test.txt");
+            printf("stress test completed successfully.\n");
+        } /* else */
+    } /* else */
+
+    return(1);
+} /* cmd_stressbuffer */
+
+
+static int cmd_setsaneconfig(char *args)
+{
+    char *org;
+    char *appName;
+    char *arcExt;
+    int inclCD;
+    int arcsFirst;
+    char *ptr = args;
+
+        /* ugly. */
+    org = ptr;
+    ptr = strchr(ptr, ' '); *ptr = '\0'; ptr++; appName = ptr;
+    ptr = strchr(ptr, ' '); *ptr = '\0'; ptr++; arcExt = ptr;
+    ptr = strchr(ptr, ' '); *ptr = '\0'; ptr++; inclCD = atoi(arcExt);
+    arcsFirst = atoi(ptr);
+
+    if (strcmp(arcExt, "!") == 0)
+        arcExt = NULL;
+
+    if (PHYSFS_setSaneConfig(org, appName, arcExt, inclCD, arcsFirst))
+        printf("Successful.\n");
+    else
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+
+    return(1);
+} /* cmd_setsaneconfig */
+
+
+static int cmd_mkdir(char *args)
+{
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    if (PHYSFS_mkdir(args))
+        printf("Successful.\n");
+    else
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+
+    return(1);
+} /* cmd_mkdir */
+
+
+static int cmd_delete(char *args)
+{
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    if (PHYSFS_delete(args))
+        printf("Successful.\n");
+    else
+        printf("Failure. reason: %s.\n", PHYSFS_getLastError());
+
+    return(1);
+} /* cmd_delete */
+
+
+static int cmd_getrealdir(char *args)
+{
+    const char *rc;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    rc = PHYSFS_getRealDir(args);
+    if (rc)
+        printf("Found at [%s].\n", rc);
+    else
+        printf("Not found.\n");
+
+    return(1);
+} /* cmd_getrealdir */
+
+
+static int cmd_exists(char *args)
+{
+    int rc;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    rc = PHYSFS_exists(args);
+    printf("File %sexists.\n", rc ? "" : "does not ");
+    return(1);
+} /* cmd_exists */
+
+
+static int cmd_isdir(char *args)
+{
+    int rc;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    rc = PHYSFS_isDirectory(args);
+    printf("File %s a directory.\n", rc ? "is" : "is NOT");
+    return(1);
+} /* cmd_isdir */
+
+
+static int cmd_issymlink(char *args)
+{
+    int rc;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    rc = PHYSFS_isSymbolicLink(args);
+    printf("File %s a symlink.\n", rc ? "is" : "is NOT");
+    return(1);
+} /* cmd_issymlink */
+
+
+static int cmd_cat(char *args)
+{
+    PHYSFS_File *f;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    f = PHYSFS_openRead(args);
+    if (f == NULL)
+        printf("failed to open. Reason: [%s].\n", PHYSFS_getLastError());
+    else
+    {
+        if (do_buffer_size)
+        {
+            if (!PHYSFS_setBuffer(f, do_buffer_size))
+            {
+                printf("failed to set file buffer. Reason: [%s].\n",
+                        PHYSFS_getLastError());
+                PHYSFS_close(f);
+                return(1);
+            } /* if */
+        } /* if */
+
+        while (1)
+        {
+            char buffer[128];
+            PHYSFS_sint64 rc;
+            PHYSFS_sint64 i;
+            rc = PHYSFS_read(f, buffer, 1, sizeof (buffer));
+
+            for (i = 0; i < rc; i++)
+                fputc((int) buffer[i], stdout);
+
+            if (rc < sizeof (buffer))
+            {
+                printf("\n\n");
+                if (!PHYSFS_eof(f))
+                {
+                    printf("\n (Error condition in reading. Reason: [%s])\n\n",
+                           PHYSFS_getLastError());
+                } /* if */
+                PHYSFS_close(f);
+                return(1);
+            } /* if */
+        } /* while */
+    } /* else */
+
+    return(1);
+} /* cmd_cat */
+
+
+static int cmd_filelength(char *args)
+{
+    PHYSFS_File *f;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    f = PHYSFS_openRead(args);
+    if (f == NULL)
+        printf("failed to open. Reason: [%s].\n", PHYSFS_getLastError());
+    else
+    {
+        PHYSFS_sint64 len = PHYSFS_fileLength(f);
+        if (len == -1)
+            printf("failed to determine length. Reason: [%s].\n", PHYSFS_getLastError());
+        else
+            printf(" (cast to int) %d bytes.\n", (int) len);
+
+        PHYSFS_close(f);
+    } /* else */
+
+    return(1);
+} /* cmd_filelength */
+
+
+#define WRITESTR "The cat sat on the mat.\n\n"
+
+static int cmd_append(char *args)
+{
+    PHYSFS_File *f;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    f = PHYSFS_openAppend(args);
+    if (f == NULL)
+        printf("failed to open. Reason: [%s].\n", PHYSFS_getLastError());
+    else
+    {
+        size_t bw;
+        PHYSFS_sint64 rc;
+
+        if (do_buffer_size)
+        {
+            if (!PHYSFS_setBuffer(f, do_buffer_size))
+            {
+                printf("failed to set file buffer. Reason: [%s].\n",
+                        PHYSFS_getLastError());
+                PHYSFS_close(f);
+                return(1);
+            } /* if */
+        } /* if */
+
+        bw = strlen(WRITESTR);
+        rc = PHYSFS_write(f, WRITESTR, 1, bw);
+        if (rc != bw)
+        {
+            printf("Wrote (%d) of (%d) bytes. Reason: [%s].\n",
+                   (int) rc, (int) bw, PHYSFS_getLastError());
+        } /* if */
+        else
+        {
+            printf("Successful.\n");
+        } /* else */
+
+        PHYSFS_close(f);
+    } /* else */
+
+    return(1);
+} /* cmd_append */
+
+
+static int cmd_write(char *args)
+{
+    PHYSFS_File *f;
+
+    if (*args == '\"')
+    {
+        args++;
+        args[strlen(args) - 1] = '\0';
+    } /* if */
+
+    f = PHYSFS_openWrite(args);
+    if (f == NULL)
+        printf("failed to open. Reason: [%s].\n", PHYSFS_getLastError());
+    else
+    {
+        size_t bw;
+        PHYSFS_sint64 rc;
+
+        if (do_buffer_size)
+        {
+            if (!PHYSFS_setBuffer(f, do_buffer_size))
+            {
+                printf("failed to set file buffer. Reason: [%s].\n",
+                        PHYSFS_getLastError());
+                PHYSFS_close(f);
+                return(1);
+            } /* if */
+        } /* if */
+
+        bw = strlen(WRITESTR);
+        rc = PHYSFS_write(f, WRITESTR, 1, bw);
+        if (rc != bw)
+        {
+            printf("Wrote (%d) of (%d) bytes. Reason: [%s].\n",
+                   (int) rc, (int) bw, PHYSFS_getLastError());
+        } /* if */
+        else
+        {
+            printf("Successful.\n");
+        } /* else */
+
+        PHYSFS_close(f);
+    } /* else */
+
+    return(1);
+} /* cmd_write */
+
+
+static void modTimeToStr(PHYSFS_sint64 modtime, char *modstr, size_t strsize)
+{
+    time_t t = (time_t) modtime;
+    char *str = ctime(&t);
+    strncpy(modstr, str, strsize);
+    modstr[strsize-1] = '\0';
+} /* modTimeToStr */
+
+
+static int cmd_getlastmodtime(char *args)
+{
+    PHYSFS_sint64 rc = PHYSFS_getLastModTime(args);
+    if (rc == -1)
+        printf("Failed to determine. Reason: [%s].\n", PHYSFS_getLastError());
+    else
+    {
+        char modstr[64];
+        modTimeToStr(rc, modstr, sizeof (modstr));
+        printf("Last modified: %s (%ld).\n", modstr, (long) rc);
+    } /* else */
+
+    return(1);
+} /* cmd_getLastModTime */
+
+
+/* must have spaces trimmed prior to this call. */
+static int count_args(const char *str)
+{
+    int retval = 0;
+    int in_quotes = 0;
+
+    if (str != NULL)
+    {
+        for (; *str != '\0'; str++)
+        {
+            if (*str == '\"')
+                in_quotes = !in_quotes;
+            else if ((*str == ' ') && (!in_quotes))
+                retval++;
+        } /* for */
+        retval++;
+    } /* if */
+
+    return(retval);
+} /* count_args */
+
+
+static int cmd_help(char *args);
+
+typedef struct
+{
+    const char *cmd;
+    int (*func)(char *args);
+    int argcount;
+    const char *usage;
+} command_info;
+
+static const command_info commands[] =
+{
+    { "quit",           cmd_quit,           0, NULL                         },
+    { "q",              cmd_quit,           0, NULL                         },
+    { "help",           cmd_help,           0, NULL                         },
+    { "init",           cmd_init,           1, "<argv0>"                    },
+    { "deinit",         cmd_deinit,         0, NULL                         },
+    { "addarchive",     cmd_addarchive,     2, "<archiveLocation> <append>" },
+    { "mount",          cmd_mount,          3, "<archiveLocation> <mntpoint> <append>" },
+    { "removearchive",  cmd_removearchive,  1, "<archiveLocation>"          },
+    { "enumerate",      cmd_enumerate,      1, "<dirToEnumerate>"           },
+    { "ls",             cmd_enumerate,      1, "<dirToEnumerate>"           },
+    { "getlasterror",   cmd_getlasterror,   0, NULL                         },
+    { "getdirsep",      cmd_getdirsep,      0, NULL                         },
+    { "getcdromdirs",   cmd_getcdromdirs,   0, NULL                         },
+    { "getsearchpath",  cmd_getsearchpath,  0, NULL                         },
+    { "getbasedir",     cmd_getbasedir,     0, NULL                         },
+    { "getuserdir",     cmd_getuserdir,     0, NULL                         },
+    { "getwritedir",    cmd_getwritedir,    0, NULL                         },
+    { "setwritedir",    cmd_setwritedir,    1, "<newWriteDir>"              },
+    { "permitsymlinks", cmd_permitsyms,     1, "<1or0>"                     },
+    { "setsaneconfig",  cmd_setsaneconfig,  5, "<org> <appName> <arcExt> <includeCdRoms> <archivesFirst>" },
+    { "mkdir",          cmd_mkdir,          1, "<dirToMk>"                  },
+    { "delete",         cmd_delete,         1, "<dirToDelete>"              },
+    { "getrealdir",     cmd_getrealdir,     1, "<fileToFind>"               },
+    { "exists",         cmd_exists,         1, "<fileToCheck>"              },
+    { "isdir",          cmd_isdir,          1, "<fileToCheck>"              },
+    { "issymlink",      cmd_issymlink,      1, "<fileToCheck>"              },
+    { "cat",            cmd_cat,            1, "<fileToCat>"                },
+    { "filelength",     cmd_filelength,     1, "<fileToCheck>"              },
+    { "append",         cmd_append,         1, "<fileToAppend>"             },
+    { "write",          cmd_write,          1, "<fileToCreateOrTrash>"      },
+    { "getlastmodtime", cmd_getlastmodtime, 1, "<fileToExamine>"            },
+    { "setbuffer",      cmd_setbuffer,      1, "<bufferSize>"               },
+    { "stressbuffer",   cmd_stressbuffer,   1, "<bufferSize>"               },
+    { NULL,             NULL,              -1, NULL                         }
+};
+
+
+static void output_usage(const char *intro, const command_info *cmdinfo)
+{
+    if (cmdinfo->argcount == 0)
+        printf("%s \"%s\" (no arguments)\n", intro, cmdinfo->cmd);
+    else
+        printf("%s \"%s %s\"\n", intro, cmdinfo->cmd, cmdinfo->usage);
+} /* output_usage */
+
+
+static int cmd_help(char *args)
+{
+    const command_info *i;
+
+    printf("Commands:\n");
+    for (i = commands; i->cmd != NULL; i++)
+        output_usage("  -", i);
+
+    return(1);
+} /* output_cmd_help */
+
+
+static void trim_command(const char *orig, char *copy)
+{
+    const char *i;
+    char *writeptr = copy;
+    int spacecount = 0;
+    int have_first = 0;
+
+    for (i = orig; *i != '\0'; i++)
+    {
+        if (*i == ' ')
+        {
+            if ((*(i + 1) != ' ') && (*(i + 1) != '\0'))
+            {
+                if ((have_first) && (!spacecount))
+                {
+                    spacecount++;
+                    *writeptr = ' ';
+                    writeptr++;
+                } /* if */
+            } /* if */
+        } /* if */
+        else
+        {
+            have_first = 1;
+            spacecount = 0;
+            *writeptr = *i;
+            writeptr++;
+        } /* else */
+    } /* for */
+
+    *writeptr = '\0';
+
+    /*
+    printf("\n command is [%s].\n", copy);
+    */
+} /* trim_command */
+
+
+static int process_command(char *complete_cmd)
+{
+    const command_info *i;
+    char *cmd_copy;
+    char *args;
+    int rc = 1;
+
+    if (complete_cmd == NULL)  /* can happen if user hits CTRL-D, etc. */
+    {
+        printf("\n");
+        return(0);
+    } /* if */
+
+    cmd_copy = (char *) malloc(strlen(complete_cmd) + 1);
+    if (cmd_copy == NULL)
+    {
+        printf("\n\n\nOUT OF MEMORY!\n\n\n");
+        return(0);
+    } /* if */
+
+    trim_command(complete_cmd, cmd_copy);
+    args = strchr(cmd_copy, ' ');
+    if (args != NULL)
+    {
+        *args = '\0';
+        args++;
+    } /* else */
+
+    if (cmd_copy[0] != '\0')
+    {
+        for (i = commands; i->cmd != NULL; i++)
+        {
+            if (strcmp(i->cmd, cmd_copy) == 0)
+            {
+                if ((i->argcount >= 0) && (count_args(args) != i->argcount))
+                    output_usage("usage:", i);
+                else
+                    rc = i->func(args);
+                break;
+            } /* if */
+        } /* for */
+
+        if (i->cmd == NULL)
+            printf("Unknown command. Enter \"help\" for instructions.\n");
+
+#if (defined PHYSFS_HAVE_READLINE)
+        add_history(complete_cmd);
+        if (history_file)
+        {
+            fprintf(history_file, "%s\n", complete_cmd);
+            fflush(history_file);
+        } /* if */
+#endif
+
+    } /* if */
+
+    free(cmd_copy);
+    return(rc);
+} /* process_command */
+
+
+static void open_history_file(void)
+{
+#if (defined PHYSFS_HAVE_READLINE)
+#if 0
+    const char *envr = getenv("TESTPHYSFS_HISTORY");
+    if (!envr)
+        return;
+#else
+    char envr[256];
+    strcpy(envr, PHYSFS_getUserDir());
+    strcat(envr, ".testphys_history");
+#endif
+
+    if (access(envr, F_OK) == 0)
+    {
+        char buf[512];
+        FILE *f = fopen(envr, "r");
+        if (!f)
+        {
+            printf("\n\n"
+                   "Could not open history file [%s] for reading!\n"
+                   "  Will not have past history available.\n\n",
+                    envr);
+            return;
+        } /* if */
+
+        do
+        {
+            fgets(buf, sizeof (buf), f);
+            if (buf[strlen(buf) - 1] == '\n')
+                buf[strlen(buf) - 1] = '\0';
+            add_history(buf);
+        } while (!feof(f));
+
+        fclose(f);
+    } /* if */
+
+    history_file = fopen(envr, "ab");
+    if (!history_file)
+    {
+        printf("\n\n"
+               "Could not open history file [%s] for appending!\n"
+               "  Will not be able to record this session's history.\n\n",
+                envr);
+    } /* if */
+#endif
+} /* open_history_file */
+
+
+int main(int argc, char **argv)
+{
+    char *buf = NULL;
+    int rc = 0;
+
+#if (defined __MWERKS__)
+    extern tSIOUXSettings SIOUXSettings;
+    SIOUXSettings.asktosaveonclose = 0;
+    SIOUXSettings.autocloseonquit = 1;
+    SIOUXSettings.rows = 40;
+    SIOUXSettings.columns = 120;
+#endif
+
+    printf("\n");
+
+    if (!PHYSFS_init(argv[0]))
+    {
+        printf("PHYSFS_init() failed!\n  reason: %s.\n", PHYSFS_getLastError());
+        return(1);
+    } /* if */
+
+    output_versions();
+    output_archivers();
+
+    open_history_file();
+
+    printf("Enter commands. Enter \"help\" for instructions.\n");
+
+    do
+    {
+#if (defined PHYSFS_HAVE_READLINE)
+        buf = readline("> ");
+#else
+        int i;
+        buf = (char *) malloc(512);
+        memset(buf, '\0', 512);
+        printf("> ");
+        for (i = 0; i < 511; i++)
+        {
+            int ch = fgetc(stdin);
+            if (ch == EOF)
+            {
+                strcpy(buf, "quit");
+                break;
+            } /* if */
+            else if ((ch == '\n') || (ch == '\r'))
+            {
+                buf[i] = '\0';
+                break;
+            } /* else if */
+            else if (ch == '\b')
+            {
+                if (i > 0)
+                    i--;
+            } /* else if */
+            else
+            {
+                buf[i] = (char) ch;
+            } /* else */
+        } /* for */
+#endif
+
+        rc = process_command(buf);
+        if (buf != NULL)
+            free(buf);
+    } while (rc);
+
+    if (!PHYSFS_deinit())
+        printf("PHYSFS_deinit() failed!\n  reason: %s.\n", PHYSFS_getLastError());
+
+    if (history_file)
+        fclose(history_file);
+
+/*
+    printf("\n\ntest_physfs written by ryan c. gordon.\n");
+    printf(" it makes you shoot teh railgun bettar.\n");
+*/
+
+    return(0);
+} /* main */
+
+/* end of test_physfs.c ... */
+
diff --git a/src/unison/physfs-1.1.1/test/wxtest_physfs.cpp b/src/unison/physfs-1.1.1/test/wxtest_physfs.cpp
new file mode 100644 (file)
index 0000000..e762633
--- /dev/null
@@ -0,0 +1,486 @@
+/**
+ * Test program for PhysicsFS, using wxWidgets. May only work on Unix.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#if ( (defined(__MACH__)) && (defined(__APPLE__)) )
+#define PLATFORM_MACOSX 1
+#include <Carbon/Carbon.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+
+#include <wx/wx.h>
+#include <wx/treectrl.h>
+
+#include "physfs.h"
+
+#define TEST_VER_MAJOR  1
+#define TEST_VER_MINOR  1
+#define TEST_VER_PATCH  1
+
+//static PHYSFS_uint32 do_buffer_size = 0;
+
+enum WxTestPhysfsMenuCommands
+{
+    // start with standard menu items, since using the wxIDs will map them
+    //  to sane things in the platform's UI (gnome icons in GTK+, moves the
+    //  about and quit items to the Apple menu on Mac OS X, etc).
+    MENUCMD_About = wxID_ABOUT,
+    MENUCMD_Quit = wxID_EXIT,
+
+    // non-standard menu items go here.
+    MENUCMD_Init = wxID_HIGHEST,
+    MENUCMD_Deinit,
+    MENUCMD_AddArchive,
+    MENUCMD_Mount,
+    MENUCMD_Remove,
+    MENUCMD_GetCDs,
+    MENUCMD_SetWriteDir,
+    MENUCMD_PermitSymLinks,
+    MENUCMD_SetSaneConfig,
+    MENUCMD_MkDir,
+    MENUCMD_Delete,
+    MENUCMD_Cat,
+    MENUCMD_SetBuffer,
+    MENUCMD_StressBuffer,
+    MENUCMD_Append,
+    MENUCMD_Write,
+    MENUCMD_GetLastError,
+
+/*
+    { "getdirsep",      cmd_getdirsep,      0, NULL                         },
+    { "getsearchpath",  cmd_getsearchpath,  0, NULL                         },
+    { "getbasedir",     cmd_getbasedir,     0, NULL                         },
+    { "getuserdir",     cmd_getuserdir,     0, NULL                         },
+    { "getwritedir",    cmd_getwritedir,    0, NULL                         },
+    { "getrealdir",     cmd_getrealdir,     1, "<fileToFind>"               },
+    { "exists",         cmd_exists,         1, "<fileToCheck>"              },
+    { "isdir",          cmd_isdir,          1, "<fileToCheck>"              },
+    { "issymlink",      cmd_issymlink,      1, "<fileToCheck>"              },
+    { "filelength",     cmd_filelength,     1, "<fileToCheck>"              },
+    { "getlastmodtime", cmd_getlastmodtime, 1, "<fileToExamine>"            },
+*/
+};
+
+
+class WxTestPhysfsFrame : public wxFrame
+{
+public:
+    WxTestPhysfsFrame(const wxChar *argv0);
+
+    void rebuildTree();
+
+    void onMenuInit(wxCommandEvent &evt);
+    void onMenuDeinit(wxCommandEvent &evt);
+    void onMenuAddArchive(wxCommandEvent &evt);
+    void onMenuGetCDs(wxCommandEvent &evt);
+    void onMenuPermitSymLinks(wxCommandEvent &evt);
+
+private:
+    wxTreeCtrl *fileTree;
+    wxTreeItemId stateItem;
+    wxTreeItemId fsItem;
+
+    int err(int success);
+    void fillFileSystemTree(const char *path, const wxTreeItemId &item);
+    void doInit(const char *argv0);
+    void doDeinit();
+
+    DECLARE_EVENT_TABLE()
+};
+
+BEGIN_EVENT_TABLE(WxTestPhysfsFrame, wxFrame)
+    EVT_MENU(MENUCMD_Init, WxTestPhysfsFrame::onMenuInit)
+    EVT_MENU(MENUCMD_Deinit, WxTestPhysfsFrame::onMenuDeinit)
+    EVT_MENU(MENUCMD_AddArchive, WxTestPhysfsFrame::onMenuAddArchive)
+    EVT_MENU(MENUCMD_GetCDs, WxTestPhysfsFrame::onMenuGetCDs)
+    EVT_MENU(MENUCMD_PermitSymLinks, WxTestPhysfsFrame::onMenuPermitSymLinks)
+END_EVENT_TABLE()
+
+
+
+// This is the the Application itself.
+class WxTestPhysfsApp : public wxApp
+{
+public:
+    WxTestPhysfsApp() : mainWindow(NULL) { /* no-op. */ }
+    virtual bool OnInit();
+
+private:
+    WxTestPhysfsFrame *mainWindow;
+};
+
+DECLARE_APP(WxTestPhysfsApp)
+
+
+static inline char *newstr(const char *str)
+{
+    char *retval = NULL;
+    if (str != NULL)
+    {
+        retval = new char[strlen(str) + 1];
+        strcpy(retval, str);
+    } // if
+    return retval;
+} // newstr
+
+static char *newutf8(const wxString &wxstr)
+{
+    #if wxUSE_UNICODE
+    size_t len = wxstr.Len() + 1;
+    char *utf8text = new char[len * 6];
+    wxConvUTF8.WC2MB(utf8text, wxstr, len);
+    return utf8text;
+    #else
+    return newstr(wxstr);
+    #endif
+} // newutf8
+
+
+WxTestPhysfsFrame::WxTestPhysfsFrame(const wxChar *argv0)
+    : wxFrame(NULL, -1, wxT("WxTestPhysfs"))
+{
+    this->CreateStatusBar();
+
+    wxMenuBar *menuBar = new wxMenuBar;
+
+    wxMenu *stuffMenu = new wxMenu;
+    stuffMenu->Append(MENUCMD_Init, wxT("&Init"));
+    stuffMenu->Append(MENUCMD_Deinit, wxT("&Deinit"));
+    stuffMenu->Append(MENUCMD_AddArchive, wxT("&Add Archive"));
+    stuffMenu->Append(MENUCMD_Mount, wxT("&Mount Archive"));
+    stuffMenu->Append(MENUCMD_Remove, wxT("&Remove Archive"));
+    stuffMenu->Append(MENUCMD_GetCDs, wxT("&Get CD-ROM drives"));
+    stuffMenu->Append(MENUCMD_SetWriteDir, wxT("&Set Write Dir"));
+    stuffMenu->Append(MENUCMD_SetSaneConfig, wxT("Set Sane &Config"));
+    stuffMenu->Append(MENUCMD_MkDir, wxT("M&kDir"));
+    stuffMenu->Append(MENUCMD_Delete, wxT("D&elete"));
+    stuffMenu->Append(MENUCMD_Cat, wxT("&Cat"));
+    stuffMenu->Append(MENUCMD_SetBuffer, wxT("Set &Buffer"));
+    stuffMenu->Append(MENUCMD_StressBuffer, wxT("Stress &Test Buffer"));
+    stuffMenu->Append(MENUCMD_Append, wxT("&Append"));
+    stuffMenu->Append(MENUCMD_Write, wxT("&Write"));
+    stuffMenu->Append(MENUCMD_Write, wxT("&Update getLastError"));
+    stuffMenu->AppendCheckItem(MENUCMD_PermitSymLinks, wxT("&Permit symlinks"));
+    menuBar->Append(stuffMenu, wxT("&Stuff"));
+
+    //wxMenu *helpMenu = new wxMenu;
+    //helpMenu->Append(MENUCMD_About, wxT("&About\tF1"));
+    //menuBar->Append(helpMenu, wxT("&Help"));
+
+    this->SetMenuBar(menuBar);
+
+    this->fileTree = new wxTreeCtrl(this, -1);
+
+    // The sizer just makes sure that fileTree owns whole client area.
+    wxBoxSizer *sizer = new wxBoxSizer(wxVERTICAL);
+    sizer->Add(this->fileTree, 1, wxALL | wxEXPAND | wxALIGN_CENTRE);
+    sizer->SetItemMinSize(this->fileTree, 1, 1);
+    this->SetSizer(sizer);
+
+    char *utf8argv0 = newutf8(wxString(argv0));
+    this->doInit(utf8argv0);
+    delete[] utf8argv0;
+} // WxTestPhysfsFrame::WxTestPhysfsFrame
+
+
+int WxTestPhysfsFrame::err(int success)
+{
+    if (success)
+        this->SetStatusText(wxT(""));
+    else
+        this->SetStatusText(wxString(PHYSFS_getLastError(), wxConvUTF8));
+    return success;
+} // WxTestPhysfsFrame::err
+
+
+void WxTestPhysfsFrame::fillFileSystemTree(const char *path,
+                                           const wxTreeItemId &item)
+{
+    char **rc = PHYSFS_enumerateFiles(path);
+    char **i;
+    wxTreeItemId id;
+
+    if (rc == NULL)
+    {
+        const wxString quote(wxT("'"));
+        wxString str(wxT("Enumeration error: "));
+        str << quote << wxString(PHYSFS_getLastError(), wxConvUTF8) << quote;
+        id = this->fileTree->AppendItem(item, str);
+        this->fileTree->SetItemTextColour(id, wxColour(255, 0, 0));
+    } // if
+    else
+    {
+        for (i = rc; *i != NULL; i++)
+        {
+            id = this->fileTree->AppendItem(item, wxString(*i, wxConvUTF8));
+            const int len = strlen(path) + strlen(*i) + 2;
+            char *fname = new char[len];
+            const char *origdir = path;
+            if (strcmp(origdir, "/") == 0)
+                origdir = "";
+            snprintf(fname, len, "%s/%s", origdir, *i);
+
+            if (PHYSFS_isDirectory(fname))
+            {
+                this->fileTree->SetItemTextColour(id, wxColour(0, 0, 255));
+                this->fillFileSystemTree(fname, id);
+            } // if
+
+            else if (PHYSFS_isSymbolicLink(fname))
+            {
+                this->fileTree->SetItemTextColour(id, wxColour(0, 255, 0));
+            } // else if
+
+            else  // ...file.
+            {
+            } // else
+
+            delete[] fname;
+        } // for
+
+        PHYSFS_freeList(rc);
+    } // else
+} // fillFileSystemTree
+
+
+void WxTestPhysfsFrame::rebuildTree()
+{
+    const wxString dot(wxT("."));
+    const wxString quote(wxT("'"));
+    wxTreeItemId item;
+    wxString str;
+    const char *cstr = NULL;
+    const bool wasInit = PHYSFS_isInit() ? true : false;
+
+    this->fileTree->DeleteAllItems();
+    wxTreeItemId root = this->fileTree->AddRoot(wxT("PhysicsFS"));
+    this->stateItem = this->fileTree->AppendItem(root, wxT("Library state"));
+
+    str = wxT("Initialized: ");
+    str << ((wasInit) ? wxT("true") : wxT("false"));
+    this->fileTree->AppendItem(this->stateItem, str);
+
+    this->fileTree->Expand(this->stateItem);
+    this->fileTree->Expand(root);
+
+    // Fill in version information...
+
+    PHYSFS_Version ver;
+    item = this->stateItem;
+    str = wxT("wxtest_physfs version: ");
+    str << TEST_VER_MAJOR << dot << TEST_VER_MINOR << dot << TEST_VER_PATCH;
+    this->fileTree->AppendItem(item, str);
+    PHYSFS_VERSION(&ver);
+    str = wxT("Compiled against PhysicsFS version: ");
+    str << (int) ver.major << dot << (int) ver.minor << dot << ver.patch;
+    this->fileTree->AppendItem(item, str);
+    PHYSFS_getLinkedVersion(&ver);
+    str = wxT("Linked against PhysicsFS version: ");
+    str << (int) ver.major << dot << (int) ver.minor << dot << ver.patch;
+    this->fileTree->AppendItem(item, str);
+
+    if (!wasInit)
+        return;   // nothing else to do before initialization...
+
+    str = wxT("Symbolic links permitted: ");
+    str << ((PHYSFS_symbolicLinksPermitted()) ? wxT("true") : wxT("false"));
+    this->fileTree->AppendItem(this->stateItem, str);
+
+    str = wxT("Native directory separator: ");
+    str << quote << wxString(PHYSFS_getDirSeparator(), wxConvUTF8) << quote;
+    this->fileTree->AppendItem(this->stateItem, str);
+
+    // Fill in supported archives...
+
+    item = this->fileTree->AppendItem(this->stateItem, wxT("Archivers"));
+    const PHYSFS_ArchiveInfo **arcs = PHYSFS_supportedArchiveTypes();
+    if (*arcs == NULL)
+        this->fileTree->AppendItem(item, wxT("(none)"));
+    else
+    {
+        const PHYSFS_ArchiveInfo **i;
+        for (i = arcs; *i != NULL; i++)
+        {
+            const wxString ext((*i)->extension, wxConvUTF8);
+            const wxString desc((*i)->description, wxConvUTF8);
+            const wxString auth((*i)->author, wxConvUTF8);
+            const wxString url((*i)->url, wxConvUTF8);
+            wxTreeItemId arcitem = this->fileTree->AppendItem(item, ext);
+            this->fileTree->AppendItem(arcitem, desc);
+            this->fileTree->AppendItem(arcitem, auth);
+            this->fileTree->AppendItem(arcitem, url);
+        } // for
+    } // else
+
+
+    // Fill in the standard paths...
+
+    item = this->fileTree->AppendItem(this->stateItem, wxT("Paths"));
+    str = wxT("Base directory: ");
+    str << quote << wxString(PHYSFS_getBaseDir(), wxConvUTF8) << quote;
+    this->fileTree->AppendItem(item, str);
+    str = wxT("User directory: ");
+    str << quote << wxString(PHYSFS_getUserDir(), wxConvUTF8) << quote;
+    this->fileTree->AppendItem(item, str);
+    str = wxT("Write directory: ");
+    if ((cstr = PHYSFS_getWriteDir()) == NULL)
+        str << wxT("(NULL)");
+    else
+        str << quote << wxString(cstr ? cstr : "(NULL)", wxConvUTF8) << quote;
+    this->fileTree->AppendItem(item, str);
+    //str = wxT("Preference directory: ");
+    //str << wxString(PHYSFS_getUserDir(), wxConvUTF8);
+    //this->fileTree->AppendItem(item, str);
+
+    // Fill in the CD-ROMs...
+
+    item = this->fileTree->AppendItem(this->stateItem, wxT("CD-ROMs"));
+    char **cds = PHYSFS_getCdRomDirs();
+    if (cds == NULL)
+    {
+        str = wxT("Error: ");
+        str << quote << wxString(PHYSFS_getLastError(), wxConvUTF8) << quote;
+        wxTreeItemId id = this->fileTree->AppendItem(item, str);
+        this->fileTree->SetItemTextColour(id, wxColour(255, 0, 0));
+    } // if
+    else
+    {
+        if (*cds == NULL)
+            this->fileTree->AppendItem(item, wxT("(none)"));
+        else
+        {
+            char **i;
+            for (i = cds; *i != NULL; i++)
+                this->fileTree->AppendItem(item, wxString(*i, wxConvUTF8));
+        } // else
+        PHYSFS_freeList(cds);
+    } // else
+
+    // Fill in search path...
+
+    item = this->fileTree->AppendItem(this->stateItem, wxT("Search path"));
+    char **sp = PHYSFS_getSearchPath();
+    if (sp == NULL)
+    {
+        str = wxT("Error: ");
+        str << quote << wxString(PHYSFS_getLastError(), wxConvUTF8) << quote;
+        wxTreeItemId id = this->fileTree->AppendItem(item, str);
+        this->fileTree->SetItemTextColour(id, wxColour(255, 0, 0));
+    } // if
+    else
+    {
+        if (*sp == NULL)
+            this->fileTree->AppendItem(item, wxT("(none)"));
+        else
+        {
+            char **i;
+            for (i = sp; *i != NULL; i++)
+                this->fileTree->AppendItem(item, wxString(*i, wxConvUTF8));
+        } // else
+        PHYSFS_freeList(sp);
+    } // else
+
+    // Now fill in the filesystem...
+
+    this->fsItem = this->fileTree->AppendItem(root, wxT("Filesystem"));
+    this->fillFileSystemTree("/", this->fsItem);
+    this->fileTree->Expand(this->fsItem);
+} // WxTestPhysfsFrame::rebuildTree
+
+
+void WxTestPhysfsFrame::doInit(const char *argv0)
+{
+    if (!this->err(PHYSFS_init(argv0)))
+        ::wxMessageBox(wxT("PHYSFS_init() failed!"), wxT("wxTestPhysfs"));
+    this->rebuildTree();
+} // WxTestPhysfsFrame::doInit
+
+
+void WxTestPhysfsFrame::doDeinit()
+{
+    if (!this->err(PHYSFS_deinit()))
+        ::wxMessageBox(wxT("PHYSFS_deinit() failed!"), wxT("wxTestPhysfs"));
+    this->rebuildTree();
+} // WxTestPhysfsFrame::doDeinit
+
+
+void WxTestPhysfsFrame::onMenuInit(wxCommandEvent &evt)
+{
+    wxString argv0(wxGetApp().argv[0] == NULL ? wxT("") : wxGetApp().argv[0]);
+    wxString str(wxGetTextFromUser(wxT("PHYSFS_init"),
+                 wxT("argv[0]? (cancel for NULL)"), argv0));
+    char *cstr = str.IsEmpty() ? NULL : newutf8(str);
+    this->doInit(cstr);
+    delete[] cstr;
+} // WxTestPhysfsFrame::onMenuInit
+
+
+void WxTestPhysfsFrame::onMenuDeinit(wxCommandEvent &evt)
+{
+    this->doDeinit();
+} // WxTestPhysfsFrame::onMenuDeinit
+
+
+void WxTestPhysfsFrame::onMenuAddArchive(wxCommandEvent &evt)
+{
+    wxString arc = wxFileSelector(wxT("Choose archive to add"));
+    if (!arc.IsEmpty())
+    {
+        char *cstr = newutf8(arc);
+        // !!! FIXME: add to start/end?
+        if (!this->err(PHYSFS_addToSearchPath(cstr, 1)))
+            ::wxMessageBox(wxT("PHYSFS_addToSearchPath() failed!"), wxT("wxTestPhysfs"));
+        delete[] cstr;
+        this->rebuildTree();
+    } // if
+} // WxTestPhysfsFrame::onMenuAddArchive
+
+
+void WxTestPhysfsFrame::onMenuGetCDs(wxCommandEvent &evt)
+{
+    this->rebuildTree();  // This will call PHYSFS_getCdRomDirs()...
+} // WxTestPhysfsFrame::onMenuGetCDs
+
+
+void WxTestPhysfsFrame::onMenuPermitSymLinks(wxCommandEvent &evt)
+{
+    PHYSFS_permitSymbolicLinks(evt.IsChecked() ? 1 : 0);
+    this->rebuildTree();
+} // WxTestPhysfsFrame::onMenuPermitSymLinks
+
+
+
+IMPLEMENT_APP(WxTestPhysfsApp)
+
+bool WxTestPhysfsApp::OnInit()
+{
+    #if PLATFORM_MACOSX
+    // This lets a stdio app become a GUI app. Otherwise, you won't get
+    //  GUI events from the system and other things will fail to work.
+    // Putting the app in an application bundle does the same thing.
+    //  TransformProcessType() is a 10.3+ API. SetFrontProcess() is 10.0+.
+    if (TransformProcessType != NULL)  // check it as a weak symbol.
+    {
+        ProcessSerialNumber psn = { 0, kCurrentProcess };
+        TransformProcessType(&psn, kProcessTransformToForegroundApplication);
+        SetFrontProcess(&psn);
+    } // if
+    #endif
+
+    this->mainWindow = new WxTestPhysfsFrame(this->argv[0]);
+    this->mainWindow->Show(true);
+    SetTopWindow(this->mainWindow);
+    return true;
+} // WxTestPhysfsApp::OnInit
+
+// end of wxtest_physfs.cpp ...
+
diff --git a/src/unison/physfs-1.1.1/zlib123/adler32.c b/src/unison/physfs-1.1.1/zlib123/adler32.c
new file mode 100644 (file)
index 0000000..007ba26
--- /dev/null
@@ -0,0 +1,149 @@
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+#define BASE 65521UL    /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
+#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf)   DO8(buf,0); DO8(buf,8);
+
+/* use NO_DIVIDE if your processor does not do division in hardware */
+#ifdef NO_DIVIDE
+#  define MOD(a) \
+    do { \
+        if (a >= (BASE << 16)) a -= (BASE << 16); \
+        if (a >= (BASE << 15)) a -= (BASE << 15); \
+        if (a >= (BASE << 14)) a -= (BASE << 14); \
+        if (a >= (BASE << 13)) a -= (BASE << 13); \
+        if (a >= (BASE << 12)) a -= (BASE << 12); \
+        if (a >= (BASE << 11)) a -= (BASE << 11); \
+        if (a >= (BASE << 10)) a -= (BASE << 10); \
+        if (a >= (BASE << 9)) a -= (BASE << 9); \
+        if (a >= (BASE << 8)) a -= (BASE << 8); \
+        if (a >= (BASE << 7)) a -= (BASE << 7); \
+        if (a >= (BASE << 6)) a -= (BASE << 6); \
+        if (a >= (BASE << 5)) a -= (BASE << 5); \
+        if (a >= (BASE << 4)) a -= (BASE << 4); \
+        if (a >= (BASE << 3)) a -= (BASE << 3); \
+        if (a >= (BASE << 2)) a -= (BASE << 2); \
+        if (a >= (BASE << 1)) a -= (BASE << 1); \
+        if (a >= BASE) a -= BASE; \
+    } while (0)
+#  define MOD4(a) \
+    do { \
+        if (a >= (BASE << 4)) a -= (BASE << 4); \
+        if (a >= (BASE << 3)) a -= (BASE << 3); \
+        if (a >= (BASE << 2)) a -= (BASE << 2); \
+        if (a >= (BASE << 1)) a -= (BASE << 1); \
+        if (a >= BASE) a -= BASE; \
+    } while (0)
+#else
+#  define MOD(a) a %= BASE
+#  define MOD4(a) a %= BASE
+#endif
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+    uLong adler;
+    const Bytef *buf;
+    uInt len;
+{
+    unsigned long sum2;
+    unsigned n;
+
+    /* split Adler-32 into component sums */
+    sum2 = (adler >> 16) & 0xffff;
+    adler &= 0xffff;
+
+    /* in case user likes doing a byte at a time, keep it fast */
+    if (len == 1) {
+        adler += buf[0];
+        if (adler >= BASE)
+            adler -= BASE;
+        sum2 += adler;
+        if (sum2 >= BASE)
+            sum2 -= BASE;
+        return adler | (sum2 << 16);
+    }
+
+    /* initial Adler-32 value (deferred check for len == 1 speed) */
+    if (buf == Z_NULL)
+        return 1L;
+
+    /* in case short lengths are provided, keep it somewhat fast */
+    if (len < 16) {
+        while (len--) {
+            adler += *buf++;
+            sum2 += adler;
+        }
+        if (adler >= BASE)
+            adler -= BASE;
+        MOD4(sum2);             /* only added so many BASE's */
+        return adler | (sum2 << 16);
+    }
+
+    /* do length NMAX blocks -- requires just one modulo operation */
+    while (len >= NMAX) {
+        len -= NMAX;
+        n = NMAX / 16;          /* NMAX is divisible by 16 */
+        do {
+            DO16(buf);          /* 16 sums unrolled */
+            buf += 16;
+        } while (--n);
+        MOD(adler);
+        MOD(sum2);
+    }
+
+    /* do remaining bytes (less than NMAX, still just one modulo) */
+    if (len) {                  /* avoid modulos if none remaining */
+        while (len >= 16) {
+            len -= 16;
+            DO16(buf);
+            buf += 16;
+        }
+        while (len--) {
+            adler += *buf++;
+            sum2 += adler;
+        }
+        MOD(adler);
+        MOD(sum2);
+    }
+
+    /* return recombined sums */
+    return adler | (sum2 << 16);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT adler32_combine(adler1, adler2, len2)
+    uLong adler1;
+    uLong adler2;
+    z_off_t len2;
+{
+    unsigned long sum1;
+    unsigned long sum2;
+    unsigned rem;
+
+    /* the derivation of this formula is left as an exercise for the reader */
+    rem = (unsigned)(len2 % BASE);
+    sum1 = adler1 & 0xffff;
+    sum2 = rem * sum1;
+    MOD(sum2);
+    sum1 += (adler2 & 0xffff) + BASE - 1;
+    sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
+    if (sum1 > BASE) sum1 -= BASE;
+    if (sum1 > BASE) sum1 -= BASE;
+    if (sum2 > (BASE << 1)) sum2 -= (BASE << 1);
+    if (sum2 > BASE) sum2 -= BASE;
+    return sum1 | (sum2 << 16);
+}
diff --git a/src/unison/physfs-1.1.1/zlib123/compress.c b/src/unison/physfs-1.1.1/zlib123/compress.c
new file mode 100644 (file)
index 0000000..df04f01
--- /dev/null
@@ -0,0 +1,79 @@
+/* compress.c -- compress a memory buffer
+ * Copyright (C) 1995-2003 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+     Compresses the source buffer into the destination buffer. The level
+   parameter has the same meaning as in deflateInit.  sourceLen is the byte
+   length of the source buffer. Upon entry, destLen is the total size of the
+   destination buffer, which must be at least 0.1% larger than sourceLen plus
+   12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+   Z_STREAM_ERROR if the level parameter is invalid.
+*/
+int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong sourceLen;
+    int level;
+{
+    z_stream stream;
+    int err;
+
+    stream.next_in = (Bytef*)source;
+    stream.avail_in = (uInt)sourceLen;
+#ifdef MAXSEG_64K
+    /* Check for source > 64K on 16-bit machine: */
+    if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+#endif
+    stream.next_out = dest;
+    stream.avail_out = (uInt)*destLen;
+    if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+    stream.zalloc = (alloc_func)0;
+    stream.zfree = (free_func)0;
+    stream.opaque = (voidpf)0;
+
+    err = deflateInit(&stream, level);
+    if (err != Z_OK) return err;
+
+    err = deflate(&stream, Z_FINISH);
+    if (err != Z_STREAM_END) {
+        deflateEnd(&stream);
+        return err == Z_OK ? Z_BUF_ERROR : err;
+    }
+    *destLen = stream.total_out;
+
+    err = deflateEnd(&stream);
+    return err;
+}
+
+/* ===========================================================================
+ */
+int ZEXPORT compress (dest, destLen, source, sourceLen)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong sourceLen;
+{
+    return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
+}
+
+/* ===========================================================================
+     If the default memLevel or windowBits for deflateInit() is changed, then
+   this function needs to be updated.
+ */
+uLong ZEXPORT compressBound (sourceLen)
+    uLong sourceLen;
+{
+    return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11;
+}
diff --git a/src/unison/physfs-1.1.1/zlib123/crc32.c b/src/unison/physfs-1.1.1/zlib123/crc32.c
new file mode 100644 (file)
index 0000000..f658a9e
--- /dev/null
@@ -0,0 +1,423 @@
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
+ * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
+ * tables for updating the shift register in one step with three exclusive-ors
+ * instead of four steps with four exclusive-ors.  This results in about a
+ * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
+ */
+
+/* @(#) $Id$ */
+
+/*
+  Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore
+  protection on the static variables used to control the first-use generation
+  of the crc tables.  Therefore, if you #define DYNAMIC_CRC_TABLE, you should
+  first call get_crc_table() to initialize the tables before allowing more than
+  one thread to use crc32().
+ */
+
+#ifdef MAKECRCH
+#  include <stdio.h>
+#  ifndef DYNAMIC_CRC_TABLE
+#    define DYNAMIC_CRC_TABLE
+#  endif /* !DYNAMIC_CRC_TABLE */
+#endif /* MAKECRCH */
+
+#include "zutil.h"      /* for STDC and FAR definitions */
+
+#define local static
+
+/* Find a four-byte integer type for crc32_little() and crc32_big(). */
+#ifndef NOBYFOUR
+#  ifdef STDC           /* need ANSI C limits.h to determine sizes */
+#    include <limits.h>
+#    define BYFOUR
+#    if (UINT_MAX == 0xffffffffUL)
+       typedef unsigned int u4;
+#    else
+#      if (ULONG_MAX == 0xffffffffUL)
+         typedef unsigned long u4;
+#      else
+#        if (USHRT_MAX == 0xffffffffUL)
+           typedef unsigned short u4;
+#        else
+#          undef BYFOUR     /* can't find a four-byte integer type! */
+#        endif
+#      endif
+#    endif
+#  endif /* STDC */
+#endif /* !NOBYFOUR */
+
+/* Definitions for doing the crc four data bytes at a time. */
+#ifdef BYFOUR
+#  define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \
+                (((w)&0xff00)<<8)+(((w)&0xff)<<24))
+   local unsigned long crc32_little OF((unsigned long,
+                        const unsigned char FAR *, unsigned));
+   local unsigned long crc32_big OF((unsigned long,
+                        const unsigned char FAR *, unsigned));
+#  define TBLS 8
+#else
+#  define TBLS 1
+#endif /* BYFOUR */
+
+/* Local functions for crc concatenation */
+local unsigned long gf2_matrix_times OF((unsigned long *mat,
+                                         unsigned long vec));
+local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat));
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local volatile int crc_table_empty = 1;
+local unsigned long FAR crc_table[TBLS][256];
+local void make_crc_table OF((void));
+#ifdef MAKECRCH
+   local void write_table OF((FILE *, const unsigned long FAR *));
+#endif /* MAKECRCH */
+/*
+  Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
+  x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+  Polynomials over GF(2) are represented in binary, one bit per coefficient,
+  with the lowest powers in the most significant bit.  Then adding polynomials
+  is just exclusive-or, and multiplying a polynomial by x is a right shift by
+  one.  If we call the above polynomial p, and represent a byte as the
+  polynomial q, also with the lowest power in the most significant bit (so the
+  byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+  where a mod b means the remainder after dividing a by b.
+
+  This calculation is done using the shift-register method of multiplying and
+  taking the remainder.  The register is initialized to zero, and for each
+  incoming bit, x^32 is added mod p to the register if the bit is a one (where
+  x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+  x (which is shifting right by one and adding x^32 mod p if the bit shifted
+  out is a one).  We start with the highest power (least significant bit) of
+  q and repeat for all eight bits of q.
+
+  The first table is simply the CRC of all possible eight bit values.  This is
+  all the information needed to generate CRCs on data a byte at a time for all
+  combinations of CRC register values and incoming bytes.  The remaining tables
+  allow for word-at-a-time CRC calculation for both big-endian and little-
+  endian machines, where a word is four bytes.
+*/
+local void make_crc_table()
+{
+    unsigned long c;
+    int n, k;
+    unsigned long poly;                 /* polynomial exclusive-or pattern */
+    /* terms of polynomial defining this crc (except x^32): */
+    static volatile int first = 1;      /* flag to limit concurrent making */
+    static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+    /* See if another task is already doing this (not thread-safe, but better
+       than nothing -- significantly reduces duration of vulnerability in
+       case the advice about DYNAMIC_CRC_TABLE is ignored) */
+    if (first) {
+        first = 0;
+
+        /* make exclusive-or pattern from polynomial (0xedb88320UL) */
+        poly = 0UL;
+        for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++)
+            poly |= 1UL << (31 - p[n]);
+
+        /* generate a crc for every 8-bit value */
+        for (n = 0; n < 256; n++) {
+            c = (unsigned long)n;
+            for (k = 0; k < 8; k++)
+                c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+            crc_table[0][n] = c;
+        }
+
+#ifdef BYFOUR
+        /* generate crc for each value followed by one, two, and three zeros,
+           and then the byte reversal of those as well as the first table */
+        for (n = 0; n < 256; n++) {
+            c = crc_table[0][n];
+            crc_table[4][n] = REV(c);
+            for (k = 1; k < 4; k++) {
+                c = crc_table[0][c & 0xff] ^ (c >> 8);
+                crc_table[k][n] = c;
+                crc_table[k + 4][n] = REV(c);
+            }
+        }
+#endif /* BYFOUR */
+
+        crc_table_empty = 0;
+    }
+    else {      /* not first */
+        /* wait for the other guy to finish (not efficient, but rare) */
+        while (crc_table_empty)
+            ;
+    }
+
+#ifdef MAKECRCH
+    /* write out CRC tables to crc32.h */
+    {
+        FILE *out;
+
+        out = fopen("crc32.h", "w");
+        if (out == NULL) return;
+        fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n");
+        fprintf(out, " * Generated automatically by crc32.c\n */\n\n");
+        fprintf(out, "local const unsigned long FAR ");
+        fprintf(out, "crc_table[TBLS][256] =\n{\n  {\n");
+        write_table(out, crc_table[0]);
+#  ifdef BYFOUR
+        fprintf(out, "#ifdef BYFOUR\n");
+        for (k = 1; k < 8; k++) {
+            fprintf(out, "  },\n  {\n");
+            write_table(out, crc_table[k]);
+        }
+        fprintf(out, "#endif\n");
+#  endif /* BYFOUR */
+        fprintf(out, "  }\n};\n");
+        fclose(out);
+    }
+#endif /* MAKECRCH */
+}
+
+#ifdef MAKECRCH
+local void write_table(out, table)
+    FILE *out;
+    const unsigned long FAR *table;
+{
+    int n;
+
+    for (n = 0; n < 256; n++)
+        fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : "    ", table[n],
+                n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", "));
+}
+#endif /* MAKECRCH */
+
+#else /* !DYNAMIC_CRC_TABLE */
+/* ========================================================================
+ * Tables of CRC-32s of all single-byte values, made by make_crc_table().
+ */
+#include "crc32.h"
+#endif /* DYNAMIC_CRC_TABLE */
+
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const unsigned long FAR * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+    if (crc_table_empty)
+        make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+    return (const unsigned long FAR *)crc_table;
+}
+
+/* ========================================================================= */
+#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
+#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
+
+/* ========================================================================= */
+unsigned long ZEXPORT crc32(crc, buf, len)
+    unsigned long crc;
+    const unsigned char FAR *buf;
+    unsigned len;
+{
+    if (buf == Z_NULL) return 0UL;
+
+#ifdef DYNAMIC_CRC_TABLE
+    if (crc_table_empty)
+        make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+
+#ifdef BYFOUR
+    if (sizeof(void *) == sizeof(ptrdiff_t)) {
+        u4 endian;
+
+        endian = 1;
+        if (*((unsigned char *)(&endian)))
+            return crc32_little(crc, buf, len);
+        else
+            return crc32_big(crc, buf, len);
+    }
+#endif /* BYFOUR */
+    crc = crc ^ 0xffffffffUL;
+    while (len >= 8) {
+        DO8;
+        len -= 8;
+    }
+    if (len) do {
+        DO1;
+    } while (--len);
+    return crc ^ 0xffffffffUL;
+}
+
+#ifdef BYFOUR
+
+/* ========================================================================= */
+#define DOLIT4 c ^= *buf4++; \
+        c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
+            crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]
+#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4
+
+/* ========================================================================= */
+local unsigned long crc32_little(crc, buf, len)
+    unsigned long crc;
+    const unsigned char FAR *buf;
+    unsigned len;
+{
+    register u4 c;
+    register const u4 FAR *buf4;
+
+    c = (u4)crc;
+    c = ~c;
+    while (len && ((ptrdiff_t)buf & 3)) {
+        c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+        len--;
+    }
+
+    buf4 = (const u4 FAR *)(const void FAR *)buf;
+    while (len >= 32) {
+        DOLIT32;
+        len -= 32;
+    }
+    while (len >= 4) {
+        DOLIT4;
+        len -= 4;
+    }
+    buf = (const unsigned char FAR *)buf4;
+
+    if (len) do {
+        c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+    } while (--len);
+    c = ~c;
+    return (unsigned long)c;
+}
+
+/* ========================================================================= */
+#define DOBIG4 c ^= *++buf4; \
+        c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
+            crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
+#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
+
+/* ========================================================================= */
+local unsigned long crc32_big(crc, buf, len)
+    unsigned long crc;
+    const unsigned char FAR *buf;
+    unsigned len;
+{
+    register u4 c;
+    register const u4 FAR *buf4;
+
+    c = REV((u4)crc);
+    c = ~c;
+    while (len && ((ptrdiff_t)buf & 3)) {
+        c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+        len--;
+    }
+
+    buf4 = (const u4 FAR *)(const void FAR *)buf;
+    buf4--;
+    while (len >= 32) {
+        DOBIG32;
+        len -= 32;
+    }
+    while (len >= 4) {
+        DOBIG4;
+        len -= 4;
+    }
+    buf4++;
+    buf = (const unsigned char FAR *)buf4;
+
+    if (len) do {
+        c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+    } while (--len);
+    c = ~c;
+    return (unsigned long)(REV(c));
+}
+
+#endif /* BYFOUR */
+
+#define GF2_DIM 32      /* dimension of GF(2) vectors (length of CRC) */
+
+/* ========================================================================= */
+local unsigned long gf2_matrix_times(mat, vec)
+    unsigned long *mat;
+    unsigned long vec;
+{
+    unsigned long sum;
+
+    sum = 0;
+    while (vec) {
+        if (vec & 1)
+            sum ^= *mat;
+        vec >>= 1;
+        mat++;
+    }
+    return sum;
+}
+
+/* ========================================================================= */
+local void gf2_matrix_square(square, mat)
+    unsigned long *square;
+    unsigned long *mat;
+{
+    int n;
+
+    for (n = 0; n < GF2_DIM; n++)
+        square[n] = gf2_matrix_times(mat, mat[n]);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT crc32_combine(crc1, crc2, len2)
+    uLong crc1;
+    uLong crc2;
+    z_off_t len2;
+{
+    int n;
+    unsigned long row;
+    unsigned long even[GF2_DIM];    /* even-power-of-two zeros operator */
+    unsigned long odd[GF2_DIM];     /* odd-power-of-two zeros operator */
+
+    /* degenerate case */
+    if (len2 == 0)
+        return crc1;
+
+    /* put operator for one zero bit in odd */
+    odd[0] = 0xedb88320L;           /* CRC-32 polynomial */
+    row = 1;
+    for (n = 1; n < GF2_DIM; n++) {
+        odd[n] = row;
+        row <<= 1;
+    }
+
+    /* put operator for two zero bits in even */
+    gf2_matrix_square(even, odd);
+
+    /* put operator for four zero bits in odd */
+    gf2_matrix_square(odd, even);
+
+    /* apply len2 zeros to crc1 (first square will put the operator for one
+       zero byte, eight zero bits, in even) */
+    do {
+        /* apply zeros operator for this bit of len2 */
+        gf2_matrix_square(even, odd);
+        if (len2 & 1)
+            crc1 = gf2_matrix_times(even, crc1);
+        len2 >>= 1;
+
+        /* if no more bits set, then done */
+        if (len2 == 0)
+            break;
+
+        /* another iteration of the loop with odd and even swapped */
+        gf2_matrix_square(odd, even);
+        if (len2 & 1)
+            crc1 = gf2_matrix_times(odd, crc1);
+        len2 >>= 1;
+
+        /* if no more bits set, then done */
+    } while (len2 != 0);
+
+    /* return combined crc */
+    crc1 ^= crc2;
+    return crc1;
+}
diff --git a/src/unison/physfs-1.1.1/zlib123/crc32.h b/src/unison/physfs-1.1.1/zlib123/crc32.h
new file mode 100644 (file)
index 0000000..8053b61
--- /dev/null
@@ -0,0 +1,441 @@
+/* crc32.h -- tables for rapid CRC calculation
+ * Generated automatically by crc32.c
+ */
+
+local const unsigned long FAR crc_table[TBLS][256] =
+{
+  {
+    0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
+    0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
+    0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
+    0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
+    0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
+    0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
+    0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
+    0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
+    0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
+    0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
+    0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
+    0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
+    0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
+    0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
+    0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
+    0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
+    0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
+    0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
+    0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
+    0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
+    0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
+    0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
+    0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
+    0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
+    0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
+    0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
+    0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
+    0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
+    0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
+    0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
+    0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
+    0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
+    0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
+    0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
+    0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
+    0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
+    0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
+    0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
+    0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
+    0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
+    0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
+    0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
+    0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
+    0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
+    0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
+    0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
+    0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
+    0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
+    0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
+    0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
+    0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
+    0x2d02ef8dUL
+#ifdef BYFOUR
+  },
+  {
+    0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL,
+    0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL,
+    0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL,
+    0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL,
+    0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL,
+    0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL,
+    0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL,
+    0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL,
+    0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL,
+    0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL,
+    0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL,
+    0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL,
+    0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL,
+    0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL,
+    0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL,
+    0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL,
+    0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL,
+    0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL,
+    0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL,
+    0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL,
+    0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL,
+    0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL,
+    0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL,
+    0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL,
+    0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL,
+    0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL,
+    0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL,
+    0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL,
+    0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL,
+    0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL,
+    0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL,
+    0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL,
+    0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL,
+    0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL,
+    0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL,
+    0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL,
+    0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL,
+    0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL,
+    0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL,
+    0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL,
+    0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL,
+    0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL,
+    0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL,
+    0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL,
+    0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL,
+    0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL,
+    0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL,
+    0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL,
+    0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL,
+    0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL,
+    0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL,
+    0x9324fd72UL
+  },
+  {
+    0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL,
+    0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL,
+    0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL,
+    0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL,
+    0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL,
+    0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL,
+    0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL,
+    0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL,
+    0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL,
+    0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL,
+    0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL,
+    0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL,
+    0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL,
+    0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL,
+    0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL,
+    0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL,
+    0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL,
+    0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL,
+    0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL,
+    0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL,
+    0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL,
+    0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL,
+    0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL,
+    0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL,
+    0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL,
+    0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL,
+    0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL,
+    0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL,
+    0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL,
+    0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL,
+    0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL,
+    0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL,
+    0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL,
+    0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL,
+    0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL,
+    0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL,
+    0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL,
+    0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL,
+    0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL,
+    0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL,
+    0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL,
+    0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL,
+    0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL,
+    0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL,
+    0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL,
+    0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL,
+    0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL,
+    0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL,
+    0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL,
+    0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL,
+    0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL,
+    0xbe9834edUL
+  },
+  {
+    0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL,
+    0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL,
+    0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL,
+    0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL,
+    0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL,
+    0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL,
+    0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL,
+    0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL,
+    0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL,
+    0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL,
+    0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL,
+    0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL,
+    0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL,
+    0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL,
+    0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL,
+    0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL,
+    0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL,
+    0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL,
+    0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL,
+    0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL,
+    0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL,
+    0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL,
+    0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL,
+    0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL,
+    0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL,
+    0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL,
+    0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL,
+    0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL,
+    0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL,
+    0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL,
+    0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL,
+    0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL,
+    0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL,
+    0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL,
+    0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL,
+    0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL,
+    0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL,
+    0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL,
+    0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL,
+    0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL,
+    0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL,
+    0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL,
+    0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL,
+    0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL,
+    0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL,
+    0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL,
+    0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL,
+    0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL,
+    0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL,
+    0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,
+    0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,
+    0xde0506f1UL
+  },
+  {
+    0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL,
+    0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL,
+    0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL,
+    0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL,
+    0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL,
+    0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL,
+    0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL,
+    0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL,
+    0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL,
+    0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL,
+    0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL,
+    0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL,
+    0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL,
+    0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL,
+    0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL,
+    0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL,
+    0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL,
+    0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL,
+    0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL,
+    0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL,
+    0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL,
+    0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL,
+    0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL,
+    0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL,
+    0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL,
+    0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL,
+    0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL,
+    0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL,
+    0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL,
+    0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL,
+    0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL,
+    0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL,
+    0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL,
+    0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL,
+    0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL,
+    0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL,
+    0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL,
+    0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL,
+    0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL,
+    0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL,
+    0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL,
+    0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL,
+    0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL,
+    0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL,
+    0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL,
+    0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL,
+    0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL,
+    0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL,
+    0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL,
+    0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL,
+    0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL,
+    0x8def022dUL
+  },
+  {
+    0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL,
+    0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL,
+    0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL,
+    0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL,
+    0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL,
+    0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL,
+    0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL,
+    0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL,
+    0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL,
+    0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL,
+    0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL,
+    0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL,
+    0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL,
+    0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL,
+    0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL,
+    0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL,
+    0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL,
+    0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL,
+    0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL,
+    0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL,
+    0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL,
+    0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL,
+    0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL,
+    0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL,
+    0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL,
+    0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL,
+    0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL,
+    0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL,
+    0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL,
+    0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL,
+    0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL,
+    0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL,
+    0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL,
+    0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL,
+    0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL,
+    0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL,
+    0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL,
+    0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL,
+    0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL,
+    0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL,
+    0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL,
+    0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL,
+    0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL,
+    0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL,
+    0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL,
+    0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL,
+    0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL,
+    0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL,
+    0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL,
+    0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL,
+    0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL,
+    0x72fd2493UL
+  },
+  {
+    0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL,
+    0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL,
+    0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL,
+    0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL,
+    0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL,
+    0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL,
+    0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL,
+    0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL,
+    0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL,
+    0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL,
+    0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL,
+    0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL,
+    0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL,
+    0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL,
+    0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL,
+    0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL,
+    0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL,
+    0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL,
+    0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL,
+    0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL,
+    0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL,
+    0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL,
+    0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL,
+    0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL,
+    0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL,
+    0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL,
+    0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL,
+    0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL,
+    0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL,
+    0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL,
+    0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL,
+    0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL,
+    0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL,
+    0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL,
+    0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL,
+    0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL,
+    0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL,
+    0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL,
+    0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL,
+    0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL,
+    0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL,
+    0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL,
+    0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL,
+    0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL,
+    0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL,
+    0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL,
+    0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL,
+    0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL,
+    0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL,
+    0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL,
+    0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL,
+    0xed3498beUL
+  },
+  {
+    0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL,
+    0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL,
+    0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL,
+    0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL,
+    0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL,
+    0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL,
+    0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL,
+    0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL,
+    0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL,
+    0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL,
+    0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL,
+    0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL,
+    0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL,
+    0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL,
+    0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL,
+    0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL,
+    0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL,
+    0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL,
+    0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL,
+    0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL,
+    0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL,
+    0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL,
+    0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL,
+    0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL,
+    0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL,
+    0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL,
+    0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL,
+    0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL,
+    0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL,
+    0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL,
+    0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL,
+    0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL,
+    0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL,
+    0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL,
+    0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL,
+    0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL,
+    0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL,
+    0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL,
+    0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL,
+    0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL,
+    0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL,
+    0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL,
+    0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL,
+    0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL,
+    0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL,
+    0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL,
+    0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL,
+    0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL,
+    0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL,
+    0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL,
+    0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL,
+    0xf10605deUL
+#endif
+  }
+};
diff --git a/src/unison/physfs-1.1.1/zlib123/deflate.c b/src/unison/physfs-1.1.1/zlib123/deflate.c
new file mode 100644 (file)
index 0000000..29ce1f6
--- /dev/null
@@ -0,0 +1,1736 @@
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process depends on being able to identify portions
+ *      of the input text which are identical to earlier input (within a
+ *      sliding window trailing behind the input currently being processed).
+ *
+ *      The most straightforward technique turns out to be the fastest for
+ *      most input files: try all possible matches and select the longest.
+ *      The key feature of this algorithm is that insertions into the string
+ *      dictionary are very simple and thus fast, and deletions are avoided
+ *      completely. Insertions are performed at each input character, whereas
+ *      string matches are performed only when the previous match ends. So it
+ *      is preferable to spend more time in matches to allow very fast string
+ *      insertions and avoid deletions. The matching algorithm for small
+ *      strings is inspired from that of Rabin & Karp. A brute force approach
+ *      is used to find longer strings when a small match has been found.
+ *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ *      (by Leonid Broukhis).
+ *         A previous version of this file used a more sophisticated algorithm
+ *      (by Fiala and Greene) which is guaranteed to run in linear amortized
+ *      time, but has a larger average cost, uses more memory and is patented.
+ *      However the F&G algorithm may be faster for some highly redundant
+ *      files if the parameter max_chain_length (described below) is too large.
+ *
+ *  ACKNOWLEDGEMENTS
+ *
+ *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ *      I found it in 'freeze' written by Leonid Broukhis.
+ *      Thanks to many people for bug reports and testing.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ *      Available in http://www.ietf.org/rfc/rfc1951.txt
+ *
+ *      A description of the Rabin and Karp algorithm is given in the book
+ *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ *      Fiala,E.R., and Greene,D.H.
+ *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+/* @(#) $Id$ */
+
+#include "deflate.h"
+
+const char deflate_copyright[] =
+   " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly ";
+/*
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+ */
+
+/* ===========================================================================
+ *  Function prototypes.
+ */
+typedef enum {
+    need_more,      /* block not completed, need more input or more output */
+    block_done,     /* block flush performed */
+    finish_started, /* finish started, need only more output at next deflate */
+    finish_done     /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window    OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast   OF((deflate_state *s, int flush));
+#ifndef FASTEST
+local block_state deflate_slow   OF((deflate_state *s, int flush));
+#endif
+local void lm_init        OF((deflate_state *s));
+local void putShortMSB    OF((deflate_state *s, uInt b));
+local void flush_pending  OF((z_streamp strm));
+local int read_buf        OF((z_streamp strm, Bytef *buf, unsigned size));
+#ifndef FASTEST
+#ifdef ASMV
+      void match_init OF((void)); /* asm code initialization */
+      uInt longest_match  OF((deflate_state *s, IPos cur_match));
+#else
+local uInt longest_match  OF((deflate_state *s, IPos cur_match));
+#endif
+#endif
+local uInt longest_match_fast OF((deflate_state *s, IPos cur_match));
+
+#ifdef DEBUG
+local  void check_match OF((deflate_state *s, IPos start, IPos match,
+                            int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+#  define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+   ush good_length; /* reduce lazy search above this match length */
+   ush max_lazy;    /* do not perform lazy search above this match length */
+   ush nice_length; /* quit search above this match length */
+   ush max_chain;
+   compress_func func;
+} config;
+
+#ifdef FASTEST
+local const config configuration_table[2] = {
+/*      good lazy nice chain */
+/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
+/* 1 */ {4,    4,  8,    4, deflate_fast}}; /* max speed, no lazy matches */
+#else
+local const config configuration_table[10] = {
+/*      good lazy nice chain */
+/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
+/* 1 */ {4,    4,  8,    4, deflate_fast}, /* max speed, no lazy matches */
+/* 2 */ {4,    5, 16,    8, deflate_fast},
+/* 3 */ {4,    6, 32,   32, deflate_fast},
+
+/* 4 */ {4,    4, 16,   16, deflate_slow},  /* lazy matches */
+/* 5 */ {8,   16, 32,   32, deflate_slow},
+/* 6 */ {8,   16, 128, 128, deflate_slow},
+/* 7 */ {8,   32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */
+#endif
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+#ifndef NO_DUMMY_DECL
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+#endif
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN  assertion: all calls to to UPDATE_HASH are made with consecutive
+ *    input characters, so that a running hash key can be computed from the
+ *    previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * If this file is compiled with -DFASTEST, the compression level is forced
+ * to 1, and no hash chains are maintained.
+ * IN  assertion: all calls to to INSERT_STRING are made with consecutive
+ *    input characters and the first MIN_MATCH bytes of str are valid
+ *    (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#ifdef FASTEST
+#define INSERT_STRING(s, str, match_head) \
+   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+    match_head = s->head[s->ins_h], \
+    s->head[s->ins_h] = (Pos)(str))
+#else
+#define INSERT_STRING(s, str, match_head) \
+   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+    match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \
+    s->head[s->ins_h] = (Pos)(str))
+#endif
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+    s->head[s->hash_size-1] = NIL; \
+    zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int ZEXPORT deflateInit_(strm, level, version, stream_size)
+    z_streamp strm;
+    int level;
+    const char *version;
+    int stream_size;
+{
+    return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+                         Z_DEFAULT_STRATEGY, version, stream_size);
+    /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+                  version, stream_size)
+    z_streamp strm;
+    int  level;
+    int  method;
+    int  windowBits;
+    int  memLevel;
+    int  strategy;
+    const char *version;
+    int stream_size;
+{
+    deflate_state *s;
+    int wrap = 1;
+    static const char my_version[] = ZLIB_VERSION;
+
+    ushf *overlay;
+    /* We overlay pending_buf and d_buf+l_buf. This works since the average
+     * output size for (length,distance) codes is <= 24 bits.
+     */
+
+    if (version == Z_NULL || version[0] != my_version[0] ||
+        stream_size != sizeof(z_stream)) {
+        return Z_VERSION_ERROR;
+    }
+    if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+    strm->msg = Z_NULL;
+    if (strm->zalloc == (alloc_func)0) {
+        strm->zalloc = zcalloc;
+        strm->opaque = (voidpf)0;
+    }
+    if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+
+#ifdef FASTEST
+    if (level != 0) level = 1;
+#else
+    if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+
+    if (windowBits < 0) { /* suppress zlib wrapper */
+        wrap = 0;
+        windowBits = -windowBits;
+    }
+#ifdef GZIP
+    else if (windowBits > 15) {
+        wrap = 2;       /* write gzip wrapper instead */
+        windowBits -= 16;
+    }
+#endif
+    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+        windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+        strategy < 0 || strategy > Z_FIXED) {
+        return Z_STREAM_ERROR;
+    }
+    if (windowBits == 8) windowBits = 9;  /* until 256-byte window bug fixed */
+    s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+    if (s == Z_NULL) return Z_MEM_ERROR;
+    strm->state = (struct internal_state FAR *)s;
+    s->strm = strm;
+
+    s->wrap = wrap;
+    s->gzhead = Z_NULL;
+    s->w_bits = windowBits;
+    s->w_size = 1 << s->w_bits;
+    s->w_mask = s->w_size - 1;
+
+    s->hash_bits = memLevel + 7;
+    s->hash_size = 1 << s->hash_bits;
+    s->hash_mask = s->hash_size - 1;
+    s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+    s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+    s->prev   = (Posf *)  ZALLOC(strm, s->w_size, sizeof(Pos));
+    s->head   = (Posf *)  ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+    s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+    overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+    s->pending_buf = (uchf *) overlay;
+    s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+    if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+        s->pending_buf == Z_NULL) {
+        s->status = FINISH_STATE;
+        strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);
+        deflateEnd (strm);
+        return Z_MEM_ERROR;
+    }
+    s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+    s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+    s->level = level;
+    s->strategy = strategy;
+    s->method = (Byte)method;
+
+    return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
+    z_streamp strm;
+    const Bytef *dictionary;
+    uInt  dictLength;
+{
+    deflate_state *s;
+    uInt length = dictLength;
+    uInt n;
+    IPos hash_head = 0;
+
+    if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL ||
+        strm->state->wrap == 2 ||
+        (strm->state->wrap == 1 && strm->state->status != INIT_STATE))
+        return Z_STREAM_ERROR;
+
+    s = strm->state;
+    if (s->wrap)
+        strm->adler = adler32(strm->adler, dictionary, dictLength);
+
+    if (length < MIN_MATCH) return Z_OK;
+    if (length > MAX_DIST(s)) {
+        length = MAX_DIST(s);
+        dictionary += dictLength - length; /* use the tail of the dictionary */
+    }
+    zmemcpy(s->window, dictionary, length);
+    s->strstart = length;
+    s->block_start = (long)length;
+
+    /* Insert all strings in the hash table (except for the last two bytes).
+     * s->lookahead stays null, so s->ins_h will be recomputed at the next
+     * call of fill_window.
+     */
+    s->ins_h = s->window[0];
+    UPDATE_HASH(s, s->ins_h, s->window[1]);
+    for (n = 0; n <= length - MIN_MATCH; n++) {
+        INSERT_STRING(s, n, hash_head);
+    }
+    if (hash_head) hash_head = 0;  /* to make compiler happy */
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateReset (strm)
+    z_streamp strm;
+{
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL ||
+        strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) {
+        return Z_STREAM_ERROR;
+    }
+
+    strm->total_in = strm->total_out = 0;
+    strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+    strm->data_type = Z_UNKNOWN;
+
+    s = (deflate_state *)strm->state;
+    s->pending = 0;
+    s->pending_out = s->pending_buf;
+
+    if (s->wrap < 0) {
+        s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */
+    }
+    s->status = s->wrap ? INIT_STATE : BUSY_STATE;
+    strm->adler =
+#ifdef GZIP
+        s->wrap == 2 ? crc32(0L, Z_NULL, 0) :
+#endif
+        adler32(0L, Z_NULL, 0);
+    s->last_flush = Z_NO_FLUSH;
+
+    _tr_init(s);
+    lm_init(s);
+
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetHeader (strm, head)
+    z_streamp strm;
+    gz_headerp head;
+{
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    if (strm->state->wrap != 2) return Z_STREAM_ERROR;
+    strm->state->gzhead = head;
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflatePrime (strm, bits, value)
+    z_streamp strm;
+    int bits;
+    int value;
+{
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    strm->state->bi_valid = bits;
+    strm->state->bi_buf = (ush)(value & ((1 << bits) - 1));
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateParams(strm, level, strategy)
+    z_streamp strm;
+    int level;
+    int strategy;
+{
+    deflate_state *s;
+    compress_func func;
+    int err = Z_OK;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = strm->state;
+
+#ifdef FASTEST
+    if (level != 0) level = 1;
+#else
+    if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+    if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) {
+        return Z_STREAM_ERROR;
+    }
+    func = configuration_table[s->level].func;
+
+    if (func != configuration_table[level].func && strm->total_in != 0) {
+        /* Flush the last buffer: */
+        err = deflate(strm, Z_PARTIAL_FLUSH);
+    }
+    if (s->level != level) {
+        s->level = level;
+        s->max_lazy_match   = configuration_table[level].max_lazy;
+        s->good_match       = configuration_table[level].good_length;
+        s->nice_match       = configuration_table[level].nice_length;
+        s->max_chain_length = configuration_table[level].max_chain;
+    }
+    s->strategy = strategy;
+    return err;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain)
+    z_streamp strm;
+    int good_length;
+    int max_lazy;
+    int nice_length;
+    int max_chain;
+{
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = strm->state;
+    s->good_match = good_length;
+    s->max_lazy_match = max_lazy;
+    s->nice_match = nice_length;
+    s->max_chain_length = max_chain;
+    return Z_OK;
+}
+
+/* =========================================================================
+ * For the default windowBits of 15 and memLevel of 8, this function returns
+ * a close to exact, as well as small, upper bound on the compressed size.
+ * They are coded as constants here for a reason--if the #define's are
+ * changed, then this function needs to be changed as well.  The return
+ * value for 15 and 8 only works for those exact settings.
+ *
+ * For any setting other than those defaults for windowBits and memLevel,
+ * the value returned is a conservative worst case for the maximum expansion
+ * resulting from using fixed blocks instead of stored blocks, which deflate
+ * can emit on compressed data for some combinations of the parameters.
+ *
+ * This function could be more sophisticated to provide closer upper bounds
+ * for every combination of windowBits and memLevel, as well as wrap.
+ * But even the conservative upper bound of about 14% expansion does not
+ * seem onerous for output buffer allocation.
+ */
+uLong ZEXPORT deflateBound(strm, sourceLen)
+    z_streamp strm;
+    uLong sourceLen;
+{
+    deflate_state *s;
+    uLong destLen;
+
+    /* conservative upper bound */
+    destLen = sourceLen +
+              ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11;
+
+    /* if can't get parameters, return conservative bound */
+    if (strm == Z_NULL || strm->state == Z_NULL)
+        return destLen;
+
+    /* if not default parameters, return conservative bound */
+    s = strm->state;
+    if (s->w_bits != 15 || s->hash_bits != 8 + 7)
+        return destLen;
+
+    /* default settings: return tight bound for that case */
+    return compressBound(sourceLen);
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+    deflate_state *s;
+    uInt b;
+{
+    put_byte(s, (Byte)(b >> 8));
+    put_byte(s, (Byte)(b & 0xff));
+}
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+    z_streamp strm;
+{
+    unsigned len = strm->state->pending;
+
+    if (len > strm->avail_out) len = strm->avail_out;
+    if (len == 0) return;
+
+    zmemcpy(strm->next_out, strm->state->pending_out, len);
+    strm->next_out  += len;
+    strm->state->pending_out  += len;
+    strm->total_out += len;
+    strm->avail_out  -= len;
+    strm->state->pending -= len;
+    if (strm->state->pending == 0) {
+        strm->state->pending_out = strm->state->pending_buf;
+    }
+}
+
+/* ========================================================================= */
+int ZEXPORT deflate (strm, flush)
+    z_streamp strm;
+    int flush;
+{
+    int old_flush; /* value of flush param for previous deflate call */
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL ||
+        flush > Z_FINISH || flush < 0) {
+        return Z_STREAM_ERROR;
+    }
+    s = strm->state;
+
+    if (strm->next_out == Z_NULL ||
+        (strm->next_in == Z_NULL && strm->avail_in != 0) ||
+        (s->status == FINISH_STATE && flush != Z_FINISH)) {
+        ERR_RETURN(strm, Z_STREAM_ERROR);
+    }
+    if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+    s->strm = strm; /* just in case */
+    old_flush = s->last_flush;
+    s->last_flush = flush;
+
+    /* Write the header */
+    if (s->status == INIT_STATE) {
+#ifdef GZIP
+        if (s->wrap == 2) {
+            strm->adler = crc32(0L, Z_NULL, 0);
+            put_byte(s, 31);
+            put_byte(s, 139);
+            put_byte(s, 8);
+            if (s->gzhead == NULL) {
+                put_byte(s, 0);
+                put_byte(s, 0);
+                put_byte(s, 0);
+                put_byte(s, 0);
+                put_byte(s, 0);
+                put_byte(s, s->level == 9 ? 2 :
+                            (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+                             4 : 0));
+                put_byte(s, OS_CODE);
+                s->status = BUSY_STATE;
+            }
+            else {
+                put_byte(s, (s->gzhead->text ? 1 : 0) +
+                            (s->gzhead->hcrc ? 2 : 0) +
+                            (s->gzhead->extra == Z_NULL ? 0 : 4) +
+                            (s->gzhead->name == Z_NULL ? 0 : 8) +
+                            (s->gzhead->comment == Z_NULL ? 0 : 16)
+                        );
+                put_byte(s, (Byte)(s->gzhead->time & 0xff));
+                put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff));
+                put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff));
+                put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff));
+                put_byte(s, s->level == 9 ? 2 :
+                            (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+                             4 : 0));
+                put_byte(s, s->gzhead->os & 0xff);
+                if (s->gzhead->extra != NULL) {
+                    put_byte(s, s->gzhead->extra_len & 0xff);
+                    put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);
+                }
+                if (s->gzhead->hcrc)
+                    strm->adler = crc32(strm->adler, s->pending_buf,
+                                        s->pending);
+                s->gzindex = 0;
+                s->status = EXTRA_STATE;
+            }
+        }
+        else
+#endif
+        {
+            uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+            uInt level_flags;
+
+            if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)
+                level_flags = 0;
+            else if (s->level < 6)
+                level_flags = 1;
+            else if (s->level == 6)
+                level_flags = 2;
+            else
+                level_flags = 3;
+            header |= (level_flags << 6);
+            if (s->strstart != 0) header |= PRESET_DICT;
+            header += 31 - (header % 31);
+
+            s->status = BUSY_STATE;
+            putShortMSB(s, header);
+
+            /* Save the adler32 of the preset dictionary: */
+            if (s->strstart != 0) {
+                putShortMSB(s, (uInt)(strm->adler >> 16));
+                putShortMSB(s, (uInt)(strm->adler & 0xffff));
+            }
+            strm->adler = adler32(0L, Z_NULL, 0);
+        }
+    }
+#ifdef GZIP
+    if (s->status == EXTRA_STATE) {
+        if (s->gzhead->extra != NULL) {
+            uInt beg = s->pending;  /* start of bytes to update crc */
+
+            while (s->gzindex < (s->gzhead->extra_len & 0xffff)) {
+                if (s->pending == s->pending_buf_size) {
+                    if (s->gzhead->hcrc && s->pending > beg)
+                        strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                            s->pending - beg);
+                    flush_pending(strm);
+                    beg = s->pending;
+                    if (s->pending == s->pending_buf_size)
+                        break;
+                }
+                put_byte(s, s->gzhead->extra[s->gzindex]);
+                s->gzindex++;
+            }
+            if (s->gzhead->hcrc && s->pending > beg)
+                strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                    s->pending - beg);
+            if (s->gzindex == s->gzhead->extra_len) {
+                s->gzindex = 0;
+                s->status = NAME_STATE;
+            }
+        }
+        else
+            s->status = NAME_STATE;
+    }
+    if (s->status == NAME_STATE) {
+        if (s->gzhead->name != NULL) {
+            uInt beg = s->pending;  /* start of bytes to update crc */
+            int val;
+
+            do {
+                if (s->pending == s->pending_buf_size) {
+                    if (s->gzhead->hcrc && s->pending > beg)
+                        strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                            s->pending - beg);
+                    flush_pending(strm);
+                    beg = s->pending;
+                    if (s->pending == s->pending_buf_size) {
+                        val = 1;
+                        break;
+                    }
+                }
+                val = s->gzhead->name[s->gzindex++];
+                put_byte(s, val);
+            } while (val != 0);
+            if (s->gzhead->hcrc && s->pending > beg)
+                strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                    s->pending - beg);
+            if (val == 0) {
+                s->gzindex = 0;
+                s->status = COMMENT_STATE;
+            }
+        }
+        else
+            s->status = COMMENT_STATE;
+    }
+    if (s->status == COMMENT_STATE) {
+        if (s->gzhead->comment != NULL) {
+            uInt beg = s->pending;  /* start of bytes to update crc */
+            int val;
+
+            do {
+                if (s->pending == s->pending_buf_size) {
+                    if (s->gzhead->hcrc && s->pending > beg)
+                        strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                            s->pending - beg);
+                    flush_pending(strm);
+                    beg = s->pending;
+                    if (s->pending == s->pending_buf_size) {
+                        val = 1;
+                        break;
+                    }
+                }
+                val = s->gzhead->comment[s->gzindex++];
+                put_byte(s, val);
+            } while (val != 0);
+            if (s->gzhead->hcrc && s->pending > beg)
+                strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                    s->pending - beg);
+            if (val == 0)
+                s->status = HCRC_STATE;
+        }
+        else
+            s->status = HCRC_STATE;
+    }
+    if (s->status == HCRC_STATE) {
+        if (s->gzhead->hcrc) {
+            if (s->pending + 2 > s->pending_buf_size)
+                flush_pending(strm);
+            if (s->pending + 2 <= s->pending_buf_size) {
+                put_byte(s, (Byte)(strm->adler & 0xff));
+                put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+                strm->adler = crc32(0L, Z_NULL, 0);
+                s->status = BUSY_STATE;
+            }
+        }
+        else
+            s->status = BUSY_STATE;
+    }
+#endif
+
+    /* Flush as much pending output as possible */
+    if (s->pending != 0) {
+        flush_pending(strm);
+        if (strm->avail_out == 0) {
+            /* Since avail_out is 0, deflate will be called again with
+             * more output space, but possibly with both pending and
+             * avail_in equal to zero. There won't be anything to do,
+             * but this is not an error situation so make sure we
+             * return OK instead of BUF_ERROR at next call of deflate:
+             */
+            s->last_flush = -1;
+            return Z_OK;
+        }
+
+    /* Make sure there is something to do and avoid duplicate consecutive
+     * flushes. For repeated and useless calls with Z_FINISH, we keep
+     * returning Z_STREAM_END instead of Z_BUF_ERROR.
+     */
+    } else if (strm->avail_in == 0 && flush <= old_flush &&
+               flush != Z_FINISH) {
+        ERR_RETURN(strm, Z_BUF_ERROR);
+    }
+
+    /* User must not provide more input after the first FINISH: */
+    if (s->status == FINISH_STATE && strm->avail_in != 0) {
+        ERR_RETURN(strm, Z_BUF_ERROR);
+    }
+
+    /* Start a new block or continue the current one.
+     */
+    if (strm->avail_in != 0 || s->lookahead != 0 ||
+        (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+        block_state bstate;
+
+        bstate = (*(configuration_table[s->level].func))(s, flush);
+
+        if (bstate == finish_started || bstate == finish_done) {
+            s->status = FINISH_STATE;
+        }
+        if (bstate == need_more || bstate == finish_started) {
+            if (strm->avail_out == 0) {
+                s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+            }
+            return Z_OK;
+            /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+             * of deflate should use the same flush parameter to make sure
+             * that the flush is complete. So we don't have to output an
+             * empty block here, this will be done at next call. This also
+             * ensures that for a very small output buffer, we emit at most
+             * one empty block.
+             */
+        }
+        if (bstate == block_done) {
+            if (flush == Z_PARTIAL_FLUSH) {
+                _tr_align(s);
+            } else { /* FULL_FLUSH or SYNC_FLUSH */
+                _tr_stored_block(s, (char*)0, 0L, 0);
+                /* For a full flush, this empty block will be recognized
+                 * as a special marker by inflate_sync().
+                 */
+                if (flush == Z_FULL_FLUSH) {
+                    CLEAR_HASH(s);             /* forget history */
+                }
+            }
+            flush_pending(strm);
+            if (strm->avail_out == 0) {
+              s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+              return Z_OK;
+            }
+        }
+    }
+    Assert(strm->avail_out > 0, "bug2");
+
+    if (flush != Z_FINISH) return Z_OK;
+    if (s->wrap <= 0) return Z_STREAM_END;
+
+    /* Write the trailer */
+#ifdef GZIP
+    if (s->wrap == 2) {
+        put_byte(s, (Byte)(strm->adler & 0xff));
+        put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+        put_byte(s, (Byte)((strm->adler >> 16) & 0xff));
+        put_byte(s, (Byte)((strm->adler >> 24) & 0xff));
+        put_byte(s, (Byte)(strm->total_in & 0xff));
+        put_byte(s, (Byte)((strm->total_in >> 8) & 0xff));
+        put_byte(s, (Byte)((strm->total_in >> 16) & 0xff));
+        put_byte(s, (Byte)((strm->total_in >> 24) & 0xff));
+    }
+    else
+#endif
+    {
+        putShortMSB(s, (uInt)(strm->adler >> 16));
+        putShortMSB(s, (uInt)(strm->adler & 0xffff));
+    }
+    flush_pending(strm);
+    /* If avail_out is zero, the application will call deflate again
+     * to flush the rest.
+     */
+    if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */
+    return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateEnd (strm)
+    z_streamp strm;
+{
+    int status;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+
+    status = strm->state->status;
+    if (status != INIT_STATE &&
+        status != EXTRA_STATE &&
+        status != NAME_STATE &&
+        status != COMMENT_STATE &&
+        status != HCRC_STATE &&
+        status != BUSY_STATE &&
+        status != FINISH_STATE) {
+      return Z_STREAM_ERROR;
+    }
+
+    /* Deallocate in reverse order of allocations: */
+    TRY_FREE(strm, strm->state->pending_buf);
+    TRY_FREE(strm, strm->state->head);
+    TRY_FREE(strm, strm->state->prev);
+    TRY_FREE(strm, strm->state->window);
+
+    ZFREE(strm, strm->state);
+    strm->state = Z_NULL;
+
+    return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ * To simplify the source, this is not supported for 16-bit MSDOS (which
+ * doesn't have enough memory anyway to duplicate compression states).
+ */
+int ZEXPORT deflateCopy (dest, source)
+    z_streamp dest;
+    z_streamp source;
+{
+#ifdef MAXSEG_64K
+    return Z_STREAM_ERROR;
+#else
+    deflate_state *ds;
+    deflate_state *ss;
+    ushf *overlay;
+
+
+    if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
+        return Z_STREAM_ERROR;
+    }
+
+    ss = source->state;
+
+    zmemcpy(dest, source, sizeof(z_stream));
+
+    ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+    if (ds == Z_NULL) return Z_MEM_ERROR;
+    dest->state = (struct internal_state FAR *) ds;
+    zmemcpy(ds, ss, sizeof(deflate_state));
+    ds->strm = dest;
+
+    ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
+    ds->prev   = (Posf *)  ZALLOC(dest, ds->w_size, sizeof(Pos));
+    ds->head   = (Posf *)  ZALLOC(dest, ds->hash_size, sizeof(Pos));
+    overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
+    ds->pending_buf = (uchf *) overlay;
+
+    if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
+        ds->pending_buf == Z_NULL) {
+        deflateEnd (dest);
+        return Z_MEM_ERROR;
+    }
+    /* following zmemcpy do not work for 16-bit MSDOS */
+    zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+    zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
+    zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
+    zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+    ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+    ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+    ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+    ds->l_desc.dyn_tree = ds->dyn_ltree;
+    ds->d_desc.dyn_tree = ds->dyn_dtree;
+    ds->bl_desc.dyn_tree = ds->bl_tree;
+
+    return Z_OK;
+#endif /* MAXSEG_64K */
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read.  All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+    z_streamp strm;
+    Bytef *buf;
+    unsigned size;
+{
+    unsigned len = strm->avail_in;
+
+    if (len > size) len = size;
+    if (len == 0) return 0;
+
+    strm->avail_in  -= len;
+
+    if (strm->state->wrap == 1) {
+        strm->adler = adler32(strm->adler, strm->next_in, len);
+    }
+#ifdef GZIP
+    else if (strm->state->wrap == 2) {
+        strm->adler = crc32(strm->adler, strm->next_in, len);
+    }
+#endif
+    zmemcpy(buf, strm->next_in, len);
+    strm->next_in  += len;
+    strm->total_in += len;
+
+    return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+    deflate_state *s;
+{
+    s->window_size = (ulg)2L*s->w_size;
+
+    CLEAR_HASH(s);
+
+    /* Set the default configuration parameters:
+     */
+    s->max_lazy_match   = configuration_table[s->level].max_lazy;
+    s->good_match       = configuration_table[s->level].good_length;
+    s->nice_match       = configuration_table[s->level].nice_length;
+    s->max_chain_length = configuration_table[s->level].max_chain;
+
+    s->strstart = 0;
+    s->block_start = 0L;
+    s->lookahead = 0;
+    s->match_length = s->prev_length = MIN_MATCH-1;
+    s->match_available = 0;
+    s->ins_h = 0;
+#ifndef FASTEST
+#ifdef ASMV
+    match_init(); /* initialize the asm code */
+#endif
+#endif
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local uInt longest_match(s, cur_match)
+    deflate_state *s;
+    IPos cur_match;                             /* current match */
+{
+    unsigned chain_length = s->max_chain_length;/* max hash chain length */
+    register Bytef *scan = s->window + s->strstart; /* current string */
+    register Bytef *match;                       /* matched string */
+    register int len;                           /* length of current match */
+    int best_len = s->prev_length;              /* best match length so far */
+    int nice_match = s->nice_match;             /* stop if match long enough */
+    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+        s->strstart - (IPos)MAX_DIST(s) : NIL;
+    /* Stop when cur_match becomes <= limit. To simplify the code,
+     * we prevent matches with the string of window index 0.
+     */
+    Posf *prev = s->prev;
+    uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+    /* Compare two bytes at a time. Note: this is not always beneficial.
+     * Try with and without -DUNALIGNED_OK to check.
+     */
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+    register ush scan_start = *(ushf*)scan;
+    register ush scan_end   = *(ushf*)(scan+best_len-1);
+#else
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+    register Byte scan_end1  = scan[best_len-1];
+    register Byte scan_end   = scan[best_len];
+#endif
+
+    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+     * It is easy to get rid of this optimization if necessary.
+     */
+    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+    /* Do not waste too much time if we already have a good match: */
+    if (s->prev_length >= s->good_match) {
+        chain_length >>= 2;
+    }
+    /* Do not look for matches beyond the end of the input. This is necessary
+     * to make deflate deterministic.
+     */
+    if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+    do {
+        Assert(cur_match < s->strstart, "no future");
+        match = s->window + cur_match;
+
+        /* Skip to next match if the match length cannot increase
+         * or if the match length is less than 2.  Note that the checks below
+         * for insufficient lookahead only occur occasionally for performance
+         * reasons.  Therefore uninitialized memory will be accessed, and
+         * conditional jumps will be made that depend on those values.
+         * However the length of the match is limited to the lookahead, so
+         * the output of deflate is not affected by the uninitialized values.
+         */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+        /* This code assumes sizeof(unsigned short) == 2. Do not use
+         * UNALIGNED_OK if your compiler uses a different size.
+         */
+        if (*(ushf*)(match+best_len-1) != scan_end ||
+            *(ushf*)match != scan_start) continue;
+
+        /* It is not necessary to compare scan[2] and match[2] since they are
+         * always equal when the other bytes match, given that the hash keys
+         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+         * strstart+3, +5, ... up to strstart+257. We check for insufficient
+         * lookahead only every 4th comparison; the 128th check will be made
+         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+         * necessary to put more guard bytes at the end of the window, or
+         * to check more often for insufficient lookahead.
+         */
+        Assert(scan[2] == match[2], "scan[2]?");
+        scan++, match++;
+        do {
+        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 scan < strend);
+        /* The funny "do {}" generates better code on most compilers */
+
+        /* Here, scan <= window+strstart+257 */
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+        if (*scan == *match) scan++;
+
+        len = (MAX_MATCH - 1) - (int)(strend-scan);
+        scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+        if (match[best_len]   != scan_end  ||
+            match[best_len-1] != scan_end1 ||
+            *match            != *scan     ||
+            *++match          != scan[1])      continue;
+
+        /* The check at best_len-1 can be removed because it will be made
+         * again later. (This heuristic is not always a win.)
+         * It is not necessary to compare scan[2] and match[2] since they
+         * are always equal when the other bytes match, given that
+         * the hash keys are equal and that HASH_BITS >= 8.
+         */
+        scan += 2, match++;
+        Assert(*scan == *match, "match[2]?");
+
+        /* We check for insufficient lookahead only every 8th comparison;
+         * the 256th check will be made at strstart+258.
+         */
+        do {
+        } while (*++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 scan < strend);
+
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+        len = MAX_MATCH - (int)(strend - scan);
+        scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+        if (len > best_len) {
+            s->match_start = cur_match;
+            best_len = len;
+            if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+            scan_end = *(ushf*)(scan+best_len-1);
+#else
+            scan_end1  = scan[best_len-1];
+            scan_end   = scan[best_len];
+#endif
+        }
+    } while ((cur_match = prev[cur_match & wmask]) > limit
+             && --chain_length != 0);
+
+    if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+    return s->lookahead;
+}
+#endif /* ASMV */
+#endif /* FASTEST */
+
+/* ---------------------------------------------------------------------------
+ * Optimized version for level == 1 or strategy == Z_RLE only
+ */
+local uInt longest_match_fast(s, cur_match)
+    deflate_state *s;
+    IPos cur_match;                             /* current match */
+{
+    register Bytef *scan = s->window + s->strstart; /* current string */
+    register Bytef *match;                       /* matched string */
+    register int len;                           /* length of current match */
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+
+    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+     * It is easy to get rid of this optimization if necessary.
+     */
+    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+    Assert(cur_match < s->strstart, "no future");
+
+    match = s->window + cur_match;
+
+    /* Return failure if the match length is less than 2:
+     */
+    if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
+
+    /* The check at best_len-1 can be removed because it will be made
+     * again later. (This heuristic is not always a win.)
+     * It is not necessary to compare scan[2] and match[2] since they
+     * are always equal when the other bytes match, given that
+     * the hash keys are equal and that HASH_BITS >= 8.
+     */
+    scan += 2, match += 2;
+    Assert(*scan == *match, "match[2]?");
+
+    /* We check for insufficient lookahead only every 8th comparison;
+     * the 256th check will be made at strstart+258.
+     */
+    do {
+    } while (*++scan == *++match && *++scan == *++match &&
+             *++scan == *++match && *++scan == *++match &&
+             *++scan == *++match && *++scan == *++match &&
+             *++scan == *++match && *++scan == *++match &&
+             scan < strend);
+
+    Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+    len = MAX_MATCH - (int)(strend - scan);
+
+    if (len < MIN_MATCH) return MIN_MATCH - 1;
+
+    s->match_start = cur_match;
+    return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead;
+}
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+    deflate_state *s;
+    IPos start, match;
+    int length;
+{
+    /* check that the match is indeed a match */
+    if (zmemcmp(s->window + match,
+                s->window + start, length) != EQUAL) {
+        fprintf(stderr, " start %u, match %u, length %d\n",
+                start, match, length);
+        do {
+            fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+        } while (--length != 0);
+        z_error("invalid match");
+    }
+    if (z_verbose > 1) {
+        fprintf(stderr,"\\[%d,%d]", start-match, length);
+        do { putc(s->window[start++], stderr); } while (--length != 0);
+    }
+}
+#else
+#  define check_match(s, start, match, length)
+#endif /* DEBUG */
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ *    At least one byte has been read, or avail_in == 0; reads are
+ *    performed for at least two bytes (required for the zip translate_eol
+ *    option -- not supported here).
+ */
+local void fill_window(s)
+    deflate_state *s;
+{
+    register unsigned n, m;
+    register Posf *p;
+    unsigned more;    /* Amount of free space at the end of the window. */
+    uInt wsize = s->w_size;
+
+    do {
+        more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+        /* Deal with !@#$% 64K limit: */
+        if (sizeof(int) <= 2) {
+            if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+                more = wsize;
+
+            } else if (more == (unsigned)(-1)) {
+                /* Very unlikely, but possible on 16 bit machine if
+                 * strstart == 0 && lookahead == 1 (input done a byte at time)
+                 */
+                more--;
+            }
+        }
+
+        /* If the window is almost full and there is insufficient lookahead,
+         * move the upper half to the lower one to make room in the upper half.
+         */
+        if (s->strstart >= wsize+MAX_DIST(s)) {
+
+            zmemcpy(s->window, s->window+wsize, (unsigned)wsize);
+            s->match_start -= wsize;
+            s->strstart    -= wsize; /* we now have strstart >= MAX_DIST */
+            s->block_start -= (long) wsize;
+
+            /* Slide the hash table (could be avoided with 32 bit values
+               at the expense of memory usage). We slide even when level == 0
+               to keep the hash table consistent if we switch back to level > 0
+               later. (Using level 0 permanently is not an optimal usage of
+               zlib, so we don't care about this pathological case.)
+             */
+            /* %%% avoid this when Z_RLE */
+            n = s->hash_size;
+            p = &s->head[n];
+            do {
+                m = *--p;
+                *p = (Pos)(m >= wsize ? m-wsize : NIL);
+            } while (--n);
+
+            n = wsize;
+#ifndef FASTEST
+            p = &s->prev[n];
+            do {
+                m = *--p;
+                *p = (Pos)(m >= wsize ? m-wsize : NIL);
+                /* If n is not on any hash chain, prev[n] is garbage but
+                 * its value will never be used.
+                 */
+            } while (--n);
+#endif
+            more += wsize;
+        }
+        if (s->strm->avail_in == 0) return;
+
+        /* If there was no sliding:
+         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+         *    more == window_size - lookahead - strstart
+         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+         * => more >= window_size - 2*WSIZE + 2
+         * In the BIG_MEM or MMAP case (not yet supported),
+         *   window_size == input_size + MIN_LOOKAHEAD  &&
+         *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+         * Otherwise, window_size == 2*WSIZE so more >= 2.
+         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+         */
+        Assert(more >= 2, "more < 2");
+
+        n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+        s->lookahead += n;
+
+        /* Initialize the hash value now that we have some input: */
+        if (s->lookahead >= MIN_MATCH) {
+            s->ins_h = s->window[s->strstart];
+            UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+            Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+        }
+        /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+         * but this is not important since only literal bytes will be emitted.
+         */
+
+    } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, eof) { \
+   _tr_flush_block(s, (s->block_start >= 0L ? \
+                   (charf *)&s->window[(unsigned)s->block_start] : \
+                   (charf *)Z_NULL), \
+                (ulg)((long)s->strstart - s->block_start), \
+                (eof)); \
+   s->block_start = s->strstart; \
+   flush_pending(s->strm); \
+   Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, eof) { \
+   FLUSH_BLOCK_ONLY(s, eof); \
+   if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+local block_state deflate_stored(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+     * to pending_buf_size, and each stored block has a 5 byte header:
+     */
+    ulg max_block_size = 0xffff;
+    ulg max_start;
+
+    if (max_block_size > s->pending_buf_size - 5) {
+        max_block_size = s->pending_buf_size - 5;
+    }
+
+    /* Copy as much as possible from input to output: */
+    for (;;) {
+        /* Fill the window as much as possible: */
+        if (s->lookahead <= 1) {
+
+            Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+                   s->block_start >= (long)s->w_size, "slide too late");
+
+            fill_window(s);
+            if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+        Assert(s->block_start >= 0L, "block gone");
+
+        s->strstart += s->lookahead;
+        s->lookahead = 0;
+
+        /* Emit a stored block if pending_buf will be full: */
+        max_start = s->block_start + max_block_size;
+        if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+            /* strstart == 0 is possible when wraparound on 16-bit machine */
+            s->lookahead = (uInt)(s->strstart - max_start);
+            s->strstart = (uInt)max_start;
+            FLUSH_BLOCK(s, 0);
+        }
+        /* Flush if we may have to slide, otherwise block_start may become
+         * negative and the data will be gone:
+         */
+        if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+            FLUSH_BLOCK(s, 0);
+        }
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    IPos hash_head = NIL; /* head of the hash chain */
+    int bflush;           /* set if current block must be flushed */
+
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (s->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+                return need_more;
+            }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        if (s->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         * At this point we have always match_length < MIN_MATCH
+         */
+        if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+#ifdef FASTEST
+            if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) ||
+                (s->strategy == Z_RLE && s->strstart - hash_head == 1)) {
+                s->match_length = longest_match_fast (s, hash_head);
+            }
+#else
+            if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) {
+                s->match_length = longest_match (s, hash_head);
+            } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) {
+                s->match_length = longest_match_fast (s, hash_head);
+            }
+#endif
+            /* longest_match() or longest_match_fast() sets match_start */
+        }
+        if (s->match_length >= MIN_MATCH) {
+            check_match(s, s->strstart, s->match_start, s->match_length);
+
+            _tr_tally_dist(s, s->strstart - s->match_start,
+                           s->match_length - MIN_MATCH, bflush);
+
+            s->lookahead -= s->match_length;
+
+            /* Insert new strings in the hash table only if the match length
+             * is not too large. This saves time but degrades compression.
+             */
+#ifndef FASTEST
+            if (s->match_length <= s->max_insert_length &&
+                s->lookahead >= MIN_MATCH) {
+                s->match_length--; /* string at strstart already in table */
+                do {
+                    s->strstart++;
+                    INSERT_STRING(s, s->strstart, hash_head);
+                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+                     * always MIN_MATCH bytes ahead.
+                     */
+                } while (--s->match_length != 0);
+                s->strstart++;
+            } else
+#endif
+            {
+                s->strstart += s->match_length;
+                s->match_length = 0;
+                s->ins_h = s->window[s->strstart];
+                UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+                Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+                /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+                 * matter since it will be recomputed at next deflate call.
+                 */
+            }
+        } else {
+            /* No match, output a literal byte */
+            Tracevv((stderr,"%c", s->window[s->strstart]));
+            _tr_tally_lit (s, s->window[s->strstart], bflush);
+            s->lookahead--;
+            s->strstart++;
+        }
+        if (bflush) FLUSH_BLOCK(s, 0);
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    IPos hash_head = NIL;    /* head of hash chain */
+    int bflush;              /* set if current block must be flushed */
+
+    /* Process the input block. */
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (s->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+                return need_more;
+            }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        if (s->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         */
+        s->prev_length = s->match_length, s->prev_match = s->match_start;
+        s->match_length = MIN_MATCH-1;
+
+        if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+            s->strstart - hash_head <= MAX_DIST(s)) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+            if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) {
+                s->match_length = longest_match (s, hash_head);
+            } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) {
+                s->match_length = longest_match_fast (s, hash_head);
+            }
+            /* longest_match() or longest_match_fast() sets match_start */
+
+            if (s->match_length <= 5 && (s->strategy == Z_FILTERED
+#if TOO_FAR <= 32767
+                || (s->match_length == MIN_MATCH &&
+                    s->strstart - s->match_start > TOO_FAR)
+#endif
+                )) {
+
+                /* If prev_match is also MIN_MATCH, match_start is garbage
+                 * but we will ignore the current match anyway.
+                 */
+                s->match_length = MIN_MATCH-1;
+            }
+        }
+        /* If there was a match at the previous step and the current
+         * match is not better, output the previous match:
+         */
+        if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+            uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+            /* Do not insert strings in hash table beyond this. */
+
+            check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+            _tr_tally_dist(s, s->strstart -1 - s->prev_match,
+                           s->prev_length - MIN_MATCH, bflush);
+
+            /* Insert in hash table all strings up to the end of the match.
+             * strstart-1 and strstart are already inserted. If there is not
+             * enough lookahead, the last two strings are not inserted in
+             * the hash table.
+             */
+            s->lookahead -= s->prev_length-1;
+            s->prev_length -= 2;
+            do {
+                if (++s->strstart <= max_insert) {
+                    INSERT_STRING(s, s->strstart, hash_head);
+                }
+            } while (--s->prev_length != 0);
+            s->match_available = 0;
+            s->match_length = MIN_MATCH-1;
+            s->strstart++;
+
+            if (bflush) FLUSH_BLOCK(s, 0);
+
+        } else if (s->match_available) {
+            /* If there was no match at the previous position, output a
+             * single literal. If there was a match but the current match
+             * is longer, truncate the previous match to a single literal.
+             */
+            Tracevv((stderr,"%c", s->window[s->strstart-1]));
+            _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+            if (bflush) {
+                FLUSH_BLOCK_ONLY(s, 0);
+            }
+            s->strstart++;
+            s->lookahead--;
+            if (s->strm->avail_out == 0) return need_more;
+        } else {
+            /* There is no previous match to compare with, wait for
+             * the next step to decide.
+             */
+            s->match_available = 1;
+            s->strstart++;
+            s->lookahead--;
+        }
+    }
+    Assert (flush != Z_NO_FLUSH, "no flush?");
+    if (s->match_available) {
+        Tracevv((stderr,"%c", s->window[s->strstart-1]));
+        _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+        s->match_available = 0;
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+#endif /* FASTEST */
+
+#if 0
+/* ===========================================================================
+ * For Z_RLE, simply look for runs of bytes, generate matches only of distance
+ * one.  Do not maintain a hash table.  (It will be regenerated if this run of
+ * deflate switches away from Z_RLE.)
+ */
+local block_state deflate_rle(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    int bflush;         /* set if current block must be flushed */
+    uInt run;           /* length of run */
+    uInt max;           /* maximum length of run */
+    uInt prev;          /* byte at distance one to match */
+    Bytef *scan;        /* scan for end of run */
+
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the longest encodable run.
+         */
+        if (s->lookahead < MAX_MATCH) {
+            fill_window(s);
+            if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) {
+                return need_more;
+            }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* See how many times the previous byte repeats */
+        run = 0;
+        if (s->strstart > 0) {      /* if there is a previous byte, that is */
+            max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH;
+            scan = s->window + s->strstart - 1;
+            prev = *scan++;
+            do {
+                if (*scan++ != prev)
+                    break;
+            } while (++run < max);
+        }
+
+        /* Emit match if have run of MIN_MATCH or longer, else emit literal */
+        if (run >= MIN_MATCH) {
+            check_match(s, s->strstart, s->strstart - 1, run);
+            _tr_tally_dist(s, 1, run - MIN_MATCH, bflush);
+            s->lookahead -= run;
+            s->strstart += run;
+        } else {
+            /* No match, output a literal byte */
+            Tracevv((stderr,"%c", s->window[s->strstart]));
+            _tr_tally_lit (s, s->window[s->strstart], bflush);
+            s->lookahead--;
+            s->strstart++;
+        }
+        if (bflush) FLUSH_BLOCK(s, 0);
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+#endif
diff --git a/src/unison/physfs-1.1.1/zlib123/deflate.h b/src/unison/physfs-1.1.1/zlib123/deflate.h
new file mode 100644 (file)
index 0000000..05a5ab3
--- /dev/null
@@ -0,0 +1,331 @@
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-2004 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef DEFLATE_H
+#define DEFLATE_H
+
+#include "zutil.h"
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+   trailer creation by deflate().  NO_GZIP would be used to avoid linking in
+   the crc code when it is not needed.  For shared libraries, gzip encoding
+   should be left enabled. */
+#ifndef NO_GZIP
+#  define GZIP
+#endif
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS  256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES   30
+/* number of distance codes */
+
+#define BL_CODES  19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define INIT_STATE    42
+#define EXTRA_STATE   69
+#define NAME_STATE    73
+#define COMMENT_STATE 91
+#define HCRC_STATE   103
+#define BUSY_STATE   113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+    union {
+        ush  freq;       /* frequency count */
+        ush  code;       /* bit string */
+    } fc;
+    union {
+        ush  dad;        /* father node in Huffman tree */
+        ush  len;        /* length of bit string */
+    } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad  dl.dad
+#define Len  dl.len
+
+typedef struct static_tree_desc_s  static_tree_desc;
+
+typedef struct tree_desc_s {
+    ct_data *dyn_tree;           /* the dynamic tree */
+    int     max_code;            /* largest code with non zero frequency */
+    static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct internal_state {
+    z_streamp strm;      /* pointer back to this zlib stream */
+    int   status;        /* as the name implies */
+    Bytef *pending_buf;  /* output still pending */
+    ulg   pending_buf_size; /* size of pending_buf */
+    Bytef *pending_out;  /* next pending byte to output to the stream */
+    uInt   pending;      /* nb of bytes in the pending buffer */
+    int   wrap;          /* bit 0 true for zlib, bit 1 true for gzip */
+    gz_headerp  gzhead;  /* gzip header information to write */
+    uInt   gzindex;      /* where in extra, name, or comment */
+    Byte  method;        /* STORED (for zip only) or DEFLATED */
+    int   last_flush;    /* value of flush param for previous deflate call */
+
+                /* used by deflate.c: */
+
+    uInt  w_size;        /* LZ77 window size (32K by default) */
+    uInt  w_bits;        /* log2(w_size)  (8..16) */
+    uInt  w_mask;        /* w_size - 1 */
+
+    Bytef *window;
+    /* Sliding window. Input bytes are read into the second half of the window,
+     * and move to the first half later to keep a dictionary of at least wSize
+     * bytes. With this organization, matches are limited to a distance of
+     * wSize-MAX_MATCH bytes, but this ensures that IO is always
+     * performed with a length multiple of the block size. Also, it limits
+     * the window size to 64K, which is quite useful on MSDOS.
+     * To do: use the user input buffer as sliding window.
+     */
+
+    ulg window_size;
+    /* Actual size of window: 2*wSize, except when the user input buffer
+     * is directly used as sliding window.
+     */
+
+    Posf *prev;
+    /* Link to older string with same hash index. To limit the size of this
+     * array to 64K, this link is maintained only for the last 32K strings.
+     * An index in this array is thus a window index modulo 32K.
+     */
+
+    Posf *head; /* Heads of the hash chains or NIL. */
+
+    uInt  ins_h;          /* hash index of string to be inserted */
+    uInt  hash_size;      /* number of elements in hash table */
+    uInt  hash_bits;      /* log2(hash_size) */
+    uInt  hash_mask;      /* hash_size-1 */
+
+    uInt  hash_shift;
+    /* Number of bits by which ins_h must be shifted at each input
+     * step. It must be such that after MIN_MATCH steps, the oldest
+     * byte no longer takes part in the hash key, that is:
+     *   hash_shift * MIN_MATCH >= hash_bits
+     */
+
+    long block_start;
+    /* Window position at the beginning of the current output block. Gets
+     * negative when the window is moved backwards.
+     */
+
+    uInt match_length;           /* length of best match */
+    IPos prev_match;             /* previous match */
+    int match_available;         /* set if previous match exists */
+    uInt strstart;               /* start of string to insert */
+    uInt match_start;            /* start of matching string */
+    uInt lookahead;              /* number of valid bytes ahead in window */
+
+    uInt prev_length;
+    /* Length of the best match at previous step. Matches not greater than this
+     * are discarded. This is used in the lazy match evaluation.
+     */
+
+    uInt max_chain_length;
+    /* To speed up deflation, hash chains are never searched beyond this
+     * length.  A higher limit improves compression ratio but degrades the
+     * speed.
+     */
+
+    uInt max_lazy_match;
+    /* Attempt to find a better match only when the current match is strictly
+     * smaller than this value. This mechanism is used only for compression
+     * levels >= 4.
+     */
+#   define max_insert_length  max_lazy_match
+    /* Insert new strings in the hash table only if the match length is not
+     * greater than this length. This saves time but degrades compression.
+     * max_insert_length is used only for compression levels <= 3.
+     */
+
+    int level;    /* compression level (1..9) */
+    int strategy; /* favor or force Huffman coding*/
+
+    uInt good_match;
+    /* Use a faster search when the previous match is longer than this */
+
+    int nice_match; /* Stop searching when current match exceeds this */
+
+                /* used by trees.c: */
+    /* Didn't use ct_data typedef below to supress compiler warning */
+    struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
+    struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+    struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
+
+    struct tree_desc_s l_desc;               /* desc. for literal tree */
+    struct tree_desc_s d_desc;               /* desc. for distance tree */
+    struct tree_desc_s bl_desc;              /* desc. for bit length tree */
+
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
+    int heap_len;               /* number of elements in the heap */
+    int heap_max;               /* element of largest frequency */
+    /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+     * The same heap array is used to build all trees.
+     */
+
+    uch depth[2*L_CODES+1];
+    /* Depth of each subtree used as tie breaker for trees of equal frequency
+     */
+
+    uchf *l_buf;          /* buffer for literals or lengths */
+
+    uInt  lit_bufsize;
+    /* Size of match buffer for literals/lengths.  There are 4 reasons for
+     * limiting lit_bufsize to 64K:
+     *   - frequencies can be kept in 16 bit counters
+     *   - if compression is not successful for the first block, all input
+     *     data is still in the window so we can still emit a stored block even
+     *     when input comes from standard input.  (This can also be done for
+     *     all blocks if lit_bufsize is not greater than 32K.)
+     *   - if compression is not successful for a file smaller than 64K, we can
+     *     even emit a stored file instead of a stored block (saving 5 bytes).
+     *     This is applicable only for zip (not gzip or zlib).
+     *   - creating new Huffman trees less frequently may not provide fast
+     *     adaptation to changes in the input data statistics. (Take for
+     *     example a binary file with poorly compressible code followed by
+     *     a highly compressible string table.) Smaller buffer sizes give
+     *     fast adaptation but have of course the overhead of transmitting
+     *     trees more frequently.
+     *   - I can't count above 4
+     */
+
+    uInt last_lit;      /* running index in l_buf */
+
+    ushf *d_buf;
+    /* Buffer for distances. To simplify the code, d_buf and l_buf have
+     * the same number of elements. To use different lengths, an extra flag
+     * array would be necessary.
+     */
+
+    ulg opt_len;        /* bit length of current block with optimal trees */
+    ulg static_len;     /* bit length of current block with static trees */
+    uInt matches;       /* number of string matches in current block */
+    int last_eob_len;   /* bit length of EOB code for last block */
+
+#ifdef DEBUG
+    ulg compressed_len; /* total bit length of compressed file mod 2^32 */
+    ulg bits_sent;      /* bit length of compressed data sent mod 2^32 */
+#endif
+
+    ush bi_buf;
+    /* Output buffer. bits are inserted starting at the bottom (least
+     * significant bits).
+     */
+    int bi_valid;
+    /* Number of valid bits in bi_buf.  All bits above the last valid bit
+     * are always zero.
+     */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s)  ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+        /* in trees.c */
+void _tr_init         OF((deflate_state *s));
+int  _tr_tally        OF((deflate_state *s, unsigned dist, unsigned lc));
+void _tr_flush_block  OF((deflate_state *s, charf *buf, ulg stored_len,
+                          int eof));
+void _tr_align        OF((deflate_state *s));
+void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
+                          int eof));
+
+#define d_code(dist) \
+   ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. _dist_code[256] and _dist_code[257] are never
+ * used.
+ */
+
+#ifndef DEBUG
+/* Inline versions of _tr_tally for speed: */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+  extern uch _length_code[];
+  extern uch _dist_code[];
+#else
+  extern const uch _length_code[];
+  extern const uch _dist_code[];
+#endif
+
+# define _tr_tally_lit(s, c, flush) \
+  { uch cc = (c); \
+    s->d_buf[s->last_lit] = 0; \
+    s->l_buf[s->last_lit++] = cc; \
+    s->dyn_ltree[cc].Freq++; \
+    flush = (s->last_lit == s->lit_bufsize-1); \
+   }
+# define _tr_tally_dist(s, distance, length, flush) \
+  { uch len = (length); \
+    ush dist = (distance); \
+    s->d_buf[s->last_lit] = dist; \
+    s->l_buf[s->last_lit++] = len; \
+    dist--; \
+    s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
+    s->dyn_dtree[d_code(dist)].Freq++; \
+    flush = (s->last_lit == s->lit_bufsize-1); \
+  }
+#else
+# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
+# define _tr_tally_dist(s, distance, length, flush) \
+              flush = _tr_tally(s, distance, length)
+#endif
+
+#endif /* DEFLATE_H */
diff --git a/src/unison/physfs-1.1.1/zlib123/gzio.c b/src/unison/physfs-1.1.1/zlib123/gzio.c
new file mode 100644 (file)
index 0000000..7e90f49
--- /dev/null
@@ -0,0 +1,1026 @@
+/* gzio.c -- IO on .gz files
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Compile this file with -DNO_GZCOMPRESS to avoid the compression code.
+ */
+
+/* @(#) $Id$ */
+
+#include <stdio.h>
+
+#include "zutil.h"
+
+#ifdef NO_DEFLATE       /* for compatibility with old definition */
+#  define NO_GZCOMPRESS
+#endif
+
+#ifndef NO_DUMMY_DECL
+struct internal_state {int dummy;}; /* for buggy compilers */
+#endif
+
+#ifndef Z_BUFSIZE
+#  ifdef MAXSEG_64K
+#    define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
+#  else
+#    define Z_BUFSIZE 16384
+#  endif
+#endif
+#ifndef Z_PRINTF_BUFSIZE
+#  define Z_PRINTF_BUFSIZE 4096
+#endif
+
+#ifdef __MVS__
+#  pragma map (fdopen , "\174\174FDOPEN")
+   FILE *fdopen(int, const char *);
+#endif
+
+#ifndef STDC
+extern voidp  malloc OF((uInt size));
+extern void   free   OF((voidpf ptr));
+#endif
+
+#define ALLOC(size) malloc(size)
+#define TRYFREE(p) {if (p) free(p);}
+
+static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
+
+/* gzip flag byte */
+#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
+#define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
+#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
+#define COMMENT      0x10 /* bit 4 set: file comment present */
+#define RESERVED     0xE0 /* bits 5..7: reserved */
+
+typedef struct gz_stream {
+    z_stream stream;
+    int      z_err;   /* error code for last stream operation */
+    int      z_eof;   /* set if end of input file */
+    FILE     *file;   /* .gz file */
+    Byte     *inbuf;  /* input buffer */
+    Byte     *outbuf; /* output buffer */
+    uLong    crc;     /* crc32 of uncompressed data */
+    char     *msg;    /* error message */
+    char     *path;   /* path name for debugging only */
+    int      transparent; /* 1 if input file is not a .gz file */
+    char     mode;    /* 'w' or 'r' */
+    z_off_t  start;   /* start of compressed data in file (header skipped) */
+    z_off_t  in;      /* bytes into deflate or inflate */
+    z_off_t  out;     /* bytes out of deflate or inflate */
+    int      back;    /* one character push-back */
+    int      last;    /* true if push-back is last character */
+} gz_stream;
+
+
+local gzFile gz_open      OF((const char *path, const char *mode, int  fd));
+local int do_flush        OF((gzFile file, int flush));
+local int    get_byte     OF((gz_stream *s));
+local void   check_header OF((gz_stream *s));
+local int    destroy      OF((gz_stream *s));
+local void   putLong      OF((FILE *file, uLong x));
+local uLong  getLong      OF((gz_stream *s));
+
+/* ===========================================================================
+     Opens a gzip (.gz) file for reading or writing. The mode parameter
+   is as in fopen ("rb" or "wb"). The file is given either by file descriptor
+   or path name (if fd == -1).
+     gz_open returns NULL if the file could not be opened or if there was
+   insufficient memory to allocate the (de)compression state; errno
+   can be checked to distinguish the two cases (if errno is zero, the
+   zlib error is Z_MEM_ERROR).
+*/
+local gzFile gz_open (path, mode, fd)
+    const char *path;
+    const char *mode;
+    int  fd;
+{
+    int err;
+    int level = Z_DEFAULT_COMPRESSION; /* compression level */
+    int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
+    char *p = (char*)mode;
+    gz_stream *s;
+    char fmode[80]; /* copy of mode, without the compression level */
+    char *m = fmode;
+
+    if (!path || !mode) return Z_NULL;
+
+    s = (gz_stream *)ALLOC(sizeof(gz_stream));
+    if (!s) return Z_NULL;
+
+    s->stream.zalloc = (alloc_func)0;
+    s->stream.zfree = (free_func)0;
+    s->stream.opaque = (voidpf)0;
+    s->stream.next_in = s->inbuf = Z_NULL;
+    s->stream.next_out = s->outbuf = Z_NULL;
+    s->stream.avail_in = s->stream.avail_out = 0;
+    s->file = NULL;
+    s->z_err = Z_OK;
+    s->z_eof = 0;
+    s->in = 0;
+    s->out = 0;
+    s->back = EOF;
+    s->crc = crc32(0L, Z_NULL, 0);
+    s->msg = NULL;
+    s->transparent = 0;
+
+    s->path = (char*)ALLOC(strlen(path)+1);
+    if (s->path == NULL) {
+        return destroy(s), (gzFile)Z_NULL;
+    }
+    strcpy(s->path, path); /* do this early for debugging */
+
+    s->mode = '\0';
+    do {
+        if (*p == 'r') s->mode = 'r';
+        if (*p == 'w' || *p == 'a') s->mode = 'w';
+        if (*p >= '0' && *p <= '9') {
+            level = *p - '0';
+        } else if (*p == 'f') {
+          strategy = Z_FILTERED;
+        } else if (*p == 'h') {
+          strategy = Z_HUFFMAN_ONLY;
+        } else if (*p == 'R') {
+          strategy = Z_RLE;
+        } else {
+            *m++ = *p; /* copy the mode */
+        }
+    } while (*p++ && m != fmode + sizeof(fmode));
+    if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
+
+    if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+        err = Z_STREAM_ERROR;
+#else
+        err = deflateInit2(&(s->stream), level,
+                           Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
+        /* windowBits is passed < 0 to suppress zlib header */
+
+        s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
+#endif
+        if (err != Z_OK || s->outbuf == Z_NULL) {
+            return destroy(s), (gzFile)Z_NULL;
+        }
+    } else {
+        s->stream.next_in  = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
+
+        err = inflateInit2(&(s->stream), -MAX_WBITS);
+        /* windowBits is passed < 0 to tell that there is no zlib header.
+         * Note that in this case inflate *requires* an extra "dummy" byte
+         * after the compressed stream in order to complete decompression and
+         * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
+         * present after the compressed stream.
+         */
+        if (err != Z_OK || s->inbuf == Z_NULL) {
+            return destroy(s), (gzFile)Z_NULL;
+        }
+    }
+    s->stream.avail_out = Z_BUFSIZE;
+
+    errno = 0;
+    s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
+
+    if (s->file == NULL) {
+        return destroy(s), (gzFile)Z_NULL;
+    }
+    if (s->mode == 'w') {
+        /* Write a very simple .gz header:
+         */
+        fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
+             Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
+        s->start = 10L;
+        /* We use 10L instead of ftell(s->file) to because ftell causes an
+         * fflush on some systems. This version of the library doesn't use
+         * start anyway in write mode, so this initialization is not
+         * necessary.
+         */
+    } else {
+        check_header(s); /* skip the .gz header */
+        s->start = ftell(s->file) - s->stream.avail_in;
+    }
+
+    return (gzFile)s;
+}
+
+/* ===========================================================================
+     Opens a gzip (.gz) file for reading or writing.
+*/
+gzFile ZEXPORT gzopen (path, mode)
+    const char *path;
+    const char *mode;
+{
+    return gz_open (path, mode, -1);
+}
+
+/* ===========================================================================
+     Associate a gzFile with the file descriptor fd. fd is not dup'ed here
+   to mimic the behavio(u)r of fdopen.
+*/
+gzFile ZEXPORT gzdopen (fd, mode)
+    int fd;
+    const char *mode;
+{
+    char name[46];      /* allow for up to 128-bit integers */
+
+    if (fd < 0) return (gzFile)Z_NULL;
+    sprintf(name, "<fd:%d>", fd); /* for debugging */
+
+    return gz_open (name, mode, fd);
+}
+
+/* ===========================================================================
+ * Update the compression level and strategy
+ */
+int ZEXPORT gzsetparams (file, level, strategy)
+    gzFile file;
+    int level;
+    int strategy;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+    /* Make room to allow flushing */
+    if (s->stream.avail_out == 0) {
+
+        s->stream.next_out = s->outbuf;
+        if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
+            s->z_err = Z_ERRNO;
+        }
+        s->stream.avail_out = Z_BUFSIZE;
+    }
+
+    return deflateParams (&(s->stream), level, strategy);
+}
+
+/* ===========================================================================
+     Read a byte from a gz_stream; update next_in and avail_in. Return EOF
+   for end of file.
+   IN assertion: the stream s has been sucessfully opened for reading.
+*/
+local int get_byte(s)
+    gz_stream *s;
+{
+    if (s->z_eof) return EOF;
+    if (s->stream.avail_in == 0) {
+        errno = 0;
+        s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
+        if (s->stream.avail_in == 0) {
+            s->z_eof = 1;
+            if (ferror(s->file)) s->z_err = Z_ERRNO;
+            return EOF;
+        }
+        s->stream.next_in = s->inbuf;
+    }
+    s->stream.avail_in--;
+    return *(s->stream.next_in)++;
+}
+
+/* ===========================================================================
+      Check the gzip header of a gz_stream opened for reading. Set the stream
+    mode to transparent if the gzip magic header is not present; set s->err
+    to Z_DATA_ERROR if the magic header is present but the rest of the header
+    is incorrect.
+    IN assertion: the stream s has already been created sucessfully;
+       s->stream.avail_in is zero for the first time, but may be non-zero
+       for concatenated .gz files.
+*/
+local void check_header(s)
+    gz_stream *s;
+{
+    int method; /* method byte */
+    int flags;  /* flags byte */
+    uInt len;
+    int c;
+
+    /* Assure two bytes in the buffer so we can peek ahead -- handle case
+       where first byte of header is at the end of the buffer after the last
+       gzip segment */
+    len = s->stream.avail_in;
+    if (len < 2) {
+        if (len) s->inbuf[0] = s->stream.next_in[0];
+        errno = 0;
+        len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file);
+        if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO;
+        s->stream.avail_in += len;
+        s->stream.next_in = s->inbuf;
+        if (s->stream.avail_in < 2) {
+            s->transparent = s->stream.avail_in;
+            return;
+        }
+    }
+
+    /* Peek ahead to check the gzip magic header */
+    if (s->stream.next_in[0] != gz_magic[0] ||
+        s->stream.next_in[1] != gz_magic[1]) {
+        s->transparent = 1;
+        return;
+    }
+    s->stream.avail_in -= 2;
+    s->stream.next_in += 2;
+
+    /* Check the rest of the gzip header */
+    method = get_byte(s);
+    flags = get_byte(s);
+    if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
+        s->z_err = Z_DATA_ERROR;
+        return;
+    }
+
+    /* Discard time, xflags and OS code: */
+    for (len = 0; len < 6; len++) (void)get_byte(s);
+
+    if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
+        len  =  (uInt)get_byte(s);
+        len += ((uInt)get_byte(s))<<8;
+        /* len is garbage if EOF but the loop below will quit anyway */
+        while (len-- != 0 && get_byte(s) != EOF) ;
+    }
+    if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
+        while ((c = get_byte(s)) != 0 && c != EOF) ;
+    }
+    if ((flags & COMMENT) != 0) {   /* skip the .gz file comment */
+        while ((c = get_byte(s)) != 0 && c != EOF) ;
+    }
+    if ((flags & HEAD_CRC) != 0) {  /* skip the header crc */
+        for (len = 0; len < 2; len++) (void)get_byte(s);
+    }
+    s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
+}
+
+ /* ===========================================================================
+ * Cleanup then free the given gz_stream. Return a zlib error code.
+   Try freeing in the reverse order of allocations.
+ */
+local int destroy (s)
+    gz_stream *s;
+{
+    int err = Z_OK;
+
+    if (!s) return Z_STREAM_ERROR;
+
+    TRYFREE(s->msg);
+
+    if (s->stream.state != NULL) {
+        if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+            err = Z_STREAM_ERROR;
+#else
+            err = deflateEnd(&(s->stream));
+#endif
+        } else if (s->mode == 'r') {
+            err = inflateEnd(&(s->stream));
+        }
+    }
+    if (s->file != NULL && fclose(s->file)) {
+#ifdef ESPIPE
+        if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
+#endif
+            err = Z_ERRNO;
+    }
+    if (s->z_err < 0) err = s->z_err;
+
+    TRYFREE(s->inbuf);
+    TRYFREE(s->outbuf);
+    TRYFREE(s->path);
+    TRYFREE(s);
+    return err;
+}
+
+/* ===========================================================================
+     Reads the given number of uncompressed bytes from the compressed file.
+   gzread returns the number of bytes actually read (0 for end of file).
+*/
+int ZEXPORT gzread (file, buf, len)
+    gzFile file;
+    voidp buf;
+    unsigned len;
+{
+    gz_stream *s = (gz_stream*)file;
+    Bytef *start = (Bytef*)buf; /* starting point for crc computation */
+    Byte  *next_out; /* == stream.next_out but not forced far (for MSDOS) */
+
+    if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
+
+    if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
+    if (s->z_err == Z_STREAM_END) return 0;  /* EOF */
+
+    next_out = (Byte*)buf;
+    s->stream.next_out = (Bytef*)buf;
+    s->stream.avail_out = len;
+
+    if (s->stream.avail_out && s->back != EOF) {
+        *next_out++ = s->back;
+        s->stream.next_out++;
+        s->stream.avail_out--;
+        s->back = EOF;
+        s->out++;
+        start++;
+        if (s->last) {
+            s->z_err = Z_STREAM_END;
+            return 1;
+        }
+    }
+
+    while (s->stream.avail_out != 0) {
+
+        if (s->transparent) {
+            /* Copy first the lookahead bytes: */
+            uInt n = s->stream.avail_in;
+            if (n > s->stream.avail_out) n = s->stream.avail_out;
+            if (n > 0) {
+                zmemcpy(s->stream.next_out, s->stream.next_in, n);
+                next_out += n;
+                s->stream.next_out = next_out;
+                s->stream.next_in   += n;
+                s->stream.avail_out -= n;
+                s->stream.avail_in  -= n;
+            }
+            if (s->stream.avail_out > 0) {
+                s->stream.avail_out -=
+                    (uInt)fread(next_out, 1, s->stream.avail_out, s->file);
+            }
+            len -= s->stream.avail_out;
+            s->in  += len;
+            s->out += len;
+            if (len == 0) s->z_eof = 1;
+            return (int)len;
+        }
+        if (s->stream.avail_in == 0 && !s->z_eof) {
+
+            errno = 0;
+            s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
+            if (s->stream.avail_in == 0) {
+                s->z_eof = 1;
+                if (ferror(s->file)) {
+                    s->z_err = Z_ERRNO;
+                    break;
+                }
+            }
+            s->stream.next_in = s->inbuf;
+        }
+        s->in += s->stream.avail_in;
+        s->out += s->stream.avail_out;
+        s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
+        s->in -= s->stream.avail_in;
+        s->out -= s->stream.avail_out;
+
+        if (s->z_err == Z_STREAM_END) {
+            /* Check CRC and original size */
+            s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
+            start = s->stream.next_out;
+
+            if (getLong(s) != s->crc) {
+                s->z_err = Z_DATA_ERROR;
+            } else {
+                (void)getLong(s);
+                /* The uncompressed length returned by above getlong() may be
+                 * different from s->out in case of concatenated .gz files.
+                 * Check for such files:
+                 */
+                check_header(s);
+                if (s->z_err == Z_OK) {
+                    inflateReset(&(s->stream));
+                    s->crc = crc32(0L, Z_NULL, 0);
+                }
+            }
+        }
+        if (s->z_err != Z_OK || s->z_eof) break;
+    }
+    s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
+
+    if (len == s->stream.avail_out &&
+        (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO))
+        return -1;
+    return (int)(len - s->stream.avail_out);
+}
+
+
+/* ===========================================================================
+      Reads one byte from the compressed file. gzgetc returns this byte
+   or -1 in case of end of file or error.
+*/
+int ZEXPORT gzgetc(file)
+    gzFile file;
+{
+    unsigned char c;
+
+    return gzread(file, &c, 1) == 1 ? c : -1;
+}
+
+
+/* ===========================================================================
+      Push one byte back onto the stream.
+*/
+int ZEXPORT gzungetc(c, file)
+    int c;
+    gzFile file;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF;
+    s->back = c;
+    s->out--;
+    s->last = (s->z_err == Z_STREAM_END);
+    if (s->last) s->z_err = Z_OK;
+    s->z_eof = 0;
+    return c;
+}
+
+
+/* ===========================================================================
+      Reads bytes from the compressed file until len-1 characters are
+   read, or a newline character is read and transferred to buf, or an
+   end-of-file condition is encountered.  The string is then terminated
+   with a null character.
+      gzgets returns buf, or Z_NULL in case of error.
+
+      The current implementation is not optimized at all.
+*/
+char * ZEXPORT gzgets(file, buf, len)
+    gzFile file;
+    char *buf;
+    int len;
+{
+    char *b = buf;
+    if (buf == Z_NULL || len <= 0) return Z_NULL;
+
+    while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ;
+    *buf = '\0';
+    return b == buf && len > 0 ? Z_NULL : b;
+}
+
+
+#ifndef NO_GZCOMPRESS
+/* ===========================================================================
+     Writes the given number of uncompressed bytes into the compressed file.
+   gzwrite returns the number of bytes actually written (0 in case of error).
+*/
+int ZEXPORT gzwrite (file, buf, len)
+    gzFile file;
+    voidpc buf;
+    unsigned len;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+    s->stream.next_in = (Bytef*)buf;
+    s->stream.avail_in = len;
+
+    while (s->stream.avail_in != 0) {
+
+        if (s->stream.avail_out == 0) {
+
+            s->stream.next_out = s->outbuf;
+            if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
+                s->z_err = Z_ERRNO;
+                break;
+            }
+            s->stream.avail_out = Z_BUFSIZE;
+        }
+        s->in += s->stream.avail_in;
+        s->out += s->stream.avail_out;
+        s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
+        s->in -= s->stream.avail_in;
+        s->out -= s->stream.avail_out;
+        if (s->z_err != Z_OK) break;
+    }
+    s->crc = crc32(s->crc, (const Bytef *)buf, len);
+
+    return (int)(len - s->stream.avail_in);
+}
+
+
+/* ===========================================================================
+     Converts, formats, and writes the args to the compressed file under
+   control of the format string, as in fprintf. gzprintf returns the number of
+   uncompressed bytes actually written (0 in case of error).
+*/
+#ifdef STDC
+#include <stdarg.h>
+
+int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...)
+{
+    char buf[Z_PRINTF_BUFSIZE];
+    va_list va;
+    int len;
+
+    buf[sizeof(buf) - 1] = 0;
+    va_start(va, format);
+#ifdef NO_vsnprintf
+#  ifdef HAS_vsprintf_void
+    (void)vsprintf(buf, format, va);
+    va_end(va);
+    for (len = 0; len < sizeof(buf); len++)
+        if (buf[len] == 0) break;
+#  else
+    len = vsprintf(buf, format, va);
+    va_end(va);
+#  endif
+#else
+#  ifdef HAS_vsnprintf_void
+    (void)vsnprintf(buf, sizeof(buf), format, va);
+    va_end(va);
+    len = strlen(buf);
+#  else
+    len = vsnprintf(buf, sizeof(buf), format, va);
+    va_end(va);
+#  endif
+#endif
+    if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0)
+        return 0;
+    return gzwrite(file, buf, (unsigned)len);
+}
+#else /* not ANSI C */
+
+int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+                       a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
+    gzFile file;
+    const char *format;
+    int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+        a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
+{
+    char buf[Z_PRINTF_BUFSIZE];
+    int len;
+
+    buf[sizeof(buf) - 1] = 0;
+#ifdef NO_snprintf
+#  ifdef HAS_sprintf_void
+    sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
+            a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+    for (len = 0; len < sizeof(buf); len++)
+        if (buf[len] == 0) break;
+#  else
+    len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
+                a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+#  endif
+#else
+#  ifdef HAS_snprintf_void
+    snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
+             a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+    len = strlen(buf);
+#  else
+    len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
+                 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+#  endif
+#endif
+    if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0)
+        return 0;
+    return gzwrite(file, buf, len);
+}
+#endif
+
+/* ===========================================================================
+      Writes c, converted to an unsigned char, into the compressed file.
+   gzputc returns the value that was written, or -1 in case of error.
+*/
+int ZEXPORT gzputc(file, c)
+    gzFile file;
+    int c;
+{
+    unsigned char cc = (unsigned char) c; /* required for big endian systems */
+
+    return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1;
+}
+
+
+/* ===========================================================================
+      Writes the given null-terminated string to the compressed file, excluding
+   the terminating null character.
+      gzputs returns the number of characters written, or -1 in case of error.
+*/
+int ZEXPORT gzputs(file, s)
+    gzFile file;
+    const char *s;
+{
+    return gzwrite(file, (char*)s, (unsigned)strlen(s));
+}
+
+
+/* ===========================================================================
+     Flushes all pending output into the compressed file. The parameter
+   flush is as in the deflate() function.
+*/
+local int do_flush (file, flush)
+    gzFile file;
+    int flush;
+{
+    uInt len;
+    int done = 0;
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+    s->stream.avail_in = 0; /* should be zero already anyway */
+
+    for (;;) {
+        len = Z_BUFSIZE - s->stream.avail_out;
+
+        if (len != 0) {
+            if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
+                s->z_err = Z_ERRNO;
+                return Z_ERRNO;
+            }
+            s->stream.next_out = s->outbuf;
+            s->stream.avail_out = Z_BUFSIZE;
+        }
+        if (done) break;
+        s->out += s->stream.avail_out;
+        s->z_err = deflate(&(s->stream), flush);
+        s->out -= s->stream.avail_out;
+
+        /* Ignore the second of two consecutive flushes: */
+        if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
+
+        /* deflate has finished flushing only when it hasn't used up
+         * all the available space in the output buffer:
+         */
+        done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
+
+        if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
+    }
+    return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+}
+
+int ZEXPORT gzflush (file, flush)
+     gzFile file;
+     int flush;
+{
+    gz_stream *s = (gz_stream*)file;
+    int err = do_flush (file, flush);
+
+    if (err) return err;
+    fflush(s->file);
+    return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+}
+#endif /* NO_GZCOMPRESS */
+
+/* ===========================================================================
+      Sets the starting position for the next gzread or gzwrite on the given
+   compressed file. The offset represents a number of bytes in the
+      gzseek returns the resulting offset location as measured in bytes from
+   the beginning of the uncompressed stream, or -1 in case of error.
+      SEEK_END is not implemented, returns error.
+      In this version of the library, gzseek can be extremely slow.
+*/
+z_off_t ZEXPORT gzseek (file, offset, whence)
+    gzFile file;
+    z_off_t offset;
+    int whence;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || whence == SEEK_END ||
+        s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
+        return -1L;
+    }
+
+    if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+        return -1L;
+#else
+        if (whence == SEEK_SET) {
+            offset -= s->in;
+        }
+        if (offset < 0) return -1L;
+
+        /* At this point, offset is the number of zero bytes to write. */
+        if (s->inbuf == Z_NULL) {
+            s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */
+            if (s->inbuf == Z_NULL) return -1L;
+            zmemzero(s->inbuf, Z_BUFSIZE);
+        }
+        while (offset > 0)  {
+            uInt size = Z_BUFSIZE;
+            if (offset < Z_BUFSIZE) size = (uInt)offset;
+
+            size = gzwrite(file, s->inbuf, size);
+            if (size == 0) return -1L;
+
+            offset -= size;
+        }
+        return s->in;
+#endif
+    }
+    /* Rest of function is for reading only */
+
+    /* compute absolute position */
+    if (whence == SEEK_CUR) {
+        offset += s->out;
+    }
+    if (offset < 0) return -1L;
+
+    if (s->transparent) {
+        /* map to fseek */
+        s->back = EOF;
+        s->stream.avail_in = 0;
+        s->stream.next_in = s->inbuf;
+        if (fseek(s->file, offset, SEEK_SET) < 0) return -1L;
+
+        s->in = s->out = offset;
+        return offset;
+    }
+
+    /* For a negative seek, rewind and use positive seek */
+    if (offset >= s->out) {
+        offset -= s->out;
+    } else if (gzrewind(file) < 0) {
+        return -1L;
+    }
+    /* offset is now the number of bytes to skip. */
+
+    if (offset != 0 && s->outbuf == Z_NULL) {
+        s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
+        if (s->outbuf == Z_NULL) return -1L;
+    }
+    if (offset && s->back != EOF) {
+        s->back = EOF;
+        s->out++;
+        offset--;
+        if (s->last) s->z_err = Z_STREAM_END;
+    }
+    while (offset > 0)  {
+        int size = Z_BUFSIZE;
+        if (offset < Z_BUFSIZE) size = (int)offset;
+
+        size = gzread(file, s->outbuf, (uInt)size);
+        if (size <= 0) return -1L;
+        offset -= size;
+    }
+    return s->out;
+}
+
+/* ===========================================================================
+     Rewinds input file.
+*/
+int ZEXPORT gzrewind (file)
+    gzFile file;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || s->mode != 'r') return -1;
+
+    s->z_err = Z_OK;
+    s->z_eof = 0;
+    s->back = EOF;
+    s->stream.avail_in = 0;
+    s->stream.next_in = s->inbuf;
+    s->crc = crc32(0L, Z_NULL, 0);
+    if (!s->transparent) (void)inflateReset(&s->stream);
+    s->in = 0;
+    s->out = 0;
+    return fseek(s->file, s->start, SEEK_SET);
+}
+
+/* ===========================================================================
+     Returns the starting position for the next gzread or gzwrite on the
+   given compressed file. This position represents a number of bytes in the
+   uncompressed data stream.
+*/
+z_off_t ZEXPORT gztell (file)
+    gzFile file;
+{
+    return gzseek(file, 0L, SEEK_CUR);
+}
+
+/* ===========================================================================
+     Returns 1 when EOF has previously been detected reading the given
+   input stream, otherwise zero.
+*/
+int ZEXPORT gzeof (file)
+    gzFile file;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    /* With concatenated compressed files that can have embedded
+     * crc trailers, z_eof is no longer the only/best indicator of EOF
+     * on a gz_stream. Handle end-of-stream error explicitly here.
+     */
+    if (s == NULL || s->mode != 'r') return 0;
+    if (s->z_eof) return 1;
+    return s->z_err == Z_STREAM_END;
+}
+
+/* ===========================================================================
+     Returns 1 if reading and doing so transparently, otherwise zero.
+*/
+int ZEXPORT gzdirect (file)
+    gzFile file;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || s->mode != 'r') return 0;
+    return s->transparent;
+}
+
+/* ===========================================================================
+   Outputs a long in LSB order to the given file
+*/
+local void putLong (file, x)
+    FILE *file;
+    uLong x;
+{
+    int n;
+    for (n = 0; n < 4; n++) {
+        fputc((int)(x & 0xff), file);
+        x >>= 8;
+    }
+}
+
+/* ===========================================================================
+   Reads a long in LSB order from the given gz_stream. Sets z_err in case
+   of error.
+*/
+local uLong getLong (s)
+    gz_stream *s;
+{
+    uLong x = (uLong)get_byte(s);
+    int c;
+
+    x += ((uLong)get_byte(s))<<8;
+    x += ((uLong)get_byte(s))<<16;
+    c = get_byte(s);
+    if (c == EOF) s->z_err = Z_DATA_ERROR;
+    x += ((uLong)c)<<24;
+    return x;
+}
+
+/* ===========================================================================
+     Flushes all pending output if necessary, closes the compressed file
+   and deallocates all the (de)compression state.
+*/
+int ZEXPORT gzclose (file)
+    gzFile file;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL) return Z_STREAM_ERROR;
+
+    if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+        return Z_STREAM_ERROR;
+#else
+        if (do_flush (file, Z_FINISH) != Z_OK)
+            return destroy((gz_stream*)file);
+
+        putLong (s->file, s->crc);
+        putLong (s->file, (uLong)(s->in & 0xffffffff));
+#endif
+    }
+    return destroy((gz_stream*)file);
+}
+
+#ifdef STDC
+#  define zstrerror(errnum) strerror(errnum)
+#else
+#  define zstrerror(errnum) ""
+#endif
+
+/* ===========================================================================
+     Returns the error message for the last error which occurred on the
+   given compressed file. errnum is set to zlib error number. If an
+   error occurred in the file system and not in the compression library,
+   errnum is set to Z_ERRNO and the application may consult errno
+   to get the exact error code.
+*/
+const char * ZEXPORT gzerror (file, errnum)
+    gzFile file;
+    int *errnum;
+{
+    char *m;
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL) {
+        *errnum = Z_STREAM_ERROR;
+        return (const char*)ERR_MSG(Z_STREAM_ERROR);
+    }
+    *errnum = s->z_err;
+    if (*errnum == Z_OK) return (const char*)"";
+
+    m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg);
+
+    if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err);
+
+    TRYFREE(s->msg);
+    s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
+    if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR);
+    strcpy(s->msg, s->path);
+    strcat(s->msg, ": ");
+    strcat(s->msg, m);
+    return (const char*)s->msg;
+}
+
+/* ===========================================================================
+     Clear the error and end-of-file flags, and do the same for the real file.
+*/
+void ZEXPORT gzclearerr (file)
+    gzFile file;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL) return;
+    if (s->z_err != Z_STREAM_END) s->z_err = Z_OK;
+    s->z_eof = 0;
+    clearerr(s->file);
+}
diff --git a/src/unison/physfs-1.1.1/zlib123/infback.c b/src/unison/physfs-1.1.1/zlib123/infback.c
new file mode 100644 (file)
index 0000000..455dbc9
--- /dev/null
@@ -0,0 +1,623 @@
+/* infback.c -- inflate using a call-back interface
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+   This code is largely copied from inflate.c.  Normally either infback.o or
+   inflate.o would be linked into an application--not both.  The interface
+   with inffast.c is retained so that optimized assembler-coded versions of
+   inflate_fast() can be used with either inflate.c or infback.c.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+
+/*
+   strm provides memory allocation functions in zalloc and zfree, or
+   Z_NULL to use the library memory allocation functions.
+
+   windowBits is in the range 8..15, and window is a user-supplied
+   window and output buffer that is 2**windowBits bytes.
+ */
+int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size)
+z_streamp strm;
+int windowBits;
+unsigned char FAR *window;
+const char *version;
+int stream_size;
+{
+    struct inflate_state FAR *state;
+
+    if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+        stream_size != (int)(sizeof(z_stream)))
+        return Z_VERSION_ERROR;
+    if (strm == Z_NULL || window == Z_NULL ||
+        windowBits < 8 || windowBits > 15)
+        return Z_STREAM_ERROR;
+    strm->msg = Z_NULL;                 /* in case we return an error */
+    if (strm->zalloc == (alloc_func)0) {
+        strm->zalloc = zcalloc;
+        strm->opaque = (voidpf)0;
+    }
+    if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+    state = (struct inflate_state FAR *)ZALLOC(strm, 1,
+                                               sizeof(struct inflate_state));
+    if (state == Z_NULL) return Z_MEM_ERROR;
+    Tracev((stderr, "inflate: allocated\n"));
+    strm->state = (struct internal_state FAR *)state;
+    state->dmax = 32768U;
+    state->wbits = windowBits;
+    state->wsize = 1U << windowBits;
+    state->window = window;
+    state->write = 0;
+    state->whave = 0;
+    return Z_OK;
+}
+
+/*
+   Return state with length and distance decoding tables and index sizes set to
+   fixed code decoding.  Normally this returns fixed tables from inffixed.h.
+   If BUILDFIXED is defined, then instead this routine builds the tables the
+   first time it's called, and returns those tables the first time and
+   thereafter.  This reduces the size of the code by about 2K bytes, in
+   exchange for a little execution time.  However, BUILDFIXED should not be
+   used for threaded applications, since the rewriting of the tables and virgin
+   may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+    static int virgin = 1;
+    static code *lenfix, *distfix;
+    static code fixed[544];
+
+    /* build fixed huffman tables if first call (may not be thread safe) */
+    if (virgin) {
+        unsigned sym, bits;
+        static code *next;
+
+        /* literal/length table */
+        sym = 0;
+        while (sym < 144) state->lens[sym++] = 8;
+        while (sym < 256) state->lens[sym++] = 9;
+        while (sym < 280) state->lens[sym++] = 7;
+        while (sym < 288) state->lens[sym++] = 8;
+        next = fixed;
+        lenfix = next;
+        bits = 9;
+        inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+        /* distance table */
+        sym = 0;
+        while (sym < 32) state->lens[sym++] = 5;
+        distfix = next;
+        bits = 5;
+        inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+        /* do this just once */
+        virgin = 0;
+    }
+#else /* !BUILDFIXED */
+#   include "inffixed.h"
+#endif /* BUILDFIXED */
+    state->lencode = lenfix;
+    state->lenbits = 9;
+    state->distcode = distfix;
+    state->distbits = 5;
+}
+
+/* Macros for inflateBack(): */
+
+/* Load returned state from inflate_fast() */
+#define LOAD() \
+    do { \
+        put = strm->next_out; \
+        left = strm->avail_out; \
+        next = strm->next_in; \
+        have = strm->avail_in; \
+        hold = state->hold; \
+        bits = state->bits; \
+    } while (0)
+
+/* Set state from registers for inflate_fast() */
+#define RESTORE() \
+    do { \
+        strm->next_out = put; \
+        strm->avail_out = left; \
+        strm->next_in = next; \
+        strm->avail_in = have; \
+        state->hold = hold; \
+        state->bits = bits; \
+    } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+    do { \
+        hold = 0; \
+        bits = 0; \
+    } while (0)
+
+/* Assure that some input is available.  If input is requested, but denied,
+   then return a Z_BUF_ERROR from inflateBack(). */
+#define PULL() \
+    do { \
+        if (have == 0) { \
+            have = in(in_desc, &next); \
+            if (have == 0) { \
+                next = Z_NULL; \
+                ret = Z_BUF_ERROR; \
+                goto inf_leave; \
+            } \
+        } \
+    } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflateBack()
+   with an error if there is no input available. */
+#define PULLBYTE() \
+    do { \
+        PULL(); \
+        have--; \
+        hold += (unsigned long)(*next++) << bits; \
+        bits += 8; \
+    } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator.  If there is
+   not enough available input to do that, then return from inflateBack() with
+   an error. */
+#define NEEDBITS(n) \
+    do { \
+        while (bits < (unsigned)(n)) \
+            PULLBYTE(); \
+    } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+    ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+    do { \
+        hold >>= (n); \
+        bits -= (unsigned)(n); \
+    } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+    do { \
+        hold >>= bits & 7; \
+        bits -= bits & 7; \
+    } while (0)
+
+/* Assure that some output space is available, by writing out the window
+   if it's full.  If the write fails, return from inflateBack() with a
+   Z_BUF_ERROR. */
+#define ROOM() \
+    do { \
+        if (left == 0) { \
+            put = state->window; \
+            left = state->wsize; \
+            state->whave = left; \
+            if (out(out_desc, put, left)) { \
+                ret = Z_BUF_ERROR; \
+                goto inf_leave; \
+            } \
+        } \
+    } while (0)
+
+/*
+   strm provides the memory allocation functions and window buffer on input,
+   and provides information on the unused input on return.  For Z_DATA_ERROR
+   returns, strm will also provide an error message.
+
+   in() and out() are the call-back input and output functions.  When
+   inflateBack() needs more input, it calls in().  When inflateBack() has
+   filled the window with output, or when it completes with data in the
+   window, it calls out() to write out the data.  The application must not
+   change the provided input until in() is called again or inflateBack()
+   returns.  The application must not change the window/output buffer until
+   inflateBack() returns.
+
+   in() and out() are called with a descriptor parameter provided in the
+   inflateBack() call.  This parameter can be a structure that provides the
+   information required to do the read or write, as well as accumulated
+   information on the input and output such as totals and check values.
+
+   in() should return zero on failure.  out() should return non-zero on
+   failure.  If either in() or out() fails, than inflateBack() returns a
+   Z_BUF_ERROR.  strm->next_in can be checked for Z_NULL to see whether it
+   was in() or out() that caused in the error.  Otherwise,  inflateBack()
+   returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format
+   error, or Z_MEM_ERROR if it could not allocate memory for the state.
+   inflateBack() can also return Z_STREAM_ERROR if the input parameters
+   are not correct, i.e. strm is Z_NULL or the state was not initialized.
+ */
+int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc)
+z_streamp strm;
+in_func in;
+void FAR *in_desc;
+out_func out;
+void FAR *out_desc;
+{
+    struct inflate_state FAR *state;
+    unsigned char FAR *next;    /* next input */
+    unsigned char FAR *put;     /* next output */
+    unsigned have, left;        /* available input and output */
+    unsigned long hold;         /* bit buffer */
+    unsigned bits;              /* bits in bit buffer */
+    unsigned copy;              /* number of stored or match bytes to copy */
+    unsigned char FAR *from;    /* where to copy match bytes from */
+    code this;                  /* current decoding table entry */
+    code last;                  /* parent table entry */
+    unsigned len;               /* length to copy for repeats, bits to drop */
+    int ret;                    /* return code */
+    static const unsigned short order[19] = /* permutation of code lengths */
+        {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+    /* Check that the strm exists and that the state was initialized */
+    if (strm == Z_NULL || strm->state == Z_NULL)
+        return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+
+    /* Reset the state */
+    strm->msg = Z_NULL;
+    state->mode = TYPE;
+    state->last = 0;
+    state->whave = 0;
+    next = strm->next_in;
+    have = next != Z_NULL ? strm->avail_in : 0;
+    hold = 0;
+    bits = 0;
+    put = state->window;
+    left = state->wsize;
+
+    /* Inflate until end of block marked as last */
+    for (;;)
+        switch (state->mode) {
+        case TYPE:
+            /* determine and dispatch block type */
+            if (state->last) {
+                BYTEBITS();
+                state->mode = DONE;
+                break;
+            }
+            NEEDBITS(3);
+            state->last = BITS(1);
+            DROPBITS(1);
+            switch (BITS(2)) {
+            case 0:                             /* stored block */
+                Tracev((stderr, "inflate:     stored block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = STORED;
+                break;
+            case 1:                             /* fixed block */
+                fixedtables(state);
+                Tracev((stderr, "inflate:     fixed codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = LEN;              /* decode codes */
+                break;
+            case 2:                             /* dynamic block */
+                Tracev((stderr, "inflate:     dynamic codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = TABLE;
+                break;
+            case 3:
+                strm->msg = (char *)"invalid block type";
+                state->mode = BAD;
+            }
+            DROPBITS(2);
+            break;
+
+        case STORED:
+            /* get and verify stored block length */
+            BYTEBITS();                         /* go to byte boundary */
+            NEEDBITS(32);
+            if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+                strm->msg = (char *)"invalid stored block lengths";
+                state->mode = BAD;
+                break;
+            }
+            state->length = (unsigned)hold & 0xffff;
+            Tracev((stderr, "inflate:       stored length %u\n",
+                    state->length));
+            INITBITS();
+
+            /* copy stored block from input to output */
+            while (state->length != 0) {
+                copy = state->length;
+                PULL();
+                ROOM();
+                if (copy > have) copy = have;
+                if (copy > left) copy = left;
+                zmemcpy(put, next, copy);
+                have -= copy;
+                next += copy;
+                left -= copy;
+                put += copy;
+                state->length -= copy;
+            }
+            Tracev((stderr, "inflate:       stored end\n"));
+            state->mode = TYPE;
+            break;
+
+        case TABLE:
+            /* get dynamic table entries descriptor */
+            NEEDBITS(14);
+            state->nlen = BITS(5) + 257;
+            DROPBITS(5);
+            state->ndist = BITS(5) + 1;
+            DROPBITS(5);
+            state->ncode = BITS(4) + 4;
+            DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+            if (state->nlen > 286 || state->ndist > 30) {
+                strm->msg = (char *)"too many length or distance symbols";
+                state->mode = BAD;
+                break;
+            }
+#endif
+            Tracev((stderr, "inflate:       table sizes ok\n"));
+
+            /* get code length code lengths (not a typo) */
+            state->have = 0;
+            while (state->have < state->ncode) {
+                NEEDBITS(3);
+                state->lens[order[state->have++]] = (unsigned short)BITS(3);
+                DROPBITS(3);
+            }
+            while (state->have < 19)
+                state->lens[order[state->have++]] = 0;
+            state->next = state->codes;
+            state->lencode = (code const FAR *)(state->next);
+            state->lenbits = 7;
+            ret = inflate_table(CODES, state->lens, 19, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid code lengths set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       code lengths ok\n"));
+
+            /* get length and distance code code lengths */
+            state->have = 0;
+            while (state->have < state->nlen + state->ndist) {
+                for (;;) {
+                    this = state->lencode[BITS(state->lenbits)];
+                    if ((unsigned)(this.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                if (this.val < 16) {
+                    NEEDBITS(this.bits);
+                    DROPBITS(this.bits);
+                    state->lens[state->have++] = this.val;
+                }
+                else {
+                    if (this.val == 16) {
+                        NEEDBITS(this.bits + 2);
+                        DROPBITS(this.bits);
+                        if (state->have == 0) {
+                            strm->msg = (char *)"invalid bit length repeat";
+                            state->mode = BAD;
+                            break;
+                        }
+                        len = (unsigned)(state->lens[state->have - 1]);
+                        copy = 3 + BITS(2);
+                        DROPBITS(2);
+                    }
+                    else if (this.val == 17) {
+                        NEEDBITS(this.bits + 3);
+                        DROPBITS(this.bits);
+                        len = 0;
+                        copy = 3 + BITS(3);
+                        DROPBITS(3);
+                    }
+                    else {
+                        NEEDBITS(this.bits + 7);
+                        DROPBITS(this.bits);
+                        len = 0;
+                        copy = 11 + BITS(7);
+                        DROPBITS(7);
+                    }
+                    if (state->have + copy > state->nlen + state->ndist) {
+                        strm->msg = (char *)"invalid bit length repeat";
+                        state->mode = BAD;
+                        break;
+                    }
+                    while (copy--)
+                        state->lens[state->have++] = (unsigned short)len;
+                }
+            }
+
+            /* handle error breaks in while */
+            if (state->mode == BAD) break;
+
+            /* build code tables */
+            state->next = state->codes;
+            state->lencode = (code const FAR *)(state->next);
+            state->lenbits = 9;
+            ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid literal/lengths set";
+                state->mode = BAD;
+                break;
+            }
+            state->distcode = (code const FAR *)(state->next);
+            state->distbits = 6;
+            ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+                            &(state->next), &(state->distbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid distances set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       codes ok\n"));
+            state->mode = LEN;
+
+        case LEN:
+            /* use inflate_fast() if we have enough input and output */
+            if (have >= 6 && left >= 258) {
+                RESTORE();
+                if (state->whave < state->wsize)
+                    state->whave = state->wsize - left;
+                inflate_fast(strm, state->wsize);
+                LOAD();
+                break;
+            }
+
+            /* get a literal, length, or end-of-block code */
+            for (;;) {
+                this = state->lencode[BITS(state->lenbits)];
+                if ((unsigned)(this.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if (this.op && (this.op & 0xf0) == 0) {
+                last = this;
+                for (;;) {
+                    this = state->lencode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + this.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+            }
+            DROPBITS(this.bits);
+            state->length = (unsigned)this.val;
+
+            /* process literal */
+            if (this.op == 0) {
+                Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+                        "inflate:         literal '%c'\n" :
+                        "inflate:         literal 0x%02x\n", this.val));
+                ROOM();
+                *put++ = (unsigned char)(state->length);
+                left--;
+                state->mode = LEN;
+                break;
+            }
+
+            /* process end of block */
+            if (this.op & 32) {
+                Tracevv((stderr, "inflate:         end of block\n"));
+                state->mode = TYPE;
+                break;
+            }
+
+            /* invalid code */
+            if (this.op & 64) {
+                strm->msg = (char *)"invalid literal/length code";
+                state->mode = BAD;
+                break;
+            }
+
+            /* length code -- get extra bits, if any */
+            state->extra = (unsigned)(this.op) & 15;
+            if (state->extra != 0) {
+                NEEDBITS(state->extra);
+                state->length += BITS(state->extra);
+                DROPBITS(state->extra);
+            }
+            Tracevv((stderr, "inflate:         length %u\n", state->length));
+
+            /* get distance code */
+            for (;;) {
+                this = state->distcode[BITS(state->distbits)];
+                if ((unsigned)(this.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if ((this.op & 0xf0) == 0) {
+                last = this;
+                for (;;) {
+                    this = state->distcode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + this.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+            }
+            DROPBITS(this.bits);
+            if (this.op & 64) {
+                strm->msg = (char *)"invalid distance code";
+                state->mode = BAD;
+                break;
+            }
+            state->offset = (unsigned)this.val;
+
+            /* get distance extra bits, if any */
+            state->extra = (unsigned)(this.op) & 15;
+            if (state->extra != 0) {
+                NEEDBITS(state->extra);
+                state->offset += BITS(state->extra);
+                DROPBITS(state->extra);
+            }
+            if (state->offset > state->wsize - (state->whave < state->wsize ?
+                                                left : 0)) {
+                strm->msg = (char *)"invalid distance too far back";
+                state->mode = BAD;
+                break;
+            }
+            Tracevv((stderr, "inflate:         distance %u\n", state->offset));
+
+            /* copy match from window to output */
+            do {
+                ROOM();
+                copy = state->wsize - state->offset;
+                if (copy < left) {
+                    from = put + copy;
+                    copy = left - copy;
+                }
+                else {
+                    from = put - state->offset;
+                    copy = left;
+                }
+                if (copy > state->length) copy = state->length;
+                state->length -= copy;
+                left -= copy;
+                do {
+                    *put++ = *from++;
+                } while (--copy);
+            } while (state->length != 0);
+            break;
+
+        case DONE:
+            /* inflate stream terminated properly -- write leftover output */
+            ret = Z_STREAM_END;
+            if (left < state->wsize) {
+                if (out(out_desc, state->window, state->wsize - left))
+                    ret = Z_BUF_ERROR;
+            }
+            goto inf_leave;
+
+        case BAD:
+            ret = Z_DATA_ERROR;
+            goto inf_leave;
+
+        default:                /* can't happen, but makes compilers happy */
+            ret = Z_STREAM_ERROR;
+            goto inf_leave;
+        }
+
+    /* Return unused input */
+  inf_leave:
+    strm->next_in = next;
+    strm->avail_in = have;
+    return ret;
+}
+
+int ZEXPORT inflateBackEnd(strm)
+z_streamp strm;
+{
+    if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+        return Z_STREAM_ERROR;
+    ZFREE(strm, strm->state);
+    strm->state = Z_NULL;
+    Tracev((stderr, "inflate: end\n"));
+    return Z_OK;
+}
diff --git a/src/unison/physfs-1.1.1/zlib123/inffast.c b/src/unison/physfs-1.1.1/zlib123/inffast.c
new file mode 100644 (file)
index 0000000..bbee92e
--- /dev/null
@@ -0,0 +1,318 @@
+/* inffast.c -- fast decoding
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifndef ASMINF
+
+/* Allow machine dependent optimization for post-increment or pre-increment.
+   Based on testing to date,
+   Pre-increment preferred for:
+   - PowerPC G3 (Adler)
+   - MIPS R5000 (Randers-Pehrson)
+   Post-increment preferred for:
+   - none
+   No measurable difference:
+   - Pentium III (Anderson)
+   - M68060 (Nikl)
+ */
+#ifdef POSTINC
+#  define OFF 0
+#  define PUP(a) *(a)++
+#else
+#  define OFF 1
+#  define PUP(a) *++(a)
+#endif
+
+/*
+   Decode literal, length, and distance codes and write out the resulting
+   literal and match bytes until either not enough input or output is
+   available, an end-of-block is encountered, or a data error is encountered.
+   When large enough input and output buffers are supplied to inflate(), for
+   example, a 16K input buffer and a 64K output buffer, more than 95% of the
+   inflate execution time is spent in this routine.
+
+   Entry assumptions:
+
+        state->mode == LEN
+        strm->avail_in >= 6
+        strm->avail_out >= 258
+        start >= strm->avail_out
+        state->bits < 8
+
+   On return, state->mode is one of:
+
+        LEN -- ran out of enough output space or enough available input
+        TYPE -- reached end of block code, inflate() to interpret next block
+        BAD -- error in block data
+
+   Notes:
+
+    - The maximum input bits used by a length/distance pair is 15 bits for the
+      length code, 5 bits for the length extra, 15 bits for the distance code,
+      and 13 bits for the distance extra.  This totals 48 bits, or six bytes.
+      Therefore if strm->avail_in >= 6, then there is enough input to avoid
+      checking for available input while decoding.
+
+    - The maximum bytes that a single length/distance pair can output is 258
+      bytes, which is the maximum length that can be coded.  inflate_fast()
+      requires strm->avail_out >= 258 for each loop to avoid checking for
+      output space.
+ */
+void inflate_fast(strm, start)
+z_streamp strm;
+unsigned start;         /* inflate()'s starting value for strm->avail_out */
+{
+    struct inflate_state FAR *state;
+    unsigned char FAR *in;      /* local strm->next_in */
+    unsigned char FAR *last;    /* while in < last, enough input available */
+    unsigned char FAR *out;     /* local strm->next_out */
+    unsigned char FAR *beg;     /* inflate()'s initial strm->next_out */
+    unsigned char FAR *end;     /* while out < end, enough space available */
+#ifdef INFLATE_STRICT
+    unsigned dmax;              /* maximum distance from zlib header */
+#endif
+    unsigned wsize;             /* window size or zero if not using window */
+    unsigned whave;             /* valid bytes in the window */
+    unsigned write;             /* window write index */
+    unsigned char FAR *window;  /* allocated sliding window, if wsize != 0 */
+    unsigned long hold;         /* local strm->hold */
+    unsigned bits;              /* local strm->bits */
+    code const FAR *lcode;      /* local strm->lencode */
+    code const FAR *dcode;      /* local strm->distcode */
+    unsigned lmask;             /* mask for first level of length codes */
+    unsigned dmask;             /* mask for first level of distance codes */
+    code this;                  /* retrieved table entry */
+    unsigned op;                /* code bits, operation, extra bits, or */
+                                /*  window position, window bytes to copy */
+    unsigned len;               /* match length, unused bytes */
+    unsigned dist;              /* match distance */
+    unsigned char FAR *from;    /* where to copy match from */
+
+    /* copy state to local variables */
+    state = (struct inflate_state FAR *)strm->state;
+    in = strm->next_in - OFF;
+    last = in + (strm->avail_in - 5);
+    out = strm->next_out - OFF;
+    beg = out - (start - strm->avail_out);
+    end = out + (strm->avail_out - 257);
+#ifdef INFLATE_STRICT
+    dmax = state->dmax;
+#endif
+    wsize = state->wsize;
+    whave = state->whave;
+    write = state->write;
+    window = state->window;
+    hold = state->hold;
+    bits = state->bits;
+    lcode = state->lencode;
+    dcode = state->distcode;
+    lmask = (1U << state->lenbits) - 1;
+    dmask = (1U << state->distbits) - 1;
+
+    /* decode literals and length/distances until end-of-block or not enough
+       input data or output space */
+    do {
+        if (bits < 15) {
+            hold += (unsigned long)(PUP(in)) << bits;
+            bits += 8;
+            hold += (unsigned long)(PUP(in)) << bits;
+            bits += 8;
+        }
+        this = lcode[hold & lmask];
+      dolen:
+        op = (unsigned)(this.bits);
+        hold >>= op;
+        bits -= op;
+        op = (unsigned)(this.op);
+        if (op == 0) {                          /* literal */
+            Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+                    "inflate:         literal '%c'\n" :
+                    "inflate:         literal 0x%02x\n", this.val));
+            PUP(out) = (unsigned char)(this.val);
+        }
+        else if (op & 16) {                     /* length base */
+            len = (unsigned)(this.val);
+            op &= 15;                           /* number of extra bits */
+            if (op) {
+                if (bits < op) {
+                    hold += (unsigned long)(PUP(in)) << bits;
+                    bits += 8;
+                }
+                len += (unsigned)hold & ((1U << op) - 1);
+                hold >>= op;
+                bits -= op;
+            }
+            Tracevv((stderr, "inflate:         length %u\n", len));
+            if (bits < 15) {
+                hold += (unsigned long)(PUP(in)) << bits;
+                bits += 8;
+                hold += (unsigned long)(PUP(in)) << bits;
+                bits += 8;
+            }
+            this = dcode[hold & dmask];
+          dodist:
+            op = (unsigned)(this.bits);
+            hold >>= op;
+            bits -= op;
+            op = (unsigned)(this.op);
+            if (op & 16) {                      /* distance base */
+                dist = (unsigned)(this.val);
+                op &= 15;                       /* number of extra bits */
+                if (bits < op) {
+                    hold += (unsigned long)(PUP(in)) << bits;
+                    bits += 8;
+                    if (bits < op) {
+                        hold += (unsigned long)(PUP(in)) << bits;
+                        bits += 8;
+                    }
+                }
+                dist += (unsigned)hold & ((1U << op) - 1);
+#ifdef INFLATE_STRICT
+                if (dist > dmax) {
+                    strm->msg = (char *)"invalid distance too far back";
+                    state->mode = BAD;
+                    break;
+                }
+#endif
+                hold >>= op;
+                bits -= op;
+                Tracevv((stderr, "inflate:         distance %u\n", dist));
+                op = (unsigned)(out - beg);     /* max distance in output */
+                if (dist > op) {                /* see if copy from window */
+                    op = dist - op;             /* distance back in window */
+                    if (op > whave) {
+                        strm->msg = (char *)"invalid distance too far back";
+                        state->mode = BAD;
+                        break;
+                    }
+                    from = window - OFF;
+                    if (write == 0) {           /* very common case */
+                        from += wsize - op;
+                        if (op < len) {         /* some from window */
+                            len -= op;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--op);
+                            from = out - dist;  /* rest from output */
+                        }
+                    }
+                    else if (write < op) {      /* wrap around window */
+                        from += wsize + write - op;
+                        op -= write;
+                        if (op < len) {         /* some from end of window */
+                            len -= op;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--op);
+                            from = window - OFF;
+                            if (write < len) {  /* some from start of window */
+                                op = write;
+                                len -= op;
+                                do {
+                                    PUP(out) = PUP(from);
+                                } while (--op);
+                                from = out - dist;      /* rest from output */
+                            }
+                        }
+                    }
+                    else {                      /* contiguous in window */
+                        from += write - op;
+                        if (op < len) {         /* some from window */
+                            len -= op;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--op);
+                            from = out - dist;  /* rest from output */
+                        }
+                    }
+                    while (len > 2) {
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        len -= 3;
+                    }
+                    if (len) {
+                        PUP(out) = PUP(from);
+                        if (len > 1)
+                            PUP(out) = PUP(from);
+                    }
+                }
+                else {
+                    from = out - dist;          /* copy direct from output */
+                    do {                        /* minimum length is three */
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        len -= 3;
+                    } while (len > 2);
+                    if (len) {
+                        PUP(out) = PUP(from);
+                        if (len > 1)
+                            PUP(out) = PUP(from);
+                    }
+                }
+            }
+            else if ((op & 64) == 0) {          /* 2nd level distance code */
+                this = dcode[this.val + (hold & ((1U << op) - 1))];
+                goto dodist;
+            }
+            else {
+                strm->msg = (char *)"invalid distance code";
+                state->mode = BAD;
+                break;
+            }
+        }
+        else if ((op & 64) == 0) {              /* 2nd level length code */
+            this = lcode[this.val + (hold & ((1U << op) - 1))];
+            goto dolen;
+        }
+        else if (op & 32) {                     /* end-of-block */
+            Tracevv((stderr, "inflate:         end of block\n"));
+            state->mode = TYPE;
+            break;
+        }
+        else {
+            strm->msg = (char *)"invalid literal/length code";
+            state->mode = BAD;
+            break;
+        }
+    } while (in < last && out < end);
+
+    /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+    len = bits >> 3;
+    in -= len;
+    bits -= len << 3;
+    hold &= (1U << bits) - 1;
+
+    /* update state and return */
+    strm->next_in = in + OFF;
+    strm->next_out = out + OFF;
+    strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
+    strm->avail_out = (unsigned)(out < end ?
+                                 257 + (end - out) : 257 - (out - end));
+    state->hold = hold;
+    state->bits = bits;
+    return;
+}
+
+/*
+   inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
+   - Using bit fields for code structure
+   - Different op definition to avoid & for extra bits (do & for table bits)
+   - Three separate decoding do-loops for direct, window, and write == 0
+   - Special case for distance > 1 copies to do overlapped load and store copy
+   - Explicit branch predictions (based on measured branch probabilities)
+   - Deferring match copy and interspersed it with decoding subsequent codes
+   - Swapping literal/length else
+   - Swapping window/direct else
+   - Larger unrolled copy loops (three is about right)
+   - Moving len -= 3 statement into middle of loop
+ */
+
+#endif /* !ASMINF */
diff --git a/src/unison/physfs-1.1.1/zlib123/inffast.h b/src/unison/physfs-1.1.1/zlib123/inffast.h
new file mode 100644 (file)
index 0000000..1e88d2d
--- /dev/null
@@ -0,0 +1,11 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+void inflate_fast OF((z_streamp strm, unsigned start));
diff --git a/src/unison/physfs-1.1.1/zlib123/inffixed.h b/src/unison/physfs-1.1.1/zlib123/inffixed.h
new file mode 100644 (file)
index 0000000..75ed4b5
--- /dev/null
@@ -0,0 +1,94 @@
+    /* inffixed.h -- table for decoding fixed codes
+     * Generated automatically by makefixed().
+     */
+
+    /* WARNING: this file should *not* be used by applications. It
+       is part of the implementation of the compression library and
+       is subject to change. Applications should only use zlib.h.
+     */
+
+    static const code lenfix[512] = {
+        {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
+        {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
+        {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
+        {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
+        {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
+        {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
+        {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
+        {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
+        {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
+        {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
+        {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
+        {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
+        {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
+        {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
+        {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
+        {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
+        {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
+        {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
+        {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
+        {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
+        {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
+        {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
+        {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
+        {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
+        {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
+        {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
+        {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
+        {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
+        {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
+        {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
+        {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
+        {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
+        {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
+        {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
+        {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
+        {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
+        {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
+        {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
+        {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
+        {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
+        {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
+        {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
+        {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
+        {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
+        {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
+        {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
+        {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
+        {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
+        {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
+        {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
+        {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
+        {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
+        {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
+        {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
+        {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
+        {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
+        {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
+        {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
+        {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
+        {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
+        {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
+        {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
+        {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
+        {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
+        {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
+        {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
+        {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
+        {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
+        {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
+        {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
+        {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
+        {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
+        {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
+        {0,9,255}
+    };
+
+    static const code distfix[32] = {
+        {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
+        {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
+        {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
+        {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
+        {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
+        {22,5,193},{64,5,0}
+    };
diff --git a/src/unison/physfs-1.1.1/zlib123/inflate.c b/src/unison/physfs-1.1.1/zlib123/inflate.c
new file mode 100644 (file)
index 0000000..792fdee
--- /dev/null
@@ -0,0 +1,1368 @@
+/* inflate.c -- zlib decompression
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * Change history:
+ *
+ * 1.2.beta0    24 Nov 2002
+ * - First version -- complete rewrite of inflate to simplify code, avoid
+ *   creation of window when not needed, minimize use of window when it is
+ *   needed, make inffast.c even faster, implement gzip decoding, and to
+ *   improve code readability and style over the previous zlib inflate code
+ *
+ * 1.2.beta1    25 Nov 2002
+ * - Use pointers for available input and output checking in inffast.c
+ * - Remove input and output counters in inffast.c
+ * - Change inffast.c entry and loop from avail_in >= 7 to >= 6
+ * - Remove unnecessary second byte pull from length extra in inffast.c
+ * - Unroll direct copy to three copies per loop in inffast.c
+ *
+ * 1.2.beta2    4 Dec 2002
+ * - Change external routine names to reduce potential conflicts
+ * - Correct filename to inffixed.h for fixed tables in inflate.c
+ * - Make hbuf[] unsigned char to match parameter type in inflate.c
+ * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset)
+ *   to avoid negation problem on Alphas (64 bit) in inflate.c
+ *
+ * 1.2.beta3    22 Dec 2002
+ * - Add comments on state->bits assertion in inffast.c
+ * - Add comments on op field in inftrees.h
+ * - Fix bug in reuse of allocated window after inflateReset()
+ * - Remove bit fields--back to byte structure for speed
+ * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths
+ * - Change post-increments to pre-increments in inflate_fast(), PPC biased?
+ * - Add compile time option, POSTINC, to use post-increments instead (Intel?)
+ * - Make MATCH copy in inflate() much faster for when inflate_fast() not used
+ * - Use local copies of stream next and avail values, as well as local bit
+ *   buffer and bit count in inflate()--for speed when inflate_fast() not used
+ *
+ * 1.2.beta4    1 Jan 2003
+ * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings
+ * - Move a comment on output buffer sizes from inffast.c to inflate.c
+ * - Add comments in inffast.c to introduce the inflate_fast() routine
+ * - Rearrange window copies in inflate_fast() for speed and simplification
+ * - Unroll last copy for window match in inflate_fast()
+ * - Use local copies of window variables in inflate_fast() for speed
+ * - Pull out common write == 0 case for speed in inflate_fast()
+ * - Make op and len in inflate_fast() unsigned for consistency
+ * - Add FAR to lcode and dcode declarations in inflate_fast()
+ * - Simplified bad distance check in inflate_fast()
+ * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new
+ *   source file infback.c to provide a call-back interface to inflate for
+ *   programs like gzip and unzip -- uses window as output buffer to avoid
+ *   window copying
+ *
+ * 1.2.beta5    1 Jan 2003
+ * - Improved inflateBack() interface to allow the caller to provide initial
+ *   input in strm.
+ * - Fixed stored blocks bug in inflateBack()
+ *
+ * 1.2.beta6    4 Jan 2003
+ * - Added comments in inffast.c on effectiveness of POSTINC
+ * - Typecasting all around to reduce compiler warnings
+ * - Changed loops from while (1) or do {} while (1) to for (;;), again to
+ *   make compilers happy
+ * - Changed type of window in inflateBackInit() to unsigned char *
+ *
+ * 1.2.beta7    27 Jan 2003
+ * - Changed many types to unsigned or unsigned short to avoid warnings
+ * - Added inflateCopy() function
+ *
+ * 1.2.0        9 Mar 2003
+ * - Changed inflateBack() interface to provide separate opaque descriptors
+ *   for the in() and out() functions
+ * - Changed inflateBack() argument and in_func typedef to swap the length
+ *   and buffer address return values for the input function
+ * - Check next_in and next_out for Z_NULL on entry to inflate()
+ *
+ * The history for versions after 1.2.0 are in ChangeLog in zlib distribution.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifdef MAKEFIXED
+#  ifndef BUILDFIXED
+#    define BUILDFIXED
+#  endif
+#endif
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+local int updatewindow OF((z_streamp strm, unsigned out));
+#ifdef BUILDFIXED
+   void makefixed OF((void));
+#endif
+local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf,
+                              unsigned len));
+
+int ZEXPORT inflateReset(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    strm->total_in = strm->total_out = state->total = 0;
+    strm->msg = Z_NULL;
+    strm->adler = 1;        /* to support ill-conceived Java test suite */
+    state->mode = HEAD;
+    state->last = 0;
+    state->havedict = 0;
+    state->dmax = 32768U;
+    state->head = Z_NULL;
+    state->wsize = 0;
+    state->whave = 0;
+    state->write = 0;
+    state->hold = 0;
+    state->bits = 0;
+    state->lencode = state->distcode = state->next = state->codes;
+    Tracev((stderr, "inflate: reset\n"));
+    return Z_OK;
+}
+
+int ZEXPORT inflatePrime(strm, bits, value)
+z_streamp strm;
+int bits;
+int value;
+{
+    struct inflate_state FAR *state;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR;
+    value &= (1L << bits) - 1;
+    state->hold += value << state->bits;
+    state->bits += bits;
+    return Z_OK;
+}
+
+int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)
+z_streamp strm;
+int windowBits;
+const char *version;
+int stream_size;
+{
+    struct inflate_state FAR *state;
+
+    if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+        stream_size != (int)(sizeof(z_stream)))
+        return Z_VERSION_ERROR;
+    if (strm == Z_NULL) return Z_STREAM_ERROR;
+    strm->msg = Z_NULL;                 /* in case we return an error */
+    if (strm->zalloc == (alloc_func)0) {
+        strm->zalloc = zcalloc;
+        strm->opaque = (voidpf)0;
+    }
+    if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+    state = (struct inflate_state FAR *)
+            ZALLOC(strm, 1, sizeof(struct inflate_state));
+    if (state == Z_NULL) return Z_MEM_ERROR;
+    Tracev((stderr, "inflate: allocated\n"));
+    strm->state = (struct internal_state FAR *)state;
+    if (windowBits < 0) {
+        state->wrap = 0;
+        windowBits = -windowBits;
+    }
+    else {
+        state->wrap = (windowBits >> 4) + 1;
+#ifdef GUNZIP
+        if (windowBits < 48) windowBits &= 15;
+#endif
+    }
+    if (windowBits < 8 || windowBits > 15) {
+        ZFREE(strm, state);
+        strm->state = Z_NULL;
+        return Z_STREAM_ERROR;
+    }
+    state->wbits = (unsigned)windowBits;
+    state->window = Z_NULL;
+    return inflateReset(strm);
+}
+
+int ZEXPORT inflateInit_(strm, version, stream_size)
+z_streamp strm;
+const char *version;
+int stream_size;
+{
+    return inflateInit2_(strm, DEF_WBITS, version, stream_size);
+}
+
+/*
+   Return state with length and distance decoding tables and index sizes set to
+   fixed code decoding.  Normally this returns fixed tables from inffixed.h.
+   If BUILDFIXED is defined, then instead this routine builds the tables the
+   first time it's called, and returns those tables the first time and
+   thereafter.  This reduces the size of the code by about 2K bytes, in
+   exchange for a little execution time.  However, BUILDFIXED should not be
+   used for threaded applications, since the rewriting of the tables and virgin
+   may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+    static int virgin = 1;
+    static code *lenfix, *distfix;
+    static code fixed[544];
+
+    /* build fixed huffman tables if first call (may not be thread safe) */
+    if (virgin) {
+        unsigned sym, bits;
+        static code *next;
+
+        /* literal/length table */
+        sym = 0;
+        while (sym < 144) state->lens[sym++] = 8;
+        while (sym < 256) state->lens[sym++] = 9;
+        while (sym < 280) state->lens[sym++] = 7;
+        while (sym < 288) state->lens[sym++] = 8;
+        next = fixed;
+        lenfix = next;
+        bits = 9;
+        inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+        /* distance table */
+        sym = 0;
+        while (sym < 32) state->lens[sym++] = 5;
+        distfix = next;
+        bits = 5;
+        inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+        /* do this just once */
+        virgin = 0;
+    }
+#else /* !BUILDFIXED */
+#   include "inffixed.h"
+#endif /* BUILDFIXED */
+    state->lencode = lenfix;
+    state->lenbits = 9;
+    state->distcode = distfix;
+    state->distbits = 5;
+}
+
+#ifdef MAKEFIXED
+#include <stdio.h>
+
+/*
+   Write out the inffixed.h that is #include'd above.  Defining MAKEFIXED also
+   defines BUILDFIXED, so the tables are built on the fly.  makefixed() writes
+   those tables to stdout, which would be piped to inffixed.h.  A small program
+   can simply call makefixed to do this:
+
+    void makefixed(void);
+
+    int main(void)
+    {
+        makefixed();
+        return 0;
+    }
+
+   Then that can be linked with zlib built with MAKEFIXED defined and run:
+
+    a.out > inffixed.h
+ */
+void makefixed()
+{
+    unsigned low, size;
+    struct inflate_state state;
+
+    fixedtables(&state);
+    puts("    /* inffixed.h -- table for decoding fixed codes");
+    puts("     * Generated automatically by makefixed().");
+    puts("     */");
+    puts("");
+    puts("    /* WARNING: this file should *not* be used by applications.");
+    puts("       It is part of the implementation of this library and is");
+    puts("       subject to change. Applications should only use zlib.h.");
+    puts("     */");
+    puts("");
+    size = 1U << 9;
+    printf("    static const code lenfix[%u] = {", size);
+    low = 0;
+    for (;;) {
+        if ((low % 7) == 0) printf("\n        ");
+        printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits,
+               state.lencode[low].val);
+        if (++low == size) break;
+        putchar(',');
+    }
+    puts("\n    };");
+    size = 1U << 5;
+    printf("\n    static const code distfix[%u] = {", size);
+    low = 0;
+    for (;;) {
+        if ((low % 6) == 0) printf("\n        ");
+        printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,
+               state.distcode[low].val);
+        if (++low == size) break;
+        putchar(',');
+    }
+    puts("\n    };");
+}
+#endif /* MAKEFIXED */
+
+/*
+   Update the window with the last wsize (normally 32K) bytes written before
+   returning.  If window does not exist yet, create it.  This is only called
+   when a window is already in use, or when output has been written during this
+   inflate call, but the end of the deflate stream has not been reached yet.
+   It is also called to create a window for dictionary data when a dictionary
+   is loaded.
+
+   Providing output buffers larger than 32K to inflate() should provide a speed
+   advantage, since only the last 32K of output is copied to the sliding window
+   upon return from inflate(), and since all distances after the first 32K of
+   output will fall in the output data, making match copies simpler and faster.
+   The advantage may be dependent on the size of the processor's data caches.
+ */
+local int updatewindow(strm, out)
+z_streamp strm;
+unsigned out;
+{
+    struct inflate_state FAR *state;
+    unsigned copy, dist;
+
+    state = (struct inflate_state FAR *)strm->state;
+
+    /* if it hasn't been done already, allocate space for the window */
+    if (state->window == Z_NULL) {
+        state->window = (unsigned char FAR *)
+                        ZALLOC(strm, 1U << state->wbits,
+                               sizeof(unsigned char));
+        if (state->window == Z_NULL) return 1;
+    }
+
+    /* if window not in use yet, initialize */
+    if (state->wsize == 0) {
+        state->wsize = 1U << state->wbits;
+        state->write = 0;
+        state->whave = 0;
+    }
+
+    /* copy state->wsize or less output bytes into the circular window */
+    copy = out - strm->avail_out;
+    if (copy >= state->wsize) {
+        zmemcpy(state->window, strm->next_out - state->wsize, state->wsize);
+        state->write = 0;
+        state->whave = state->wsize;
+    }
+    else {
+        dist = state->wsize - state->write;
+        if (dist > copy) dist = copy;
+        zmemcpy(state->window + state->write, strm->next_out - copy, dist);
+        copy -= dist;
+        if (copy) {
+            zmemcpy(state->window, strm->next_out - copy, copy);
+            state->write = copy;
+            state->whave = state->wsize;
+        }
+        else {
+            state->write += dist;
+            if (state->write == state->wsize) state->write = 0;
+            if (state->whave < state->wsize) state->whave += dist;
+        }
+    }
+    return 0;
+}
+
+/* Macros for inflate(): */
+
+/* check function to use adler32() for zlib or crc32() for gzip */
+#ifdef GUNZIP
+#  define UPDATE(check, buf, len) \
+    (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
+#else
+#  define UPDATE(check, buf, len) adler32(check, buf, len)
+#endif
+
+/* check macros for header crc */
+#ifdef GUNZIP
+#  define CRC2(check, word) \
+    do { \
+        hbuf[0] = (unsigned char)(word); \
+        hbuf[1] = (unsigned char)((word) >> 8); \
+        check = crc32(check, hbuf, 2); \
+    } while (0)
+
+#  define CRC4(check, word) \
+    do { \
+        hbuf[0] = (unsigned char)(word); \
+        hbuf[1] = (unsigned char)((word) >> 8); \
+        hbuf[2] = (unsigned char)((word) >> 16); \
+        hbuf[3] = (unsigned char)((word) >> 24); \
+        check = crc32(check, hbuf, 4); \
+    } while (0)
+#endif
+
+/* Load registers with state in inflate() for speed */
+#define LOAD() \
+    do { \
+        put = strm->next_out; \
+        left = strm->avail_out; \
+        next = strm->next_in; \
+        have = strm->avail_in; \
+        hold = state->hold; \
+        bits = state->bits; \
+    } while (0)
+
+/* Restore state from registers in inflate() */
+#define RESTORE() \
+    do { \
+        strm->next_out = put; \
+        strm->avail_out = left; \
+        strm->next_in = next; \
+        strm->avail_in = have; \
+        state->hold = hold; \
+        state->bits = bits; \
+    } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+    do { \
+        hold = 0; \
+        bits = 0; \
+    } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflate()
+   if there is no input available. */
+#define PULLBYTE() \
+    do { \
+        if (have == 0) goto inf_leave; \
+        have--; \
+        hold += (unsigned long)(*next++) << bits; \
+        bits += 8; \
+    } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator.  If there is
+   not enough available input to do that, then return from inflate(). */
+#define NEEDBITS(n) \
+    do { \
+        while (bits < (unsigned)(n)) \
+            PULLBYTE(); \
+    } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+    ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+    do { \
+        hold >>= (n); \
+        bits -= (unsigned)(n); \
+    } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+    do { \
+        hold >>= bits & 7; \
+        bits -= bits & 7; \
+    } while (0)
+
+/* Reverse the bytes in a 32-bit value */
+#define REVERSE(q) \
+    ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
+     (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
+
+/*
+   inflate() uses a state machine to process as much input data and generate as
+   much output data as possible before returning.  The state machine is
+   structured roughly as follows:
+
+    for (;;) switch (state) {
+    ...
+    case STATEn:
+        if (not enough input data or output space to make progress)
+            return;
+        ... make progress ...
+        state = STATEm;
+        break;
+    ...
+    }
+
+   so when inflate() is called again, the same case is attempted again, and
+   if the appropriate resources are provided, the machine proceeds to the
+   next state.  The NEEDBITS() macro is usually the way the state evaluates
+   whether it can proceed or should return.  NEEDBITS() does the return if
+   the requested bits are not available.  The typical use of the BITS macros
+   is:
+
+        NEEDBITS(n);
+        ... do something with BITS(n) ...
+        DROPBITS(n);
+
+   where NEEDBITS(n) either returns from inflate() if there isn't enough
+   input left to load n bits into the accumulator, or it continues.  BITS(n)
+   gives the low n bits in the accumulator.  When done, DROPBITS(n) drops
+   the low n bits off the accumulator.  INITBITS() clears the accumulator
+   and sets the number of available bits to zero.  BYTEBITS() discards just
+   enough bits to put the accumulator on a byte boundary.  After BYTEBITS()
+   and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
+
+   NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
+   if there is no input available.  The decoding of variable length codes uses
+   PULLBYTE() directly in order to pull just enough bytes to decode the next
+   code, and no more.
+
+   Some states loop until they get enough input, making sure that enough
+   state information is maintained to continue the loop where it left off
+   if NEEDBITS() returns in the loop.  For example, want, need, and keep
+   would all have to actually be part of the saved state in case NEEDBITS()
+   returns:
+
+    case STATEw:
+        while (want < need) {
+            NEEDBITS(n);
+            keep[want++] = BITS(n);
+            DROPBITS(n);
+        }
+        state = STATEx;
+    case STATEx:
+
+   As shown above, if the next state is also the next case, then the break
+   is omitted.
+
+   A state may also return if there is not enough output space available to
+   complete that state.  Those states are copying stored data, writing a
+   literal byte, and copying a matching string.
+
+   When returning, a "goto inf_leave" is used to update the total counters,
+   update the check value, and determine whether any progress has been made
+   during that inflate() call in order to return the proper return code.
+   Progress is defined as a change in either strm->avail_in or strm->avail_out.
+   When there is a window, goto inf_leave will update the window with the last
+   output written.  If a goto inf_leave occurs in the middle of decompression
+   and there is no window currently, goto inf_leave will create one and copy
+   output to the window for the next call of inflate().
+
+   In this implementation, the flush parameter of inflate() only affects the
+   return code (per zlib.h).  inflate() always writes as much as possible to
+   strm->next_out, given the space available and the provided input--the effect
+   documented in zlib.h of Z_SYNC_FLUSH.  Furthermore, inflate() always defers
+   the allocation of and copying into a sliding window until necessary, which
+   provides the effect documented in zlib.h for Z_FINISH when the entire input
+   stream available.  So the only thing the flush parameter actually does is:
+   when flush is set to Z_FINISH, inflate() cannot return Z_OK.  Instead it
+   will return Z_BUF_ERROR if it has not reached the end of the stream.
+ */
+
+int ZEXPORT inflate(strm, flush)
+z_streamp strm;
+int flush;
+{
+    struct inflate_state FAR *state;
+    unsigned char FAR *next;    /* next input */
+    unsigned char FAR *put;     /* next output */
+    unsigned have, left;        /* available input and output */
+    unsigned long hold;         /* bit buffer */
+    unsigned bits;              /* bits in bit buffer */
+    unsigned in, out;           /* save starting available input and output */
+    unsigned copy;              /* number of stored or match bytes to copy */
+    unsigned char FAR *from;    /* where to copy match bytes from */
+    code this;                  /* current decoding table entry */
+    code last;                  /* parent table entry */
+    unsigned len;               /* length to copy for repeats, bits to drop */
+    int ret;                    /* return code */
+#ifdef GUNZIP
+    unsigned char hbuf[4];      /* buffer for gzip header crc calculation */
+#endif
+    static const unsigned short order[19] = /* permutation of code lengths */
+        {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+    if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL ||
+        (strm->next_in == Z_NULL && strm->avail_in != 0))
+        return Z_STREAM_ERROR;
+
+    state = (struct inflate_state FAR *)strm->state;
+    if (state->mode == TYPE) state->mode = TYPEDO;      /* skip check */
+    LOAD();
+    in = have;
+    out = left;
+    ret = Z_OK;
+    for (;;)
+        switch (state->mode) {
+        case HEAD:
+            if (state->wrap == 0) {
+                state->mode = TYPEDO;
+                break;
+            }
+            NEEDBITS(16);
+#ifdef GUNZIP
+            if ((state->wrap & 2) && hold == 0x8b1f) {  /* gzip header */
+                state->check = crc32(0L, Z_NULL, 0);
+                CRC2(state->check, hold);
+                INITBITS();
+                state->mode = FLAGS;
+                break;
+            }
+            state->flags = 0;           /* expect zlib header */
+            if (state->head != Z_NULL)
+                state->head->done = -1;
+            if (!(state->wrap & 1) ||   /* check if zlib header allowed */
+#else
+            if (
+#endif
+                ((BITS(8) << 8) + (hold >> 8)) % 31) {
+                strm->msg = (char *)"incorrect header check";
+                state->mode = BAD;
+                break;
+            }
+            if (BITS(4) != Z_DEFLATED) {
+                strm->msg = (char *)"unknown compression method";
+                state->mode = BAD;
+                break;
+            }
+            DROPBITS(4);
+            len = BITS(4) + 8;
+            if (len > state->wbits) {
+                strm->msg = (char *)"invalid window size";
+                state->mode = BAD;
+                break;
+            }
+            state->dmax = 1U << len;
+            Tracev((stderr, "inflate:   zlib header ok\n"));
+            strm->adler = state->check = adler32(0L, Z_NULL, 0);
+            state->mode = hold & 0x200 ? DICTID : TYPE;
+            INITBITS();
+            break;
+#ifdef GUNZIP
+        case FLAGS:
+            NEEDBITS(16);
+            state->flags = (int)(hold);
+            if ((state->flags & 0xff) != Z_DEFLATED) {
+                strm->msg = (char *)"unknown compression method";
+                state->mode = BAD;
+                break;
+            }
+            if (state->flags & 0xe000) {
+                strm->msg = (char *)"unknown header flags set";
+                state->mode = BAD;
+                break;
+            }
+            if (state->head != Z_NULL)
+                state->head->text = (int)((hold >> 8) & 1);
+            if (state->flags & 0x0200) CRC2(state->check, hold);
+            INITBITS();
+            state->mode = TIME;
+        case TIME:
+            NEEDBITS(32);
+            if (state->head != Z_NULL)
+                state->head->time = hold;
+            if (state->flags & 0x0200) CRC4(state->check, hold);
+            INITBITS();
+            state->mode = OS;
+        case OS:
+            NEEDBITS(16);
+            if (state->head != Z_NULL) {
+                state->head->xflags = (int)(hold & 0xff);
+                state->head->os = (int)(hold >> 8);
+            }
+            if (state->flags & 0x0200) CRC2(state->check, hold);
+            INITBITS();
+            state->mode = EXLEN;
+        case EXLEN:
+            if (state->flags & 0x0400) {
+                NEEDBITS(16);
+                state->length = (unsigned)(hold);
+                if (state->head != Z_NULL)
+                    state->head->extra_len = (unsigned)hold;
+                if (state->flags & 0x0200) CRC2(state->check, hold);
+                INITBITS();
+            }
+            else if (state->head != Z_NULL)
+                state->head->extra = Z_NULL;
+            state->mode = EXTRA;
+        case EXTRA:
+            if (state->flags & 0x0400) {
+                copy = state->length;
+                if (copy > have) copy = have;
+                if (copy) {
+                    if (state->head != Z_NULL &&
+                        state->head->extra != Z_NULL) {
+                        len = state->head->extra_len - state->length;
+                        zmemcpy(state->head->extra + len, next,
+                                len + copy > state->head->extra_max ?
+                                state->head->extra_max - len : copy);
+                    }
+                    if (state->flags & 0x0200)
+                        state->check = crc32(state->check, next, copy);
+                    have -= copy;
+                    next += copy;
+                    state->length -= copy;
+                }
+                if (state->length) goto inf_leave;
+            }
+            state->length = 0;
+            state->mode = NAME;
+        case NAME:
+            if (state->flags & 0x0800) {
+                if (have == 0) goto inf_leave;
+                copy = 0;
+                do {
+                    len = (unsigned)(next[copy++]);
+                    if (state->head != Z_NULL &&
+                            state->head->name != Z_NULL &&
+                            state->length < state->head->name_max)
+                        state->head->name[state->length++] = len;
+                } while (len && copy < have);
+                if (state->flags & 0x0200)
+                    state->check = crc32(state->check, next, copy);
+                have -= copy;
+                next += copy;
+                if (len) goto inf_leave;
+            }
+            else if (state->head != Z_NULL)
+                state->head->name = Z_NULL;
+            state->length = 0;
+            state->mode = COMMENT;
+        case COMMENT:
+            if (state->flags & 0x1000) {
+                if (have == 0) goto inf_leave;
+                copy = 0;
+                do {
+                    len = (unsigned)(next[copy++]);
+                    if (state->head != Z_NULL &&
+                            state->head->comment != Z_NULL &&
+                            state->length < state->head->comm_max)
+                        state->head->comment[state->length++] = len;
+                } while (len && copy < have);
+                if (state->flags & 0x0200)
+                    state->check = crc32(state->check, next, copy);
+                have -= copy;
+                next += copy;
+                if (len) goto inf_leave;
+            }
+            else if (state->head != Z_NULL)
+                state->head->comment = Z_NULL;
+            state->mode = HCRC;
+        case HCRC:
+            if (state->flags & 0x0200) {
+                NEEDBITS(16);
+                if (hold != (state->check & 0xffff)) {
+                    strm->msg = (char *)"header crc mismatch";
+                    state->mode = BAD;
+                    break;
+                }
+                INITBITS();
+            }
+            if (state->head != Z_NULL) {
+                state->head->hcrc = (int)((state->flags >> 9) & 1);
+                state->head->done = 1;
+            }
+            strm->adler = state->check = crc32(0L, Z_NULL, 0);
+            state->mode = TYPE;
+            break;
+#endif
+        case DICTID:
+            NEEDBITS(32);
+            strm->adler = state->check = REVERSE(hold);
+            INITBITS();
+            state->mode = DICT;
+        case DICT:
+            if (state->havedict == 0) {
+                RESTORE();
+                return Z_NEED_DICT;
+            }
+            strm->adler = state->check = adler32(0L, Z_NULL, 0);
+            state->mode = TYPE;
+        case TYPE:
+            if (flush == Z_BLOCK) goto inf_leave;
+        case TYPEDO:
+            if (state->last) {
+                BYTEBITS();
+                state->mode = CHECK;
+                break;
+            }
+            NEEDBITS(3);
+            state->last = BITS(1);
+            DROPBITS(1);
+            switch (BITS(2)) {
+            case 0:                             /* stored block */
+                Tracev((stderr, "inflate:     stored block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = STORED;
+                break;
+            case 1:                             /* fixed block */
+                fixedtables(state);
+                Tracev((stderr, "inflate:     fixed codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = LEN;              /* decode codes */
+                break;
+            case 2:                             /* dynamic block */
+                Tracev((stderr, "inflate:     dynamic codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = TABLE;
+                break;
+            case 3:
+                strm->msg = (char *)"invalid block type";
+                state->mode = BAD;
+            }
+            DROPBITS(2);
+            break;
+        case STORED:
+            BYTEBITS();                         /* go to byte boundary */
+            NEEDBITS(32);
+            if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+                strm->msg = (char *)"invalid stored block lengths";
+                state->mode = BAD;
+                break;
+            }
+            state->length = (unsigned)hold & 0xffff;
+            Tracev((stderr, "inflate:       stored length %u\n",
+                    state->length));
+            INITBITS();
+            state->mode = COPY;
+        case COPY:
+            copy = state->length;
+            if (copy) {
+                if (copy > have) copy = have;
+                if (copy > left) copy = left;
+                if (copy == 0) goto inf_leave;
+                zmemcpy(put, next, copy);
+                have -= copy;
+                next += copy;
+                left -= copy;
+                put += copy;
+                state->length -= copy;
+                break;
+            }
+            Tracev((stderr, "inflate:       stored end\n"));
+            state->mode = TYPE;
+            break;
+        case TABLE:
+            NEEDBITS(14);
+            state->nlen = BITS(5) + 257;
+            DROPBITS(5);
+            state->ndist = BITS(5) + 1;
+            DROPBITS(5);
+            state->ncode = BITS(4) + 4;
+            DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+            if (state->nlen > 286 || state->ndist > 30) {
+                strm->msg = (char *)"too many length or distance symbols";
+                state->mode = BAD;
+                break;
+            }
+#endif
+            Tracev((stderr, "inflate:       table sizes ok\n"));
+            state->have = 0;
+            state->mode = LENLENS;
+        case LENLENS:
+            while (state->have < state->ncode) {
+                NEEDBITS(3);
+                state->lens[order[state->have++]] = (unsigned short)BITS(3);
+                DROPBITS(3);
+            }
+            while (state->have < 19)
+                state->lens[order[state->have++]] = 0;
+            state->next = state->codes;
+            state->lencode = (code const FAR *)(state->next);
+            state->lenbits = 7;
+            ret = inflate_table(CODES, state->lens, 19, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid code lengths set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       code lengths ok\n"));
+            state->have = 0;
+            state->mode = CODELENS;
+        case CODELENS:
+            while (state->have < state->nlen + state->ndist) {
+                for (;;) {
+                    this = state->lencode[BITS(state->lenbits)];
+                    if ((unsigned)(this.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                if (this.val < 16) {
+                    NEEDBITS(this.bits);
+                    DROPBITS(this.bits);
+                    state->lens[state->have++] = this.val;
+                }
+                else {
+                    if (this.val == 16) {
+                        NEEDBITS(this.bits + 2);
+                        DROPBITS(this.bits);
+                        if (state->have == 0) {
+                            strm->msg = (char *)"invalid bit length repeat";
+                            state->mode = BAD;
+                            break;
+                        }
+                        len = state->lens[state->have - 1];
+                        copy = 3 + BITS(2);
+                        DROPBITS(2);
+                    }
+                    else if (this.val == 17) {
+                        NEEDBITS(this.bits + 3);
+                        DROPBITS(this.bits);
+                        len = 0;
+                        copy = 3 + BITS(3);
+                        DROPBITS(3);
+                    }
+                    else {
+                        NEEDBITS(this.bits + 7);
+                        DROPBITS(this.bits);
+                        len = 0;
+                        copy = 11 + BITS(7);
+                        DROPBITS(7);
+                    }
+                    if (state->have + copy > state->nlen + state->ndist) {
+                        strm->msg = (char *)"invalid bit length repeat";
+                        state->mode = BAD;
+                        break;
+                    }
+                    while (copy--)
+                        state->lens[state->have++] = (unsigned short)len;
+                }
+            }
+
+            /* handle error breaks in while */
+            if (state->mode == BAD) break;
+
+            /* build code tables */
+            state->next = state->codes;
+            state->lencode = (code const FAR *)(state->next);
+            state->lenbits = 9;
+            ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid literal/lengths set";
+                state->mode = BAD;
+                break;
+            }
+            state->distcode = (code const FAR *)(state->next);
+            state->distbits = 6;
+            ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+                            &(state->next), &(state->distbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid distances set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       codes ok\n"));
+            state->mode = LEN;
+        case LEN:
+            if (have >= 6 && left >= 258) {
+                RESTORE();
+                inflate_fast(strm, out);
+                LOAD();
+                break;
+            }
+            for (;;) {
+                this = state->lencode[BITS(state->lenbits)];
+                if ((unsigned)(this.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if (this.op && (this.op & 0xf0) == 0) {
+                last = this;
+                for (;;) {
+                    this = state->lencode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + this.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+            }
+            DROPBITS(this.bits);
+            state->length = (unsigned)this.val;
+            if ((int)(this.op) == 0) {
+                Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+                        "inflate:         literal '%c'\n" :
+                        "inflate:         literal 0x%02x\n", this.val));
+                state->mode = LIT;
+                break;
+            }
+            if (this.op & 32) {
+                Tracevv((stderr, "inflate:         end of block\n"));
+                state->mode = TYPE;
+                break;
+            }
+            if (this.op & 64) {
+                strm->msg = (char *)"invalid literal/length code";
+                state->mode = BAD;
+                break;
+            }
+            state->extra = (unsigned)(this.op) & 15;
+            state->mode = LENEXT;
+        case LENEXT:
+            if (state->extra) {
+                NEEDBITS(state->extra);
+                state->length += BITS(state->extra);
+                DROPBITS(state->extra);
+            }
+            Tracevv((stderr, "inflate:         length %u\n", state->length));
+            state->mode = DIST;
+        case DIST:
+            for (;;) {
+                this = state->distcode[BITS(state->distbits)];
+                if ((unsigned)(this.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if ((this.op & 0xf0) == 0) {
+                last = this;
+                for (;;) {
+                    this = state->distcode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + this.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+            }
+            DROPBITS(this.bits);
+            if (this.op & 64) {
+                strm->msg = (char *)"invalid distance code";
+                state->mode = BAD;
+                break;
+            }
+            state->offset = (unsigned)this.val;
+            state->extra = (unsigned)(this.op) & 15;
+            state->mode = DISTEXT;
+        case DISTEXT:
+            if (state->extra) {
+                NEEDBITS(state->extra);
+                state->offset += BITS(state->extra);
+                DROPBITS(state->extra);
+            }
+#ifdef INFLATE_STRICT
+            if (state->offset > state->dmax) {
+                strm->msg = (char *)"invalid distance too far back";
+                state->mode = BAD;
+                break;
+            }
+#endif
+            if (state->offset > state->whave + out - left) {
+                strm->msg = (char *)"invalid distance too far back";
+                state->mode = BAD;
+                break;
+            }
+            Tracevv((stderr, "inflate:         distance %u\n", state->offset));
+            state->mode = MATCH;
+        case MATCH:
+            if (left == 0) goto inf_leave;
+            copy = out - left;
+            if (state->offset > copy) {         /* copy from window */
+                copy = state->offset - copy;
+                if (copy > state->write) {
+                    copy -= state->write;
+                    from = state->window + (state->wsize - copy);
+                }
+                else
+                    from = state->window + (state->write - copy);
+                if (copy > state->length) copy = state->length;
+            }
+            else {                              /* copy from output */
+                from = put - state->offset;
+                copy = state->length;
+            }
+            if (copy > left) copy = left;
+            left -= copy;
+            state->length -= copy;
+            do {
+                *put++ = *from++;
+            } while (--copy);
+            if (state->length == 0) state->mode = LEN;
+            break;
+        case LIT:
+            if (left == 0) goto inf_leave;
+            *put++ = (unsigned char)(state->length);
+            left--;
+            state->mode = LEN;
+            break;
+        case CHECK:
+            if (state->wrap) {
+                NEEDBITS(32);
+                out -= left;
+                strm->total_out += out;
+                state->total += out;
+                if (out)
+                    strm->adler = state->check =
+                        UPDATE(state->check, put - out, out);
+                out = left;
+                if ((
+#ifdef GUNZIP
+                     state->flags ? hold :
+#endif
+                     REVERSE(hold)) != state->check) {
+                    strm->msg = (char *)"incorrect data check";
+                    state->mode = BAD;
+                    break;
+                }
+                INITBITS();
+                Tracev((stderr, "inflate:   check matches trailer\n"));
+            }
+#ifdef GUNZIP
+            state->mode = LENGTH;
+        case LENGTH:
+            if (state->wrap && state->flags) {
+                NEEDBITS(32);
+                if (hold != (state->total & 0xffffffffUL)) {
+                    strm->msg = (char *)"incorrect length check";
+                    state->mode = BAD;
+                    break;
+                }
+                INITBITS();
+                Tracev((stderr, "inflate:   length matches trailer\n"));
+            }
+#endif
+            state->mode = DONE;
+        case DONE:
+            ret = Z_STREAM_END;
+            goto inf_leave;
+        case BAD:
+            ret = Z_DATA_ERROR;
+            goto inf_leave;
+        case MEM:
+            return Z_MEM_ERROR;
+        case SYNC:
+        default:
+            return Z_STREAM_ERROR;
+        }
+
+    /*
+       Return from inflate(), updating the total counts and the check value.
+       If there was no progress during the inflate() call, return a buffer
+       error.  Call updatewindow() to create and/or update the window state.
+       Note: a memory error from inflate() is non-recoverable.
+     */
+  inf_leave:
+    RESTORE();
+    if (state->wsize || (state->mode < CHECK && out != strm->avail_out))
+        if (updatewindow(strm, out)) {
+            state->mode = MEM;
+            return Z_MEM_ERROR;
+        }
+    in -= strm->avail_in;
+    out -= strm->avail_out;
+    strm->total_in += in;
+    strm->total_out += out;
+    state->total += out;
+    if (state->wrap && out)
+        strm->adler = state->check =
+            UPDATE(state->check, strm->next_out - out, out);
+    strm->data_type = state->bits + (state->last ? 64 : 0) +
+                      (state->mode == TYPE ? 128 : 0);
+    if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
+        ret = Z_BUF_ERROR;
+    return ret;
+}
+
+int ZEXPORT inflateEnd(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+    if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+        return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (state->window != Z_NULL) ZFREE(strm, state->window);
+    ZFREE(strm, strm->state);
+    strm->state = Z_NULL;
+    Tracev((stderr, "inflate: end\n"));
+    return Z_OK;
+}
+
+int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength)
+z_streamp strm;
+const Bytef *dictionary;
+uInt dictLength;
+{
+    struct inflate_state FAR *state;
+    unsigned long id;
+
+    /* check state */
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (state->wrap != 0 && state->mode != DICT)
+        return Z_STREAM_ERROR;
+
+    /* check for correct dictionary id */
+    if (state->mode == DICT) {
+        id = adler32(0L, Z_NULL, 0);
+        id = adler32(id, dictionary, dictLength);
+        if (id != state->check)
+            return Z_DATA_ERROR;
+    }
+
+    /* copy dictionary to window */
+    if (updatewindow(strm, strm->avail_out)) {
+        state->mode = MEM;
+        return Z_MEM_ERROR;
+    }
+    if (dictLength > state->wsize) {
+        zmemcpy(state->window, dictionary + dictLength - state->wsize,
+                state->wsize);
+        state->whave = state->wsize;
+    }
+    else {
+        zmemcpy(state->window + state->wsize - dictLength, dictionary,
+                dictLength);
+        state->whave = dictLength;
+    }
+    state->havedict = 1;
+    Tracev((stderr, "inflate:   dictionary set\n"));
+    return Z_OK;
+}
+
+int ZEXPORT inflateGetHeader(strm, head)
+z_streamp strm;
+gz_headerp head;
+{
+    struct inflate_state FAR *state;
+
+    /* check state */
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;
+
+    /* save header structure */
+    state->head = head;
+    head->done = 0;
+    return Z_OK;
+}
+
+/*
+   Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff.  Return when found
+   or when out of input.  When called, *have is the number of pattern bytes
+   found in order so far, in 0..3.  On return *have is updated to the new
+   state.  If on return *have equals four, then the pattern was found and the
+   return value is how many bytes were read including the last byte of the
+   pattern.  If *have is less than four, then the pattern has not been found
+   yet and the return value is len.  In the latter case, syncsearch() can be
+   called again with more data and the *have state.  *have is initialized to
+   zero for the first call.
+ */
+local unsigned syncsearch(have, buf, len)
+unsigned FAR *have;
+unsigned char FAR *buf;
+unsigned len;
+{
+    unsigned got;
+    unsigned next;
+
+    got = *have;
+    next = 0;
+    while (next < len && got < 4) {
+        if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))
+            got++;
+        else if (buf[next])
+            got = 0;
+        else
+            got = 4 - got;
+        next++;
+    }
+    *have = got;
+    return next;
+}
+
+int ZEXPORT inflateSync(strm)
+z_streamp strm;
+{
+    unsigned len;               /* number of bytes to look at or looked at */
+    unsigned long in, out;      /* temporary to save total_in and total_out */
+    unsigned char buf[4];       /* to restore bit buffer to byte string */
+    struct inflate_state FAR *state;
+
+    /* check parameters */
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;
+
+    /* if first time, start search in bit buffer */
+    if (state->mode != SYNC) {
+        state->mode = SYNC;
+        state->hold <<= state->bits & 7;
+        state->bits -= state->bits & 7;
+        len = 0;
+        while (state->bits >= 8) {
+            buf[len++] = (unsigned char)(state->hold);
+            state->hold >>= 8;
+            state->bits -= 8;
+        }
+        state->have = 0;
+        syncsearch(&(state->have), buf, len);
+    }
+
+    /* search available input */
+    len = syncsearch(&(state->have), strm->next_in, strm->avail_in);
+    strm->avail_in -= len;
+    strm->next_in += len;
+    strm->total_in += len;
+
+    /* return no joy or set up to restart inflate() on a new block */
+    if (state->have != 4) return Z_DATA_ERROR;
+    in = strm->total_in;  out = strm->total_out;
+    inflateReset(strm);
+    strm->total_in = in;  strm->total_out = out;
+    state->mode = TYPE;
+    return Z_OK;
+}
+
+/*
+   Returns true if inflate is currently at the end of a block generated by
+   Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+   implementation to provide an additional safety check. PPP uses
+   Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored
+   block. When decompressing, PPP checks that at the end of input packet,
+   inflate is waiting for these length bytes.
+ */
+int ZEXPORT inflateSyncPoint(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    return state->mode == STORED && state->bits == 0;
+}
+
+int ZEXPORT inflateCopy(dest, source)
+z_streamp dest;
+z_streamp source;
+{
+    struct inflate_state FAR *state;
+    struct inflate_state FAR *copy;
+    unsigned char FAR *window;
+    unsigned wsize;
+
+    /* check input */
+    if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL ||
+        source->zalloc == (alloc_func)0 || source->zfree == (free_func)0)
+        return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)source->state;
+
+    /* allocate space */
+    copy = (struct inflate_state FAR *)
+           ZALLOC(source, 1, sizeof(struct inflate_state));
+    if (copy == Z_NULL) return Z_MEM_ERROR;
+    window = Z_NULL;
+    if (state->window != Z_NULL) {
+        window = (unsigned char FAR *)
+                 ZALLOC(source, 1U << state->wbits, sizeof(unsigned char));
+        if (window == Z_NULL) {
+            ZFREE(source, copy);
+            return Z_MEM_ERROR;
+        }
+    }
+
+    /* copy state */
+    zmemcpy(dest, source, sizeof(z_stream));
+    zmemcpy(copy, state, sizeof(struct inflate_state));
+    if (state->lencode >= state->codes &&
+        state->lencode <= state->codes + ENOUGH - 1) {
+        copy->lencode = copy->codes + (state->lencode - state->codes);
+        copy->distcode = copy->codes + (state->distcode - state->codes);
+    }
+    copy->next = copy->codes + (state->next - state->codes);
+    if (window != Z_NULL) {
+        wsize = 1U << state->wbits;
+        zmemcpy(window, state->window, wsize);
+    }
+    copy->window = window;
+    dest->state = (struct internal_state FAR *)copy;
+    return Z_OK;
+}
diff --git a/src/unison/physfs-1.1.1/zlib123/inflate.h b/src/unison/physfs-1.1.1/zlib123/inflate.h
new file mode 100644 (file)
index 0000000..07bd3e7
--- /dev/null
@@ -0,0 +1,115 @@
+/* inflate.h -- internal inflate state definition
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+   trailer decoding by inflate().  NO_GZIP would be used to avoid linking in
+   the crc code when it is not needed.  For shared libraries, gzip decoding
+   should be left enabled. */
+#ifndef NO_GZIP
+#  define GUNZIP
+#endif
+
+/* Possible inflate modes between inflate() calls */
+typedef enum {
+    HEAD,       /* i: waiting for magic header */
+    FLAGS,      /* i: waiting for method and flags (gzip) */
+    TIME,       /* i: waiting for modification time (gzip) */
+    OS,         /* i: waiting for extra flags and operating system (gzip) */
+    EXLEN,      /* i: waiting for extra length (gzip) */
+    EXTRA,      /* i: waiting for extra bytes (gzip) */
+    NAME,       /* i: waiting for end of file name (gzip) */
+    COMMENT,    /* i: waiting for end of comment (gzip) */
+    HCRC,       /* i: waiting for header crc (gzip) */
+    DICTID,     /* i: waiting for dictionary check value */
+    DICT,       /* waiting for inflateSetDictionary() call */
+        TYPE,       /* i: waiting for type bits, including last-flag bit */
+        TYPEDO,     /* i: same, but skip check to exit inflate on new block */
+        STORED,     /* i: waiting for stored size (length and complement) */
+        COPY,       /* i/o: waiting for input or output to copy stored block */
+        TABLE,      /* i: waiting for dynamic block table lengths */
+        LENLENS,    /* i: waiting for code length code lengths */
+        CODELENS,   /* i: waiting for length/lit and distance code lengths */
+            LEN,        /* i: waiting for length/lit code */
+            LENEXT,     /* i: waiting for length extra bits */
+            DIST,       /* i: waiting for distance code */
+            DISTEXT,    /* i: waiting for distance extra bits */
+            MATCH,      /* o: waiting for output space to copy string */
+            LIT,        /* o: waiting for output space to write literal */
+    CHECK,      /* i: waiting for 32-bit check value */
+    LENGTH,     /* i: waiting for 32-bit length (gzip) */
+    DONE,       /* finished check, done -- remain here until reset */
+    BAD,        /* got a data error -- remain here until reset */
+    MEM,        /* got an inflate() memory error -- remain here until reset */
+    SYNC        /* looking for synchronization bytes to restart inflate() */
+} inflate_mode;
+
+/*
+    State transitions between above modes -
+
+    (most modes can go to the BAD or MEM mode -- not shown for clarity)
+
+    Process header:
+        HEAD -> (gzip) or (zlib)
+        (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME
+        NAME -> COMMENT -> HCRC -> TYPE
+        (zlib) -> DICTID or TYPE
+        DICTID -> DICT -> TYPE
+    Read deflate blocks:
+            TYPE -> STORED or TABLE or LEN or CHECK
+            STORED -> COPY -> TYPE
+            TABLE -> LENLENS -> CODELENS -> LEN
+    Read deflate codes:
+                LEN -> LENEXT or LIT or TYPE
+                LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
+                LIT -> LEN
+    Process trailer:
+        CHECK -> LENGTH -> DONE
+ */
+
+/* state maintained between inflate() calls.  Approximately 7K bytes. */
+struct inflate_state {
+    inflate_mode mode;          /* current inflate mode */
+    int last;                   /* true if processing last block */
+    int wrap;                   /* bit 0 true for zlib, bit 1 true for gzip */
+    int havedict;               /* true if dictionary provided */
+    int flags;                  /* gzip header method and flags (0 if zlib) */
+    unsigned dmax;              /* zlib header max distance (INFLATE_STRICT) */
+    unsigned long check;        /* protected copy of check value */
+    unsigned long total;        /* protected copy of output count */
+    gz_headerp head;            /* where to save gzip header information */
+        /* sliding window */
+    unsigned wbits;             /* log base 2 of requested window size */
+    unsigned wsize;             /* window size or zero if not using window */
+    unsigned whave;             /* valid bytes in the window */
+    unsigned write;             /* window write index */
+    unsigned char FAR *window;  /* allocated sliding window, if needed */
+        /* bit accumulator */
+    unsigned long hold;         /* input bit accumulator */
+    unsigned bits;              /* number of bits in "in" */
+        /* for string and stored block copying */
+    unsigned length;            /* literal or length of data to copy */
+    unsigned offset;            /* distance back to copy string from */
+        /* for table and code decoding */
+    unsigned extra;             /* extra bits needed */
+        /* fixed and dynamic code tables */
+    code const FAR *lencode;    /* starting table for length/literal codes */
+    code const FAR *distcode;   /* starting table for distance codes */
+    unsigned lenbits;           /* index bits for lencode */
+    unsigned distbits;          /* index bits for distcode */
+        /* dynamic table building */
+    unsigned ncode;             /* number of code length code lengths */
+    unsigned nlen;              /* number of length code lengths */
+    unsigned ndist;             /* number of distance code lengths */
+    unsigned have;              /* number of code lengths in lens[] */
+    code FAR *next;             /* next available space in codes[] */
+    unsigned short lens[320];   /* temporary storage for code lengths */
+    unsigned short work[288];   /* work area for code table building */
+    code codes[ENOUGH];         /* space for code tables */
+};
diff --git a/src/unison/physfs-1.1.1/zlib123/inftrees.c b/src/unison/physfs-1.1.1/zlib123/inftrees.c
new file mode 100644 (file)
index 0000000..8a9c13f
--- /dev/null
@@ -0,0 +1,329 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+#define MAXBITS 15
+
+const char inflate_copyright[] =
+   " inflate 1.2.3 Copyright 1995-2005 Mark Adler ";
+/*
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+ */
+
+/*
+   Build a set of tables to decode the provided canonical Huffman code.
+   The code lengths are lens[0..codes-1].  The result starts at *table,
+   whose indices are 0..2^bits-1.  work is a writable array of at least
+   lens shorts, which is used as a work area.  type is the type of code
+   to be generated, CODES, LENS, or DISTS.  On return, zero is success,
+   -1 is an invalid code, and +1 means that ENOUGH isn't enough.  table
+   on return points to the next available entry's address.  bits is the
+   requested root table index bits, and on return it is the actual root
+   table index bits.  It will differ if the request is greater than the
+   longest code or if it is less than the shortest code.
+ */
+int inflate_table(type, lens, codes, table, bits, work)
+codetype type;
+unsigned short FAR *lens;
+unsigned codes;
+code FAR * FAR *table;
+unsigned FAR *bits;
+unsigned short FAR *work;
+{
+    unsigned len;               /* a code's length in bits */
+    unsigned sym;               /* index of code symbols */
+    unsigned min, max;          /* minimum and maximum code lengths */
+    unsigned root;              /* number of index bits for root table */
+    unsigned curr;              /* number of index bits for current table */
+    unsigned drop;              /* code bits to drop for sub-table */
+    int left;                   /* number of prefix codes available */
+    unsigned used;              /* code entries in table used */
+    unsigned huff;              /* Huffman code */
+    unsigned incr;              /* for incrementing code, index */
+    unsigned fill;              /* index for replicating entries */
+    unsigned low;               /* low bits for current root entry */
+    unsigned mask;              /* mask for low root bits */
+    code this;                  /* table entry for duplication */
+    code FAR *next;             /* next available space in table */
+    const unsigned short FAR *base;     /* base value table to use */
+    const unsigned short FAR *extra;    /* extra bits table to use */
+    int end;                    /* use base and extra for symbol > end */
+    unsigned short count[MAXBITS+1];    /* number of codes of each length */
+    unsigned short offs[MAXBITS+1];     /* offsets in table for each length */
+    static const unsigned short lbase[31] = { /* Length codes 257..285 base */
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+    static const unsigned short lext[31] = { /* Length codes 257..285 extra */
+        16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
+        19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196};
+    static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
+        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577, 0, 0};
+    static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
+        16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
+        23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
+        28, 28, 29, 29, 64, 64};
+
+    /*
+       Process a set of code lengths to create a canonical Huffman code.  The
+       code lengths are lens[0..codes-1].  Each length corresponds to the
+       symbols 0..codes-1.  The Huffman code is generated by first sorting the
+       symbols by length from short to long, and retaining the symbol order
+       for codes with equal lengths.  Then the code starts with all zero bits
+       for the first code of the shortest length, and the codes are integer
+       increments for the same length, and zeros are appended as the length
+       increases.  For the deflate format, these bits are stored backwards
+       from their more natural integer increment ordering, and so when the
+       decoding tables are built in the large loop below, the integer codes
+       are incremented backwards.
+
+       This routine assumes, but does not check, that all of the entries in
+       lens[] are in the range 0..MAXBITS.  The caller must assure this.
+       1..MAXBITS is interpreted as that code length.  zero means that that
+       symbol does not occur in this code.
+
+       The codes are sorted by computing a count of codes for each length,
+       creating from that a table of starting indices for each length in the
+       sorted table, and then entering the symbols in order in the sorted
+       table.  The sorted table is work[], with that space being provided by
+       the caller.
+
+       The length counts are used for other purposes as well, i.e. finding
+       the minimum and maximum length codes, determining if there are any
+       codes at all, checking for a valid set of lengths, and looking ahead
+       at length counts to determine sub-table sizes when building the
+       decoding tables.
+     */
+
+    /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
+    for (len = 0; len <= MAXBITS; len++)
+        count[len] = 0;
+    for (sym = 0; sym < codes; sym++)
+        count[lens[sym]]++;
+
+    /* bound code lengths, force root to be within code lengths */
+    root = *bits;
+    for (max = MAXBITS; max >= 1; max--)
+        if (count[max] != 0) break;
+    if (root > max) root = max;
+    if (max == 0) {                     /* no symbols to code at all */
+        this.op = (unsigned char)64;    /* invalid code marker */
+        this.bits = (unsigned char)1;
+        this.val = (unsigned short)0;
+        *(*table)++ = this;             /* make a table to force an error */
+        *(*table)++ = this;
+        *bits = 1;
+        return 0;     /* no symbols, but wait for decoding to report error */
+    }
+    for (min = 1; min <= MAXBITS; min++)
+        if (count[min] != 0) break;
+    if (root < min) root = min;
+
+    /* check for an over-subscribed or incomplete set of lengths */
+    left = 1;
+    for (len = 1; len <= MAXBITS; len++) {
+        left <<= 1;
+        left -= count[len];
+        if (left < 0) return -1;        /* over-subscribed */
+    }
+    if (left > 0 && (type == CODES || max != 1))
+        return -1;                      /* incomplete set */
+
+    /* generate offsets into symbol table for each length for sorting */
+    offs[1] = 0;
+    for (len = 1; len < MAXBITS; len++)
+        offs[len + 1] = offs[len] + count[len];
+
+    /* sort symbols by length, by symbol order within each length */
+    for (sym = 0; sym < codes; sym++)
+        if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
+
+    /*
+       Create and fill in decoding tables.  In this loop, the table being
+       filled is at next and has curr index bits.  The code being used is huff
+       with length len.  That code is converted to an index by dropping drop
+       bits off of the bottom.  For codes where len is less than drop + curr,
+       those top drop + curr - len bits are incremented through all values to
+       fill the table with replicated entries.
+
+       root is the number of index bits for the root table.  When len exceeds
+       root, sub-tables are created pointed to by the root entry with an index
+       of the low root bits of huff.  This is saved in low to check for when a
+       new sub-table should be started.  drop is zero when the root table is
+       being filled, and drop is root when sub-tables are being filled.
+
+       When a new sub-table is needed, it is necessary to look ahead in the
+       code lengths to determine what size sub-table is needed.  The length
+       counts are used for this, and so count[] is decremented as codes are
+       entered in the tables.
+
+       used keeps track of how many table entries have been allocated from the
+       provided *table space.  It is checked when a LENS table is being made
+       against the space in *table, ENOUGH, minus the maximum space needed by
+       the worst case distance code, MAXD.  This should never happen, but the
+       sufficiency of ENOUGH has not been proven exhaustively, hence the check.
+       This assumes that when type == LENS, bits == 9.
+
+       sym increments through all symbols, and the loop terminates when
+       all codes of length max, i.e. all codes, have been processed.  This
+       routine permits incomplete codes, so another loop after this one fills
+       in the rest of the decoding tables with invalid code markers.
+     */
+
+    /* set up for code type */
+    switch (type) {
+    case CODES:
+        base = extra = work;    /* dummy value--not used */
+        end = 19;
+        break;
+    case LENS:
+        base = lbase;
+        base -= 257;
+        extra = lext;
+        extra -= 257;
+        end = 256;
+        break;
+    default:            /* DISTS */
+        base = dbase;
+        extra = dext;
+        end = -1;
+    }
+
+    /* initialize state for loop */
+    huff = 0;                   /* starting code */
+    sym = 0;                    /* starting code symbol */
+    len = min;                  /* starting code length */
+    next = *table;              /* current table to fill in */
+    curr = root;                /* current table index bits */
+    drop = 0;                   /* current bits to drop from code for index */
+    low = (unsigned)(-1);       /* trigger new sub-table when len > root */
+    used = 1U << root;          /* use root table entries */
+    mask = used - 1;            /* mask for comparing low */
+
+    /* check available table space */
+    if (type == LENS && used >= ENOUGH - MAXD)
+        return 1;
+
+    /* process all codes and make table entries */
+    for (;;) {
+        /* create table entry */
+        this.bits = (unsigned char)(len - drop);
+        if ((int)(work[sym]) < end) {
+            this.op = (unsigned char)0;
+            this.val = work[sym];
+        }
+        else if ((int)(work[sym]) > end) {
+            this.op = (unsigned char)(extra[work[sym]]);
+            this.val = base[work[sym]];
+        }
+        else {
+            this.op = (unsigned char)(32 + 64);         /* end of block */
+            this.val = 0;
+        }
+
+        /* replicate for those indices with low len bits equal to huff */
+        incr = 1U << (len - drop);
+        fill = 1U << curr;
+        min = fill;                 /* save offset to next table */
+        do {
+            fill -= incr;
+            next[(huff >> drop) + fill] = this;
+        } while (fill != 0);
+
+        /* backwards increment the len-bit code huff */
+        incr = 1U << (len - 1);
+        while (huff & incr)
+            incr >>= 1;
+        if (incr != 0) {
+            huff &= incr - 1;
+            huff += incr;
+        }
+        else
+            huff = 0;
+
+        /* go to next symbol, update count, len */
+        sym++;
+        if (--(count[len]) == 0) {
+            if (len == max) break;
+            len = lens[work[sym]];
+        }
+
+        /* create new sub-table if needed */
+        if (len > root && (huff & mask) != low) {
+            /* if first time, transition to sub-tables */
+            if (drop == 0)
+                drop = root;
+
+            /* increment past last table */
+            next += min;            /* here min is 1 << curr */
+
+            /* determine length of next table */
+            curr = len - drop;
+            left = (int)(1 << curr);
+            while (curr + drop < max) {
+                left -= count[curr + drop];
+                if (left <= 0) break;
+                curr++;
+                left <<= 1;
+            }
+
+            /* check for enough space */
+            used += 1U << curr;
+            if (type == LENS && used >= ENOUGH - MAXD)
+                return 1;
+
+            /* point entry in root table to sub-table */
+            low = huff & mask;
+            (*table)[low].op = (unsigned char)curr;
+            (*table)[low].bits = (unsigned char)root;
+            (*table)[low].val = (unsigned short)(next - *table);
+        }
+    }
+
+    /*
+       Fill in rest of table for incomplete codes.  This loop is similar to the
+       loop above in incrementing huff for table indices.  It is assumed that
+       len is equal to curr + drop, so there is no loop needed to increment
+       through high index bits.  When the current sub-table is filled, the loop
+       drops back to the root table to fill in any remaining entries there.
+     */
+    this.op = (unsigned char)64;                /* invalid code marker */
+    this.bits = (unsigned char)(len - drop);
+    this.val = (unsigned short)0;
+    while (huff != 0) {
+        /* when done with sub-table, drop back to root table */
+        if (drop != 0 && (huff & mask) != low) {
+            drop = 0;
+            len = root;
+            next = *table;
+            this.bits = (unsigned char)len;
+        }
+
+        /* put invalid code marker in table */
+        next[huff >> drop] = this;
+
+        /* backwards increment the len-bit code huff */
+        incr = 1U << (len - 1);
+        while (huff & incr)
+            incr >>= 1;
+        if (incr != 0) {
+            huff &= incr - 1;
+            huff += incr;
+        }
+        else
+            huff = 0;
+    }
+
+    /* set return parameters */
+    *table += used;
+    *bits = root;
+    return 0;
+}
diff --git a/src/unison/physfs-1.1.1/zlib123/inftrees.h b/src/unison/physfs-1.1.1/zlib123/inftrees.h
new file mode 100644 (file)
index 0000000..b1104c8
--- /dev/null
@@ -0,0 +1,55 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* Structure for decoding tables.  Each entry provides either the
+   information needed to do the operation requested by the code that
+   indexed that table entry, or it provides a pointer to another
+   table that indexes more bits of the code.  op indicates whether
+   the entry is a pointer to another table, a literal, a length or
+   distance, an end-of-block, or an invalid code.  For a table
+   pointer, the low four bits of op is the number of index bits of
+   that table.  For a length or distance, the low four bits of op
+   is the number of extra bits to get after the code.  bits is
+   the number of bits in this code or part of the code to drop off
+   of the bit buffer.  val is the actual byte to output in the case
+   of a literal, the base length or distance, or the offset from
+   the current table to the next table.  Each entry is four bytes. */
+typedef struct {
+    unsigned char op;           /* operation, extra bits, table bits */
+    unsigned char bits;         /* bits in this part of the code */
+    unsigned short val;         /* offset in table or code value */
+} code;
+
+/* op values as set by inflate_table():
+    00000000 - literal
+    0000tttt - table link, tttt != 0 is the number of table index bits
+    0001eeee - length or distance, eeee is the number of extra bits
+    01100000 - end of block
+    01000000 - invalid code
+ */
+
+/* Maximum size of dynamic tree.  The maximum found in a long but non-
+   exhaustive search was 1444 code structures (852 for length/literals
+   and 592 for distances, the latter actually the result of an
+   exhaustive search).  The true maximum is not known, but the value
+   below is more than safe. */
+#define ENOUGH 2048
+#define MAXD 592
+
+/* Type of code to build for inftable() */
+typedef enum {
+    CODES,
+    LENS,
+    DISTS
+} codetype;
+
+extern int inflate_table OF((codetype type, unsigned short FAR *lens,
+                             unsigned codes, code FAR * FAR *table,
+                             unsigned FAR *bits, unsigned short FAR *work));
diff --git a/src/unison/physfs-1.1.1/zlib123/trees.c b/src/unison/physfs-1.1.1/zlib123/trees.c
new file mode 100644 (file)
index 0000000..395e4e1
--- /dev/null
@@ -0,0 +1,1219 @@
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-2005 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process uses several Huffman trees. The more
+ *      common source values are represented by shorter bit sequences.
+ *
+ *      Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values).  The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ *      Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ *      Storer, James A.
+ *          Data Compression:  Methods and Theory, pp. 49-50.
+ *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
+ *
+ *      Sedgewick, R.
+ *          Algorithms, p290.
+ *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* @(#) $Id$ */
+
+/* #define GEN_TREES_H */
+
+#include "deflate.h"
+
+#ifdef DEBUG
+#  include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6      16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10    17
+/* repeat a zero length 3-10 times  (3 bits of repeat count) */
+
+#define REPZ_11_138  18
+/* repeat a zero length 11-138 times  (7 bits of repeat count) */
+
+local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+   = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local const int extra_dbits[D_CODES] /* extra bits for each distance code */
+   = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local const uch bl_order[BL_CODES]
+   = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+#define DIST_CODE_LEN  512 /* see definition of array dist_code below */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+/* non ANSI compilers may not accept trees.h */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+uch _dist_code[DIST_CODE_LEN];
+/* Distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+uch _length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#else
+#  include "trees.h"
+#endif /* GEN_TREES_H */
+
+struct static_tree_desc_s {
+    const ct_data *static_tree;  /* static tree or NULL */
+    const intf *extra_bits;      /* extra bits for each code or NULL */
+    int     extra_base;          /* base index for extra_bits */
+    int     elems;               /* max number of elements in the tree */
+    int     max_length;          /* max bit length for the codes */
+};
+
+local static_tree_desc  static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc  static_d_desc =
+{static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS};
+
+local static_tree_desc  static_bl_desc =
+{(const ct_data *)0, extra_blbits, 0,   BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block     OF((deflate_state *s));
+local void pqdownheap     OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen     OF((deflate_state *s, tree_desc *desc));
+local void gen_codes      OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree     OF((deflate_state *s, tree_desc *desc));
+local void scan_tree      OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree      OF((deflate_state *s, ct_data *tree, int max_code));
+local int  build_bl_tree  OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+                              int blcodes));
+local void compress_block OF((deflate_state *s, ct_data *ltree,
+                              ct_data *dtree));
+local void set_data_type  OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup      OF((deflate_state *s));
+local void bi_flush       OF((deflate_state *s));
+local void copy_block     OF((deflate_state *s, charf *buf, unsigned len,
+                              int header));
+
+#ifdef GEN_TREES_H
+local void gen_trees_header OF((void));
+#endif
+
+#ifndef DEBUG
+#  define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+   /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+#  define send_code(s, c, tree) \
+     { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+       send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+    put_byte(s, (uch)((w) & 0xff)); \
+    put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG
+local void send_bits      OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+    deflate_state *s;
+    int value;  /* value to send */
+    int length; /* number of bits */
+{
+    Tracevv((stderr," l %2d v %4x ", length, value));
+    Assert(length > 0 && length <= 15, "invalid length");
+    s->bits_sent += (ulg)length;
+
+    /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+     * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+     * unused bits in value.
+     */
+    if (s->bi_valid > (int)Buf_size - length) {
+        s->bi_buf |= (value << s->bi_valid);
+        put_short(s, s->bi_buf);
+        s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+        s->bi_valid += length - Buf_size;
+    } else {
+        s->bi_buf |= value << s->bi_valid;
+        s->bi_valid += length;
+    }
+}
+#else /* !DEBUG */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+  if (s->bi_valid > (int)Buf_size - len) {\
+    int val = value;\
+    s->bi_buf |= (val << s->bi_valid);\
+    put_short(s, s->bi_buf);\
+    s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+    s->bi_valid += len - Buf_size;\
+  } else {\
+    s->bi_buf |= (value) << s->bi_valid;\
+    s->bi_valid += len;\
+  }\
+}
+#endif /* DEBUG */
+
+
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables.
+ */
+local void tr_static_init()
+{
+#if defined(GEN_TREES_H) || !defined(STDC)
+    static int static_init_done = 0;
+    int n;        /* iterates over tree elements */
+    int bits;     /* bit counter */
+    int length;   /* length value */
+    int code;     /* code value */
+    int dist;     /* distance index */
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    if (static_init_done) return;
+
+    /* For some embedded targets, global variables are not initialized: */
+    static_l_desc.static_tree = static_ltree;
+    static_l_desc.extra_bits = extra_lbits;
+    static_d_desc.static_tree = static_dtree;
+    static_d_desc.extra_bits = extra_dbits;
+    static_bl_desc.extra_bits = extra_blbits;
+
+    /* Initialize the mapping length (0..255) -> length code (0..28) */
+    length = 0;
+    for (code = 0; code < LENGTH_CODES-1; code++) {
+        base_length[code] = length;
+        for (n = 0; n < (1<<extra_lbits[code]); n++) {
+            _length_code[length++] = (uch)code;
+        }
+    }
+    Assert (length == 256, "tr_static_init: length != 256");
+    /* Note that the length 255 (match length 258) can be represented
+     * in two different ways: code 284 + 5 bits or code 285, so we
+     * overwrite length_code[255] to use the best encoding:
+     */
+    _length_code[length-1] = (uch)code;
+
+    /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+    dist = 0;
+    for (code = 0 ; code < 16; code++) {
+        base_dist[code] = dist;
+        for (n = 0; n < (1<<extra_dbits[code]); n++) {
+            _dist_code[dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: dist != 256");
+    dist >>= 7; /* from now on, all distances are divided by 128 */
+    for ( ; code < D_CODES; code++) {
+        base_dist[code] = dist << 7;
+        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+            _dist_code[256 + dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+    /* Construct the codes of the static literal tree */
+    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+    n = 0;
+    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+    while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+    /* Codes 286 and 287 do not exist, but we must include them in the
+     * tree construction to get a canonical Huffman tree (longest code
+     * all ones)
+     */
+    gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+    /* The static distance tree is trivial: */
+    for (n = 0; n < D_CODES; n++) {
+        static_dtree[n].Len = 5;
+        static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+    }
+    static_init_done = 1;
+
+#  ifdef GEN_TREES_H
+    gen_trees_header();
+#  endif
+#endif /* defined(GEN_TREES_H) || !defined(STDC) */
+}
+
+/* ===========================================================================
+ * Genererate the file trees.h describing the static trees.
+ */
+#ifdef GEN_TREES_H
+#  ifndef DEBUG
+#    include <stdio.h>
+#  endif
+
+#  define SEPARATOR(i, last, width) \
+      ((i) == (last)? "\n};\n\n" :    \
+       ((i) % (width) == (width)-1 ? ",\n" : ", "))
+
+void gen_trees_header()
+{
+    FILE *header = fopen("trees.h", "w");
+    int i;
+
+    Assert (header != NULL, "Can't open trees.h");
+    fprintf(header,
+            "/* header created automatically with -DGEN_TREES_H */\n\n");
+
+    fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n");
+    for (i = 0; i < L_CODES+2; i++) {
+        fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code,
+                static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
+    }
+
+    fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n");
+    for (i = 0; i < D_CODES; i++) {
+        fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code,
+                static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
+    }
+
+    fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n");
+    for (i = 0; i < DIST_CODE_LEN; i++) {
+        fprintf(header, "%2u%s", _dist_code[i],
+                SEPARATOR(i, DIST_CODE_LEN-1, 20));
+    }
+
+    fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n");
+    for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {
+        fprintf(header, "%2u%s", _length_code[i],
+                SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
+    }
+
+    fprintf(header, "local const int base_length[LENGTH_CODES] = {\n");
+    for (i = 0; i < LENGTH_CODES; i++) {
+        fprintf(header, "%1u%s", base_length[i],
+                SEPARATOR(i, LENGTH_CODES-1, 20));
+    }
+
+    fprintf(header, "local const int base_dist[D_CODES] = {\n");
+    for (i = 0; i < D_CODES; i++) {
+        fprintf(header, "%5u%s", base_dist[i],
+                SEPARATOR(i, D_CODES-1, 10));
+    }
+
+    fclose(header);
+}
+#endif /* GEN_TREES_H */
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void _tr_init(s)
+    deflate_state *s;
+{
+    tr_static_init();
+
+    s->l_desc.dyn_tree = s->dyn_ltree;
+    s->l_desc.stat_desc = &static_l_desc;
+
+    s->d_desc.dyn_tree = s->dyn_dtree;
+    s->d_desc.stat_desc = &static_d_desc;
+
+    s->bl_desc.dyn_tree = s->bl_tree;
+    s->bl_desc.stat_desc = &static_bl_desc;
+
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+    s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG
+    s->compressed_len = 0L;
+    s->bits_sent = 0L;
+#endif
+
+    /* Initialize the first block of the first file: */
+    init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+    deflate_state *s;
+{
+    int n; /* iterates over tree elements */
+
+    /* Initialize the trees. */
+    for (n = 0; n < L_CODES;  n++) s->dyn_ltree[n].Freq = 0;
+    for (n = 0; n < D_CODES;  n++) s->dyn_dtree[n].Freq = 0;
+    for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+    s->dyn_ltree[END_BLOCK].Freq = 1;
+    s->opt_len = s->static_len = 0L;
+    s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+    top = s->heap[SMALLEST]; \
+    s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+    pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+   (tree[n].Freq < tree[m].Freq || \
+   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+    deflate_state *s;
+    ct_data *tree;  /* the tree to restore */
+    int k;               /* node to move down */
+{
+    int v = s->heap[k];
+    int j = k << 1;  /* left son of k */
+    while (j <= s->heap_len) {
+        /* Set j to the smallest of the two sons: */
+        if (j < s->heap_len &&
+            smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+            j++;
+        }
+        /* Exit if v is smaller than both sons */
+        if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+        /* Exchange v with the smallest son */
+        s->heap[k] = s->heap[j];  k = j;
+
+        /* And continue down the tree, setting j to the left son of k */
+        j <<= 1;
+    }
+    s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ *    above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ *     array bl_count contains the frequencies for each bit length.
+ *     The length opt_len is updated; static_len is also updated if stree is
+ *     not null.
+ */
+local void gen_bitlen(s, desc)
+    deflate_state *s;
+    tree_desc *desc;    /* the tree descriptor */
+{
+    ct_data *tree        = desc->dyn_tree;
+    int max_code         = desc->max_code;
+    const ct_data *stree = desc->stat_desc->static_tree;
+    const intf *extra    = desc->stat_desc->extra_bits;
+    int base             = desc->stat_desc->extra_base;
+    int max_length       = desc->stat_desc->max_length;
+    int h;              /* heap index */
+    int n, m;           /* iterate over the tree elements */
+    int bits;           /* bit length */
+    int xbits;          /* extra bits */
+    ush f;              /* frequency */
+    int overflow = 0;   /* number of elements with bit length too large */
+
+    for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+    /* In a first pass, compute the optimal bit lengths (which may
+     * overflow in the case of the bit length tree).
+     */
+    tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+    for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+        n = s->heap[h];
+        bits = tree[tree[n].Dad].Len + 1;
+        if (bits > max_length) bits = max_length, overflow++;
+        tree[n].Len = (ush)bits;
+        /* We overwrite tree[n].Dad which is no longer needed */
+
+        if (n > max_code) continue; /* not a leaf node */
+
+        s->bl_count[bits]++;
+        xbits = 0;
+        if (n >= base) xbits = extra[n-base];
+        f = tree[n].Freq;
+        s->opt_len += (ulg)f * (bits + xbits);
+        if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+    }
+    if (overflow == 0) return;
+
+    Trace((stderr,"\nbit length overflow\n"));
+    /* This happens for example on obj2 and pic of the Calgary corpus */
+
+    /* Find the first bit length which could increase: */
+    do {
+        bits = max_length-1;
+        while (s->bl_count[bits] == 0) bits--;
+        s->bl_count[bits]--;      /* move one leaf down the tree */
+        s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+        s->bl_count[max_length]--;
+        /* The brother of the overflow item also moves one step up,
+         * but this does not affect bl_count[max_length]
+         */
+        overflow -= 2;
+    } while (overflow > 0);
+
+    /* Now recompute all bit lengths, scanning in increasing frequency.
+     * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+     * lengths instead of fixing only the wrong ones. This idea is taken
+     * from 'ar' written by Haruhiko Okumura.)
+     */
+    for (bits = max_length; bits != 0; bits--) {
+        n = s->bl_count[bits];
+        while (n != 0) {
+            m = s->heap[--h];
+            if (m > max_code) continue;
+            if ((unsigned) tree[m].Len != (unsigned) bits) {
+                Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+                s->opt_len += ((long)bits - (long)tree[m].Len)
+                              *(long)tree[m].Freq;
+                tree[m].Len = (ush)bits;
+            }
+            n--;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ *     zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+    ct_data *tree;             /* the tree to decorate */
+    int max_code;              /* largest code with non zero frequency */
+    ushf *bl_count;            /* number of codes at each bit length */
+{
+    ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+    ush code = 0;              /* running code value */
+    int bits;                  /* bit index */
+    int n;                     /* code index */
+
+    /* The distribution counts are first used to generate the code values
+     * without bit reversal.
+     */
+    for (bits = 1; bits <= MAX_BITS; bits++) {
+        next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+    }
+    /* Check that the bit counts in bl_count are consistent. The last code
+     * must be all ones.
+     */
+    Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+            "inconsistent bit counts");
+    Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+    for (n = 0;  n <= max_code; n++) {
+        int len = tree[n].Len;
+        if (len == 0) continue;
+        /* Now reverse the bits */
+        tree[n].Code = bi_reverse(next_code[len]++, len);
+
+        Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+             n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+    }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ *     and corresponding code. The length opt_len is updated; static_len is
+ *     also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+    deflate_state *s;
+    tree_desc *desc; /* the tree descriptor */
+{
+    ct_data *tree         = desc->dyn_tree;
+    const ct_data *stree  = desc->stat_desc->static_tree;
+    int elems             = desc->stat_desc->elems;
+    int n, m;          /* iterate over heap elements */
+    int max_code = -1; /* largest code with non zero frequency */
+    int node;          /* new node being created */
+
+    /* Construct the initial heap, with least frequent element in
+     * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+     * heap[0] is not used.
+     */
+    s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+    for (n = 0; n < elems; n++) {
+        if (tree[n].Freq != 0) {
+            s->heap[++(s->heap_len)] = max_code = n;
+            s->depth[n] = 0;
+        } else {
+            tree[n].Len = 0;
+        }
+    }
+
+    /* The pkzip format requires that at least one distance code exists,
+     * and that at least one bit should be sent even if there is only one
+     * possible code. So to avoid special checks later on we force at least
+     * two codes of non zero frequency.
+     */
+    while (s->heap_len < 2) {
+        node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+        tree[node].Freq = 1;
+        s->depth[node] = 0;
+        s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+        /* node is 0 or 1 so it does not have extra bits */
+    }
+    desc->max_code = max_code;
+
+    /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+     * establish sub-heaps of increasing lengths:
+     */
+    for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+    /* Construct the Huffman tree by repeatedly combining the least two
+     * frequent nodes.
+     */
+    node = elems;              /* next internal node of the tree */
+    do {
+        pqremove(s, tree, n);  /* n = node of least frequency */
+        m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+        s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+        s->heap[--(s->heap_max)] = m;
+
+        /* Create a new node father of n and m */
+        tree[node].Freq = tree[n].Freq + tree[m].Freq;
+        s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ?
+                                s->depth[n] : s->depth[m]) + 1);
+        tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+        if (tree == s->bl_tree) {
+            fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+        }
+#endif
+        /* and insert the new node in the heap */
+        s->heap[SMALLEST] = node++;
+        pqdownheap(s, tree, SMALLEST);
+
+    } while (s->heap_len >= 2);
+
+    s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+    /* At this point, the fields freq and dad are set. We can now
+     * generate the bit lengths.
+     */
+    gen_bitlen(s, (tree_desc *)desc);
+
+    /* The field len is now set, we can generate the bit codes */
+    gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+    deflate_state *s;
+    ct_data *tree;   /* the tree to be scanned */
+    int max_code;    /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    if (nextlen == 0) max_count = 138, min_count = 3;
+    tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            s->bl_tree[curlen].Freq += count;
+        } else if (curlen != 0) {
+            if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+            s->bl_tree[REP_3_6].Freq++;
+        } else if (count <= 10) {
+            s->bl_tree[REPZ_3_10].Freq++;
+        } else {
+            s->bl_tree[REPZ_11_138].Freq++;
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+    deflate_state *s;
+    ct_data *tree; /* the tree to be scanned */
+    int max_code;       /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    /* tree[max_code+1].Len = -1; */  /* guard already set */
+    if (nextlen == 0) max_count = 138, min_count = 3;
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+        } else if (curlen != 0) {
+            if (curlen != prevlen) {
+                send_code(s, curlen, s->bl_tree); count--;
+            }
+            Assert(count >= 3 && count <= 6, " 3_6?");
+            send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+        } else if (count <= 10) {
+            send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+        } else {
+            send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+    deflate_state *s;
+{
+    int max_blindex;  /* index of last bit length code of non zero freq */
+
+    /* Determine the bit length frequencies for literal and distance trees */
+    scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+    scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+    /* Build the bit length tree: */
+    build_tree(s, (tree_desc *)(&(s->bl_desc)));
+    /* opt_len now includes the length of the tree representations, except
+     * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+     */
+
+    /* Determine the number of bit length codes to send. The pkzip format
+     * requires that at least 4 bit length codes be sent. (appnote.txt says
+     * 3 but the actual value used is 4.)
+     */
+    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+        if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+    }
+    /* Update opt_len to include the bit length tree and counts */
+    s->opt_len += 3*(max_blindex+1) + 5+5+4;
+    Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+            s->opt_len, s->static_len));
+
+    return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+    deflate_state *s;
+    int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+    int rank;                    /* index in bl_order */
+
+    Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+            "too many codes");
+    Tracev((stderr, "\nbl counts: "));
+    send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+    send_bits(s, dcodes-1,   5);
+    send_bits(s, blcodes-4,  4); /* not -3 as stated in appnote.txt */
+    for (rank = 0; rank < blcodes; rank++) {
+        Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+        send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+    }
+    Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+    Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+    Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void _tr_stored_block(s, buf, stored_len, eof)
+    deflate_state *s;
+    charf *buf;       /* input block */
+    ulg stored_len;   /* length of input block */
+    int eof;          /* true if this is the last block for a file */
+{
+    send_bits(s, (STORED_BLOCK<<1)+eof, 3);  /* send block type */
+#ifdef DEBUG
+    s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+    s->compressed_len += (stored_len + 4) << 3;
+#endif
+    copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ * The current inflate code requires 9 bits of lookahead. If the
+ * last two codes for the previous block (real code plus EOB) were coded
+ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ * the last real code. In this case we send two empty static blocks instead
+ * of one. (There are no problems if the previous block is stored or fixed.)
+ * To simplify the code, we assume the worst case of last real code encoded
+ * on one bit only.
+ */
+void _tr_align(s)
+    deflate_state *s;
+{
+    send_bits(s, STATIC_TREES<<1, 3);
+    send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+    s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+#endif
+    bi_flush(s);
+    /* Of the 10 bits for the empty block, we have already sent
+     * (10 - bi_valid) bits. The lookahead for the last real code (before
+     * the EOB of the previous block) was thus at least one plus the length
+     * of the EOB plus what we have just sent of the empty static block.
+     */
+    if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
+        send_bits(s, STATIC_TREES<<1, 3);
+        send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+        s->compressed_len += 10L;
+#endif
+        bi_flush(s);
+    }
+    s->last_eob_len = 7;
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file.
+ */
+void _tr_flush_block(s, buf, stored_len, eof)
+    deflate_state *s;
+    charf *buf;       /* input block, or NULL if too old */
+    ulg stored_len;   /* length of input block */
+    int eof;          /* true if this is the last block for a file */
+{
+    ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+    int max_blindex = 0;  /* index of last bit length code of non zero freq */
+
+    /* Build the Huffman trees unless a stored block is forced */
+    if (s->level > 0) {
+
+        /* Check if the file is binary or text */
+        if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN)
+            set_data_type(s);
+
+        /* Construct the literal and distance trees */
+        build_tree(s, (tree_desc *)(&(s->l_desc)));
+        Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+                s->static_len));
+
+        build_tree(s, (tree_desc *)(&(s->d_desc)));
+        Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+                s->static_len));
+        /* At this point, opt_len and static_len are the total bit lengths of
+         * the compressed block data, excluding the tree representations.
+         */
+
+        /* Build the bit length tree for the above two trees, and get the index
+         * in bl_order of the last bit length code to send.
+         */
+        max_blindex = build_bl_tree(s);
+
+        /* Determine the best encoding. Compute the block lengths in bytes. */
+        opt_lenb = (s->opt_len+3+7)>>3;
+        static_lenb = (s->static_len+3+7)>>3;
+
+        Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+                opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+                s->last_lit));
+
+        if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+    } else {
+        Assert(buf != (char*)0, "lost buf");
+        opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+    }
+
+#ifdef FORCE_STORED
+    if (buf != (char*)0) { /* force stored block */
+#else
+    if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+                       /* 4: two words for the lengths */
+#endif
+        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+         * Otherwise we can't have processed more than WSIZE input bytes since
+         * the last block flush, because compression would have been
+         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+         * transform a block into a stored block.
+         */
+        _tr_stored_block(s, buf, stored_len, eof);
+
+#ifdef FORCE_STATIC
+    } else if (static_lenb >= 0) { /* force static trees */
+#else
+    } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) {
+#endif
+        send_bits(s, (STATIC_TREES<<1)+eof, 3);
+        compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+#ifdef DEBUG
+        s->compressed_len += 3 + s->static_len;
+#endif
+    } else {
+        send_bits(s, (DYN_TREES<<1)+eof, 3);
+        send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+                       max_blindex+1);
+        compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
+#ifdef DEBUG
+        s->compressed_len += 3 + s->opt_len;
+#endif
+    }
+    Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+    /* The above check is made mod 2^32, for files larger than 512 MB
+     * and uLong implemented on 32 bits.
+     */
+    init_block(s);
+
+    if (eof) {
+        bi_windup(s);
+#ifdef DEBUG
+        s->compressed_len += 7;  /* align on byte boundary */
+#endif
+    }
+    Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+           s->compressed_len-7*eof));
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int _tr_tally (s, dist, lc)
+    deflate_state *s;
+    unsigned dist;  /* distance of matched string */
+    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+    s->d_buf[s->last_lit] = (ush)dist;
+    s->l_buf[s->last_lit++] = (uch)lc;
+    if (dist == 0) {
+        /* lc is the unmatched char */
+        s->dyn_ltree[lc].Freq++;
+    } else {
+        s->matches++;
+        /* Here, lc is the match length - MIN_MATCH */
+        dist--;             /* dist = match distance - 1 */
+        Assert((ush)dist < (ush)MAX_DIST(s) &&
+               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+               (ush)d_code(dist) < (ush)D_CODES,  "_tr_tally: bad match");
+
+        s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
+        s->dyn_dtree[d_code(dist)].Freq++;
+    }
+
+#ifdef TRUNCATE_BLOCK
+    /* Try to guess if it is profitable to stop the current block here */
+    if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
+        /* Compute an upper bound for the compressed length */
+        ulg out_length = (ulg)s->last_lit*8L;
+        ulg in_length = (ulg)((long)s->strstart - s->block_start);
+        int dcode;
+        for (dcode = 0; dcode < D_CODES; dcode++) {
+            out_length += (ulg)s->dyn_dtree[dcode].Freq *
+                (5L+extra_dbits[dcode]);
+        }
+        out_length >>= 3;
+        Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+               s->last_lit, in_length, out_length,
+               100L - out_length*100L/in_length));
+        if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+    }
+#endif
+    return (s->last_lit == s->lit_bufsize-1);
+    /* We avoid equality with lit_bufsize because of wraparound at 64K
+     * on 16 bit machines and because stored blocks are restricted to
+     * 64K-1 bytes.
+     */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+    deflate_state *s;
+    ct_data *ltree; /* literal tree */
+    ct_data *dtree; /* distance tree */
+{
+    unsigned dist;      /* distance of matched string */
+    int lc;             /* match length or unmatched char (if dist == 0) */
+    unsigned lx = 0;    /* running index in l_buf */
+    unsigned code;      /* the code to send */
+    int extra;          /* number of extra bits to send */
+
+    if (s->last_lit != 0) do {
+        dist = s->d_buf[lx];
+        lc = s->l_buf[lx++];
+        if (dist == 0) {
+            send_code(s, lc, ltree); /* send a literal byte */
+            Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+        } else {
+            /* Here, lc is the match length - MIN_MATCH */
+            code = _length_code[lc];
+            send_code(s, code+LITERALS+1, ltree); /* send the length code */
+            extra = extra_lbits[code];
+            if (extra != 0) {
+                lc -= base_length[code];
+                send_bits(s, lc, extra);       /* send the extra length bits */
+            }
+            dist--; /* dist is now the match distance - 1 */
+            code = d_code(dist);
+            Assert (code < D_CODES, "bad d_code");
+
+            send_code(s, code, dtree);       /* send the distance code */
+            extra = extra_dbits[code];
+            if (extra != 0) {
+                dist -= base_dist[code];
+                send_bits(s, dist, extra);   /* send the extra distance bits */
+            }
+        } /* literal or match pair ? */
+
+        /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+        Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
+               "pendingBuf overflow");
+
+    } while (lx < s->last_lit);
+
+    send_code(s, END_BLOCK, ltree);
+    s->last_eob_len = ltree[END_BLOCK].Len;
+}
+
+/* ===========================================================================
+ * Set the data type to BINARY or TEXT, using a crude approximation:
+ * set it to Z_TEXT if all symbols are either printable characters (33 to 255)
+ * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise.
+ * IN assertion: the fields Freq of dyn_ltree are set.
+ */
+local void set_data_type(s)
+    deflate_state *s;
+{
+    int n;
+
+    for (n = 0; n < 9; n++)
+        if (s->dyn_ltree[n].Freq != 0)
+            break;
+    if (n == 9)
+        for (n = 14; n < 32; n++)
+            if (s->dyn_ltree[n].Freq != 0)
+                break;
+    s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY;
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+    unsigned code; /* the value to invert */
+    int len;       /* its bit length */
+{
+    register unsigned res = 0;
+    do {
+        res |= code & 1;
+        code >>= 1, res <<= 1;
+    } while (--len > 0);
+    return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+    deflate_state *s;
+{
+    if (s->bi_valid == 16) {
+        put_short(s, s->bi_buf);
+        s->bi_buf = 0;
+        s->bi_valid = 0;
+    } else if (s->bi_valid >= 8) {
+        put_byte(s, (Byte)s->bi_buf);
+        s->bi_buf >>= 8;
+        s->bi_valid -= 8;
+    }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(s)
+    deflate_state *s;
+{
+    if (s->bi_valid > 8) {
+        put_short(s, s->bi_buf);
+    } else if (s->bi_valid > 0) {
+        put_byte(s, (Byte)s->bi_buf);
+    }
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+#ifdef DEBUG
+    s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+    deflate_state *s;
+    charf    *buf;    /* the input data */
+    unsigned len;     /* its length */
+    int      header;  /* true if block header must be written */
+{
+    bi_windup(s);        /* align on byte boundary */
+    s->last_eob_len = 8; /* enough lookahead for inflate */
+
+    if (header) {
+        put_short(s, (ush)len);
+        put_short(s, (ush)~len);
+#ifdef DEBUG
+        s->bits_sent += 2*16;
+#endif
+    }
+#ifdef DEBUG
+    s->bits_sent += (ulg)len<<3;
+#endif
+    while (len--) {
+        put_byte(s, *buf++);
+    }
+}
diff --git a/src/unison/physfs-1.1.1/zlib123/trees.h b/src/unison/physfs-1.1.1/zlib123/trees.h
new file mode 100644 (file)
index 0000000..72facf9
--- /dev/null
@@ -0,0 +1,128 @@
+/* header created automatically with -DGEN_TREES_H */
+
+local const ct_data static_ltree[L_CODES+2] = {
+{{ 12},{  8}}, {{140},{  8}}, {{ 76},{  8}}, {{204},{  8}}, {{ 44},{  8}},
+{{172},{  8}}, {{108},{  8}}, {{236},{  8}}, {{ 28},{  8}}, {{156},{  8}},
+{{ 92},{  8}}, {{220},{  8}}, {{ 60},{  8}}, {{188},{  8}}, {{124},{  8}},
+{{252},{  8}}, {{  2},{  8}}, {{130},{  8}}, {{ 66},{  8}}, {{194},{  8}},
+{{ 34},{  8}}, {{162},{  8}}, {{ 98},{  8}}, {{226},{  8}}, {{ 18},{  8}},
+{{146},{  8}}, {{ 82},{  8}}, {{210},{  8}}, {{ 50},{  8}}, {{178},{  8}},
+{{114},{  8}}, {{242},{  8}}, {{ 10},{  8}}, {{138},{  8}}, {{ 74},{  8}},
+{{202},{  8}}, {{ 42},{  8}}, {{170},{  8}}, {{106},{  8}}, {{234},{  8}},
+{{ 26},{  8}}, {{154},{  8}}, {{ 90},{  8}}, {{218},{  8}}, {{ 58},{  8}},
+{{186},{  8}}, {{122},{  8}}, {{250},{  8}}, {{  6},{  8}}, {{134},{  8}},
+{{ 70},{  8}}, {{198},{  8}}, {{ 38},{  8}}, {{166},{  8}}, {{102},{  8}},
+{{230},{  8}}, {{ 22},{  8}}, {{150},{  8}}, {{ 86},{  8}}, {{214},{  8}},
+{{ 54},{  8}}, {{182},{  8}}, {{118},{  8}}, {{246},{  8}}, {{ 14},{  8}},
+{{142},{  8}}, {{ 78},{  8}}, {{206},{  8}}, {{ 46},{  8}}, {{174},{  8}},
+{{110},{  8}}, {{238},{  8}}, {{ 30},{  8}}, {{158},{  8}}, {{ 94},{  8}},
+{{222},{  8}}, {{ 62},{  8}}, {{190},{  8}}, {{126},{  8}}, {{254},{  8}},
+{{  1},{  8}}, {{129},{  8}}, {{ 65},{  8}}, {{193},{  8}}, {{ 33},{  8}},
+{{161},{  8}}, {{ 97},{  8}}, {{225},{  8}}, {{ 17},{  8}}, {{145},{  8}},
+{{ 81},{  8}}, {{209},{  8}}, {{ 49},{  8}}, {{177},{  8}}, {{113},{  8}},
+{{241},{  8}}, {{  9},{  8}}, {{137},{  8}}, {{ 73},{  8}}, {{201},{  8}},
+{{ 41},{  8}}, {{169},{  8}}, {{105},{  8}}, {{233},{  8}}, {{ 25},{  8}},
+{{153},{  8}}, {{ 89},{  8}}, {{217},{  8}}, {{ 57},{  8}}, {{185},{  8}},
+{{121},{  8}}, {{249},{  8}}, {{  5},{  8}}, {{133},{  8}}, {{ 69},{  8}},
+{{197},{  8}}, {{ 37},{  8}}, {{165},{  8}}, {{101},{  8}}, {{229},{  8}},
+{{ 21},{  8}}, {{149},{  8}}, {{ 85},{  8}}, {{213},{  8}}, {{ 53},{  8}},
+{{181},{  8}}, {{117},{  8}}, {{245},{  8}}, {{ 13},{  8}}, {{141},{  8}},
+{{ 77},{  8}}, {{205},{  8}}, {{ 45},{  8}}, {{173},{  8}}, {{109},{  8}},
+{{237},{  8}}, {{ 29},{  8}}, {{157},{  8}}, {{ 93},{  8}}, {{221},{  8}},
+{{ 61},{  8}}, {{189},{  8}}, {{125},{  8}}, {{253},{  8}}, {{ 19},{  9}},
+{{275},{  9}}, {{147},{  9}}, {{403},{  9}}, {{ 83},{  9}}, {{339},{  9}},
+{{211},{  9}}, {{467},{  9}}, {{ 51},{  9}}, {{307},{  9}}, {{179},{  9}},
+{{435},{  9}}, {{115},{  9}}, {{371},{  9}}, {{243},{  9}}, {{499},{  9}},
+{{ 11},{  9}}, {{267},{  9}}, {{139},{  9}}, {{395},{  9}}, {{ 75},{  9}},
+{{331},{  9}}, {{203},{  9}}, {{459},{  9}}, {{ 43},{  9}}, {{299},{  9}},
+{{171},{  9}}, {{427},{  9}}, {{107},{  9}}, {{363},{  9}}, {{235},{  9}},
+{{491},{  9}}, {{ 27},{  9}}, {{283},{  9}}, {{155},{  9}}, {{411},{  9}},
+{{ 91},{  9}}, {{347},{  9}}, {{219},{  9}}, {{475},{  9}}, {{ 59},{  9}},
+{{315},{  9}}, {{187},{  9}}, {{443},{  9}}, {{123},{  9}}, {{379},{  9}},
+{{251},{  9}}, {{507},{  9}}, {{  7},{  9}}, {{263},{  9}}, {{135},{  9}},
+{{391},{  9}}, {{ 71},{  9}}, {{327},{  9}}, {{199},{  9}}, {{455},{  9}},
+{{ 39},{  9}}, {{295},{  9}}, {{167},{  9}}, {{423},{  9}}, {{103},{  9}},
+{{359},{  9}}, {{231},{  9}}, {{487},{  9}}, {{ 23},{  9}}, {{279},{  9}},
+{{151},{  9}}, {{407},{  9}}, {{ 87},{  9}}, {{343},{  9}}, {{215},{  9}},
+{{471},{  9}}, {{ 55},{  9}}, {{311},{  9}}, {{183},{  9}}, {{439},{  9}},
+{{119},{  9}}, {{375},{  9}}, {{247},{  9}}, {{503},{  9}}, {{ 15},{  9}},
+{{271},{  9}}, {{143},{  9}}, {{399},{  9}}, {{ 79},{  9}}, {{335},{  9}},
+{{207},{  9}}, {{463},{  9}}, {{ 47},{  9}}, {{303},{  9}}, {{175},{  9}},
+{{431},{  9}}, {{111},{  9}}, {{367},{  9}}, {{239},{  9}}, {{495},{  9}},
+{{ 31},{  9}}, {{287},{  9}}, {{159},{  9}}, {{415},{  9}}, {{ 95},{  9}},
+{{351},{  9}}, {{223},{  9}}, {{479},{  9}}, {{ 63},{  9}}, {{319},{  9}},
+{{191},{  9}}, {{447},{  9}}, {{127},{  9}}, {{383},{  9}}, {{255},{  9}},
+{{511},{  9}}, {{  0},{  7}}, {{ 64},{  7}}, {{ 32},{  7}}, {{ 96},{  7}},
+{{ 16},{  7}}, {{ 80},{  7}}, {{ 48},{  7}}, {{112},{  7}}, {{  8},{  7}},
+{{ 72},{  7}}, {{ 40},{  7}}, {{104},{  7}}, {{ 24},{  7}}, {{ 88},{  7}},
+{{ 56},{  7}}, {{120},{  7}}, {{  4},{  7}}, {{ 68},{  7}}, {{ 36},{  7}},
+{{100},{  7}}, {{ 20},{  7}}, {{ 84},{  7}}, {{ 52},{  7}}, {{116},{  7}},
+{{  3},{  8}}, {{131},{  8}}, {{ 67},{  8}}, {{195},{  8}}, {{ 35},{  8}},
+{{163},{  8}}, {{ 99},{  8}}, {{227},{  8}}
+};
+
+local const ct_data static_dtree[D_CODES] = {
+{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
+{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
+{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
+{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
+{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
+{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
+};
+
+const uch _dist_code[DIST_CODE_LEN] = {
+ 0,  1,  2,  3,  4,  4,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  8,
+ 8,  8,  8,  8,  9,  9,  9,  9,  9,  9,  9,  9, 10, 10, 10, 10, 10, 10, 10, 10,
+10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  0,  0, 16, 17,
+18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+};
+
+const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {
+ 0,  1,  2,  3,  4,  5,  6,  7,  8,  8,  9,  9, 10, 10, 11, 11, 12, 12, 12, 12,
+13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
+};
+
+local const int base_length[LENGTH_CODES] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+64, 80, 96, 112, 128, 160, 192, 224, 0
+};
+
+local const int base_dist[D_CODES] = {
+    0,     1,     2,     3,     4,     6,     8,    12,    16,    24,
+   32,    48,    64,    96,   128,   192,   256,   384,   512,   768,
+ 1024,  1536,  2048,  3072,  4096,  6144,  8192, 12288, 16384, 24576
+};
+
diff --git a/src/unison/physfs-1.1.1/zlib123/uncompr.c b/src/unison/physfs-1.1.1/zlib123/uncompr.c
new file mode 100644 (file)
index 0000000..b59e3d0
--- /dev/null
@@ -0,0 +1,61 @@
+/* uncompr.c -- decompress a memory buffer
+ * Copyright (C) 1995-2003 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+     Decompresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be large enough to hold the
+   entire uncompressed data. (The size of the uncompressed data must have
+   been saved previously by the compressor and transmitted to the decompressor
+   by some mechanism outside the scope of this compression library.)
+   Upon exit, destLen is the actual size of the compressed buffer.
+     This function can be used to decompress a whole file at once if the
+   input file is mmap'ed.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+int ZEXPORT uncompress (dest, destLen, source, sourceLen)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong sourceLen;
+{
+    z_stream stream;
+    int err;
+
+    stream.next_in = (Bytef*)source;
+    stream.avail_in = (uInt)sourceLen;
+    /* Check for source > 64K on 16-bit machine: */
+    if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+
+    stream.next_out = dest;
+    stream.avail_out = (uInt)*destLen;
+    if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+    stream.zalloc = (alloc_func)0;
+    stream.zfree = (free_func)0;
+
+    err = inflateInit(&stream);
+    if (err != Z_OK) return err;
+
+    err = inflate(&stream, Z_FINISH);
+    if (err != Z_STREAM_END) {
+        inflateEnd(&stream);
+        if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
+            return Z_DATA_ERROR;
+        return err;
+    }
+    *destLen = stream.total_out;
+
+    err = inflateEnd(&stream);
+    return err;
+}
diff --git a/src/unison/physfs-1.1.1/zlib123/zconf.h b/src/unison/physfs-1.1.1/zlib123/zconf.h
new file mode 100644 (file)
index 0000000..03a9431
--- /dev/null
@@ -0,0 +1,332 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+#  define deflateInit_          z_deflateInit_
+#  define deflate               z_deflate
+#  define deflateEnd            z_deflateEnd
+#  define inflateInit_          z_inflateInit_
+#  define inflate               z_inflate
+#  define inflateEnd            z_inflateEnd
+#  define deflateInit2_         z_deflateInit2_
+#  define deflateSetDictionary  z_deflateSetDictionary
+#  define deflateCopy           z_deflateCopy
+#  define deflateReset          z_deflateReset
+#  define deflateParams         z_deflateParams
+#  define deflateBound          z_deflateBound
+#  define deflatePrime          z_deflatePrime
+#  define inflateInit2_         z_inflateInit2_
+#  define inflateSetDictionary  z_inflateSetDictionary
+#  define inflateSync           z_inflateSync
+#  define inflateSyncPoint      z_inflateSyncPoint
+#  define inflateCopy           z_inflateCopy
+#  define inflateReset          z_inflateReset
+#  define inflateBack           z_inflateBack
+#  define inflateBackEnd        z_inflateBackEnd
+#  define compress              z_compress
+#  define compress2             z_compress2
+#  define compressBound         z_compressBound
+#  define uncompress            z_uncompress
+#  define adler32               z_adler32
+#  define crc32                 z_crc32
+#  define get_crc_table         z_get_crc_table
+#  define zError                z_zError
+
+#  define alloc_func            z_alloc_func
+#  define free_func             z_free_func
+#  define in_func               z_in_func
+#  define out_func              z_out_func
+#  define Byte                  z_Byte
+#  define uInt                  z_uInt
+#  define uLong                 z_uLong
+#  define Bytef                 z_Bytef
+#  define charf                 z_charf
+#  define intf                  z_intf
+#  define uIntf                 z_uIntf
+#  define uLongf                z_uLongf
+#  define voidpf                z_voidpf
+#  define voidp                 z_voidp
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+#  define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+#  define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+#  define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+#  ifndef WIN32
+#    define WIN32
+#  endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+#  if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+#    ifndef SYS16BIT
+#      define SYS16BIT
+#    endif
+#  endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+#  define MAXSEG_64K
+#endif
+#ifdef MSDOS
+#  define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+#  ifndef STDC
+#    define STDC
+#  endif
+#  if __STDC_VERSION__ >= 199901L
+#    ifndef STDC99
+#      define STDC99
+#    endif
+#  endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+#  define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC)    /* iSeries (formerly AS/400). */
+#  define STDC
+#endif
+
+#ifndef STDC
+#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+#    define const       /* note: need a more gentle solution here */
+#  endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+#  define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  ifdef MAXSEG_64K
+#    define MAX_MEM_LEVEL 8
+#  else
+#    define MAX_MEM_LEVEL 9
+#  endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            (1 << (windowBits+2)) +  (1 << (memLevel+9))
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+#  if defined(M_I86SM) || defined(M_I86MM)
+     /* MSC small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef _MSC_VER
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#  if (defined(__SMALL__) || defined(__MEDIUM__))
+     /* Turbo C small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef __BORLANDC__
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+   /* If building or using zlib as a DLL, define ZLIB_DLL.
+    * This is not mandatory, but it offers a little performance increase.
+    */
+#  ifdef ZLIB_DLL
+#    if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+#      ifdef ZLIB_INTERNAL
+#        define ZEXTERN extern __declspec(dllexport)
+#      else
+#        define ZEXTERN extern __declspec(dllimport)
+#      endif
+#    endif
+#  endif  /* ZLIB_DLL */
+   /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+    * define ZLIB_WINAPI.
+    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+    */
+#  ifdef ZLIB_WINAPI
+#    ifdef FAR
+#      undef FAR
+#    endif
+#    include <windows.h>
+     /* No need for _export, use ZLIB.DEF instead. */
+     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+#    define ZEXPORT WINAPI
+#    ifdef WIN32
+#      define ZEXPORTVA WINAPIV
+#    else
+#      define ZEXPORTVA FAR CDECL
+#    endif
+#  endif
+#endif
+
+#if defined (__BEOS__)
+#  ifdef ZLIB_DLL
+#    ifdef ZLIB_INTERNAL
+#      define ZEXPORT   __declspec(dllexport)
+#      define ZEXPORTVA __declspec(dllexport)
+#    else
+#      define ZEXPORT   __declspec(dllimport)
+#      define ZEXPORTVA __declspec(dllimport)
+#    endif
+#  endif
+#endif
+
+#ifndef ZEXTERN
+#  define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+#  define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+#  define ZEXPORTVA
+#endif
+
+#ifndef FAR
+#  define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char  Byte;  /* 8 bits */
+#endif
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+#  define Bytef Byte FAR
+#else
+   typedef Byte  FAR Bytef;
+#endif
+typedef char  FAR charf;
+typedef int   FAR intf;
+typedef uInt  FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+   typedef void const *voidpc;
+   typedef void FAR   *voidpf;
+   typedef void       *voidp;
+#else
+   typedef Byte const *voidpc;
+   typedef Byte FAR   *voidpf;
+   typedef Byte       *voidp;
+#endif
+
+#if 0           /* HAVE_UNISTD_H -- this line is updated by ./configure */
+#  include <sys/types.h> /* for off_t */
+#  include <unistd.h>    /* for SEEK_* and off_t */
+#  ifdef VMS
+#    include <unixio.h>   /* for off_t */
+#  endif
+#  define z_off_t off_t
+#endif
+#ifndef SEEK_SET
+#  define SEEK_SET        0       /* Seek from beginning of file.  */
+#  define SEEK_CUR        1       /* Seek from current position.  */
+#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
+#endif
+#ifndef z_off_t
+#  define z_off_t long
+#endif
+
+#if defined(__OS400__)
+#  define NO_vsnprintf
+#endif
+
+#if defined(__MVS__)
+#  define NO_vsnprintf
+#  ifdef FAR
+#    undef FAR
+#  endif
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+#   pragma map(deflateInit_,"DEIN")
+#   pragma map(deflateInit2_,"DEIN2")
+#   pragma map(deflateEnd,"DEEND")
+#   pragma map(deflateBound,"DEBND")
+#   pragma map(inflateInit_,"ININ")
+#   pragma map(inflateInit2_,"ININ2")
+#   pragma map(inflateEnd,"INEND")
+#   pragma map(inflateSync,"INSY")
+#   pragma map(inflateSetDictionary,"INSEDI")
+#   pragma map(compressBound,"CMBND")
+#   pragma map(inflate_table,"INTABL")
+#   pragma map(inflate_fast,"INFA")
+#   pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
diff --git a/src/unison/physfs-1.1.1/zlib123/zlib.h b/src/unison/physfs-1.1.1/zlib123/zlib.h
new file mode 100644 (file)
index 0000000..0228179
--- /dev/null
@@ -0,0 +1,1357 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.2.3, July 18th, 2005
+
+  Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
+
+  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.
+
+  Jean-loup Gailly        Mark Adler
+  jloup@gzip.org          madler@alumni.caltech.edu
+
+
+  The data format used by the zlib library is described by RFCs (Request for
+  Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
+  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef ZLIB_H
+#define ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.2.3"
+#define ZLIB_VERNUM 0x1230
+
+/*
+     The 'zlib' compression library provides in-memory compression and
+  decompression functions, including integrity checks of the uncompressed
+  data.  This version of the library supports only one compression method
+  (deflation) but other algorithms will be added later and will have the same
+  stream interface.
+
+     Compression can be done in a single step if the buffers are large
+  enough (for example if an input file is mmap'ed), or can be done by
+  repeated calls of the compression function.  In the latter case, the
+  application must provide more input and/or consume the output
+  (providing more output space) before each call.
+
+     The compressed data format used by default by the in-memory functions is
+  the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
+  around a deflate stream, which is itself documented in RFC 1951.
+
+     The library also supports reading and writing files in gzip (.gz) format
+  with an interface similar to that of stdio using the functions that start
+  with "gz".  The gzip format is different from the zlib format.  gzip is a
+  gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
+
+     This library can optionally read and write gzip streams in memory as well.
+
+     The zlib format was designed to be compact and fast for use in memory
+  and on communications channels.  The gzip format was designed for single-
+  file compression on file systems, has a larger header than zlib to maintain
+  directory information, and uses a different, slower check method than zlib.
+
+     The library does not install any signal handler. The decoder checks
+  the consistency of the compressed data, so the library should never
+  crash even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+    Bytef    *next_in;  /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total nb of input bytes read so far */
+
+    Bytef    *next_out; /* next output byte should be put there */
+    uInt     avail_out; /* remaining free space at next_out */
+    uLong    total_out; /* total nb of bytes output so far */
+
+    char     *msg;      /* last error message, NULL if no error */
+    struct internal_state FAR *state; /* not visible by applications */
+
+    alloc_func zalloc;  /* used to allocate the internal state */
+    free_func  zfree;   /* used to free the internal state */
+    voidpf     opaque;  /* private data object passed to zalloc and zfree */
+
+    int     data_type;  /* best guess about the data type: binary or text */
+    uLong   adler;      /* adler32 value of the uncompressed data */
+    uLong   reserved;   /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+     gzip header information passed to and from zlib routines.  See RFC 1952
+  for more details on the meanings of these fields.
+*/
+typedef struct gz_header_s {
+    int     text;       /* true if compressed data believed to be text */
+    uLong   time;       /* modification time */
+    int     xflags;     /* extra flags (not used when writing a gzip file) */
+    int     os;         /* operating system */
+    Bytef   *extra;     /* pointer to extra field or Z_NULL if none */
+    uInt    extra_len;  /* extra field length (valid if extra != Z_NULL) */
+    uInt    extra_max;  /* space at extra (only when reading header) */
+    Bytef   *name;      /* pointer to zero-terminated file name or Z_NULL */
+    uInt    name_max;   /* space at name (only when reading header) */
+    Bytef   *comment;   /* pointer to zero-terminated comment or Z_NULL */
+    uInt    comm_max;   /* space at comment (only when reading header) */
+    int     hcrc;       /* true if there was or will be a header crc */
+    int     done;       /* true when done reading gzip header (not used
+                           when writing a gzip file) */
+} gz_header;
+
+typedef gz_header FAR *gz_headerp;
+
+/*
+   The application must update next_in and avail_in when avail_in has
+   dropped to zero. It must update next_out and avail_out when avail_out
+   has dropped to zero. The application must initialize zalloc, zfree and
+   opaque before calling the init function. All other fields are set by the
+   compression library and must not be updated by the application.
+
+   The opaque value provided by the application will be passed as the first
+   parameter for calls of zalloc and zfree. This can be useful for custom
+   memory management. The compression library attaches no meaning to the
+   opaque value.
+
+   zalloc must return Z_NULL if there is not enough memory for the object.
+   If zlib is used in a multi-threaded application, zalloc and zfree must be
+   thread safe.
+
+   On 16-bit systems, the functions zalloc and zfree must be able to allocate
+   exactly 65536 bytes, but will not be required to allocate more than this
+   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+   pointers returned by zalloc for objects of exactly 65536 bytes *must*
+   have their offset normalized to zero. The default allocation function
+   provided by this library ensures this (see zutil.c). To reduce memory
+   requirements and avoid any allocation of 64K objects, at the expense of
+   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+   The fields total_in and total_out can be used for statistics or
+   progress reports. After compression, total_in holds the total size of
+   the uncompressed data and may be saved for use in the decompressor
+   (particularly if the decompressor wants to decompress everything in
+   a single step).
+*/
+
+                        /* constants */
+
+#define Z_NO_FLUSH      0
+#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_SYNC_FLUSH    2
+#define Z_FULL_FLUSH    3
+#define Z_FINISH        4
+#define Z_BLOCK         5
+/* Allowed flush values; see deflate() and inflate() below for details */
+
+#define Z_OK            0
+#define Z_STREAM_END    1
+#define Z_NEED_DICT     2
+#define Z_ERRNO        (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR   (-3)
+#define Z_MEM_ERROR    (-4)
+#define Z_BUF_ERROR    (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION         0
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1)
+/* compression levels */
+
+#define Z_FILTERED            1
+#define Z_HUFFMAN_ONLY        2
+#define Z_RLE                 3
+#define Z_FIXED               4
+#define Z_DEFAULT_STRATEGY    0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY   0
+#define Z_TEXT     1
+#define Z_ASCII    Z_TEXT   /* for compatibility with 1.2.2 and earlier */
+#define Z_UNKNOWN  2
+/* Possible values of the data_type field (though see inflate()) */
+
+#define Z_DEFLATED   8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+                        /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+   If the first character differs, the library code actually used is
+   not compatible with the zlib.h header file used by the application.
+   This check is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+     Initializes the internal stream state for compression. The fields
+   zalloc, zfree and opaque must be initialized before by the caller.
+   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+   use default allocation functions.
+
+     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+   1 gives best speed, 9 gives best compression, 0 gives no compression at
+   all (the input data is simply copied a block at a time).
+   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+   compression (currently equivalent to level 6).
+
+     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+   with the version assumed by the caller (ZLIB_VERSION).
+   msg is set to null if there is no error message.  deflateInit does not
+   perform any compression: this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+    deflate compresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may introduce some
+  output latency (reading input without producing any output) except when
+  forced to flush.
+
+    The detailed semantics are as follows. deflate performs one or both of the
+  following actions:
+
+  - Compress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in and avail_in are updated and
+    processing will resume at this point for the next call of deflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly. This action is forced if the parameter flush is non zero.
+    Forcing flush frequently degrades the compression ratio, so this parameter
+    should be set only when necessary (in interactive applications).
+    Some output may be provided even if flush is not set.
+
+  Before the call of deflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating avail_in or avail_out accordingly; avail_out
+  should never be zero before the call. The application can consume the
+  compressed output when it wants, for example when the output buffer is full
+  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+  and with zero avail_out, it must be called again after making room in the
+  output buffer because there might be more output pending.
+
+    Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
+  decide how much data to accumualte before producing output, in order to
+  maximize compression.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+  flushed to the output buffer and the output is aligned on a byte boundary, so
+  that the decompressor can get all input data available so far. (In particular
+  avail_in is zero after the call if enough output space has been provided
+  before the call.)  Flushing may degrade compression for some compression
+  algorithms and so it should be used only when necessary.
+
+    If flush is set to Z_FULL_FLUSH, all output is flushed as with
+  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+  restart from this point if previous compressed data has been damaged or if
+  random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+  compression.
+
+    If deflate returns with avail_out == 0, this function must be called again
+  with the same value of the flush parameter and more output space (updated
+  avail_out), until the flush is complete (deflate returns with non-zero
+  avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
+  avail_out is greater than six to avoid repeated flush markers due to
+  avail_out == 0 on return.
+
+    If the parameter flush is set to Z_FINISH, pending input is processed,
+  pending output is flushed and deflate returns with Z_STREAM_END if there
+  was enough output space; if deflate returns with Z_OK, this function must be
+  called again with Z_FINISH and more output space (updated avail_out) but no
+  more input data, until it returns with Z_STREAM_END or an error. After
+  deflate has returned Z_STREAM_END, the only possible operations on the
+  stream are deflateReset or deflateEnd.
+
+    Z_FINISH can be used immediately after deflateInit if all the compression
+  is to be done in a single step. In this case, avail_out must be at least
+  the value returned by deflateBound (see below). If deflate does not return
+  Z_STREAM_END, then it must be called again as described above.
+
+    deflate() sets strm->adler to the adler32 checksum of all input read
+  so far (that is, total_in bytes).
+
+    deflate() may update strm->data_type if it can make a good guess about
+  the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered
+  binary. This field is only for information purposes and does not affect
+  the compression algorithm in any manner.
+
+    deflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if all input has been
+  consumed and all output has been produced (only when flush is set to
+  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
+  (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not
+  fatal, and deflate() can be called again with more input and more output
+  space to continue compressing.
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+   prematurely (some input or output was discarded). In the error case,
+   msg may be set but then points to a static string (which must not be
+   deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+     Initializes the internal stream state for decompression. The fields
+   next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+   the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
+   value depends on the compression method), inflateInit determines the
+   compression method from the zlib header and allocates all data structures
+   accordingly; otherwise the allocation will be deferred to the first call of
+   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+   use default allocation functions.
+
+     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+   version assumed by the caller.  msg is set to null if there is no error
+   message. inflateInit does not perform any decompression apart from reading
+   the zlib header if present: this will be done by inflate().  (So next_in and
+   avail_in may be modified, but next_out and avail_out are unchanged.)
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+    inflate decompresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may introduce
+  some output latency (reading input without producing any output) except when
+  forced to flush.
+
+  The detailed semantics are as follows. inflate performs one or both of the
+  following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in is updated and processing
+    will resume at this point for the next call of inflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  inflate() provides as much output as possible, until there
+    is no more input data or no more space in the output buffer (see below
+    about the flush parameter).
+
+  Before the call of inflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating the next_* and avail_* values accordingly.
+  The application can consume the uncompressed output when it wants, for
+  example when the output buffer is full (avail_out == 0), or after each
+  call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+  must be called again after making room in the output buffer because there
+  might be more output pending.
+
+    The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH,
+  Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much
+  output as possible to the output buffer. Z_BLOCK requests that inflate() stop
+  if and when it gets to the next deflate block boundary. When decoding the
+  zlib or gzip format, this will cause inflate() to return immediately after
+  the header and before the first block. When doing a raw inflate, inflate()
+  will go ahead and process the first block, and will return when it gets to
+  the end of that block, or when it runs out of data.
+
+    The Z_BLOCK option assists in appending to or combining deflate streams.
+  Also to assist in this, on return inflate() will set strm->data_type to the
+  number of unused bits in the last byte taken from strm->next_in, plus 64
+  if inflate() is currently decoding the last block in the deflate stream,
+  plus 128 if inflate() returned immediately after decoding an end-of-block
+  code or decoding the complete header up to just before the first byte of the
+  deflate stream. The end-of-block will not be indicated until all of the
+  uncompressed data from that block has been written to strm->next_out.  The
+  number of unused bits may in general be greater than seven, except when
+  bit 7 of data_type is set, in which case the number of unused bits will be
+  less than eight.
+
+    inflate() should normally be called until it returns Z_STREAM_END or an
+  error. However if all decompression is to be performed in a single step
+  (a single call of inflate), the parameter flush should be set to
+  Z_FINISH. In this case all pending input is processed and all pending
+  output is flushed; avail_out must be large enough to hold all the
+  uncompressed data. (The size of the uncompressed data may have been saved
+  by the compressor for this purpose.) The next operation on this stream must
+  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+  is never required, but can be used to inform inflate that a faster approach
+  may be used for the single inflate() call.
+
+     In this implementation, inflate() always flushes as much output as
+  possible to the output buffer, and always uses the faster approach on the
+  first call. So the only effect of the flush parameter in this implementation
+  is on the return value of inflate(), as noted below, or when it returns early
+  because Z_BLOCK is used.
+
+     If a preset dictionary is needed after this call (see inflateSetDictionary
+  below), inflate sets strm->adler to the adler32 checksum of the dictionary
+  chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+  strm->adler to the adler32 checksum of all output produced so far (that is,
+  total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+  below. At the end of the stream, inflate() checks that its computed adler32
+  checksum is equal to that saved by the compressor and returns Z_STREAM_END
+  only if the checksum is correct.
+
+    inflate() will decompress and check either zlib-wrapped or gzip-wrapped
+  deflate data.  The header type is detected automatically.  Any information
+  contained in the gzip header is not retained, so applications that need that
+  information should instead use raw inflate, see inflateInit2() below, or
+  inflateBack() and perform their own processing of the gzip header and
+  trailer.
+
+    inflate() returns Z_OK if some progress has been made (more input processed
+  or more output produced), Z_STREAM_END if the end of the compressed data has
+  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+  corrupted (input stream not conforming to the zlib format or incorrect check
+  value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+  if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
+  Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+  output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
+  inflate() can be called again with more input and more output space to
+  continue decompressing. If Z_DATA_ERROR is returned, the application may then
+  call inflateSync() to look for a good compression block if a partial recovery
+  of the data is desired.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+   was inconsistent. In the error case, msg may be set but then points to a
+   static string (which must not be deallocated).
+*/
+
+                        /* Advanced functions */
+
+/*
+    The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+                                     int  level,
+                                     int  method,
+                                     int  windowBits,
+                                     int  memLevel,
+                                     int  strategy));
+
+     This is another version of deflateInit with more compression options. The
+   fields next_in, zalloc, zfree and opaque must be initialized before by
+   the caller.
+
+     The method parameter is the compression method. It must be Z_DEFLATED in
+   this version of the library.
+
+     The windowBits parameter is the base two logarithm of the window size
+   (the size of the history buffer). It should be in the range 8..15 for this
+   version of the library. Larger values of this parameter result in better
+   compression at the expense of memory usage. The default value is 15 if
+   deflateInit is used instead.
+
+     windowBits can also be -8..-15 for raw deflate. In this case, -windowBits
+   determines the window size. deflate() will then generate raw deflate data
+   with no zlib header or trailer, and will not compute an adler32 check value.
+
+     windowBits can also be greater than 15 for optional gzip encoding. Add
+   16 to windowBits to write a simple gzip header and trailer around the
+   compressed data instead of a zlib wrapper. The gzip header will have no
+   file name, no extra data, no comment, no modification time (set to zero),
+   no header crc, and the operating system will be set to 255 (unknown).  If a
+   gzip stream is being written, strm->adler is a crc32 instead of an adler32.
+
+     The memLevel parameter specifies how much memory should be allocated
+   for the internal compression state. memLevel=1 uses minimum memory but
+   is slow and reduces compression ratio; memLevel=9 uses maximum memory
+   for optimal speed. The default value is 8. See zconf.h for total memory
+   usage as a function of windowBits and memLevel.
+
+     The strategy parameter is used to tune the compression algorithm. Use the
+   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+   filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
+   string match), or Z_RLE to limit match distances to one (run-length
+   encoding). Filtered data consists mostly of small values with a somewhat
+   random distribution. In this case, the compression algorithm is tuned to
+   compress them better. The effect of Z_FILTERED is to force more Huffman
+   coding and less string matching; it is somewhat intermediate between
+   Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as
+   Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy
+   parameter only affects the compression ratio but not the correctness of the
+   compressed output even if it is not set appropriately.  Z_FIXED prevents the
+   use of dynamic Huffman codes, allowing for a simpler decoder for special
+   applications.
+
+      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
+   method). msg is set to null if there is no error message.  deflateInit2 does
+   not perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the compression dictionary from the given byte sequence
+   without producing any compressed output. This function must be called
+   immediately after deflateInit, deflateInit2 or deflateReset, before any
+   call of deflate. The compressor and decompressor must use exactly the same
+   dictionary (see inflateSetDictionary).
+
+     The dictionary should consist of strings (byte sequences) that are likely
+   to be encountered later in the data to be compressed, with the most commonly
+   used strings preferably put towards the end of the dictionary. Using a
+   dictionary is most useful when the data to be compressed is short and can be
+   predicted with good accuracy; the data can then be compressed better than
+   with the default empty dictionary.
+
+     Depending on the size of the compression data structures selected by
+   deflateInit or deflateInit2, a part of the dictionary may in effect be
+   discarded, for example if the dictionary is larger than the window size in
+   deflate or deflate2. Thus the strings most likely to be useful should be
+   put at the end of the dictionary, not at the front. In addition, the
+   current implementation of deflate will use at most the window size minus
+   262 bytes of the provided dictionary.
+
+     Upon return of this function, strm->adler is set to the adler32 value
+   of the dictionary; the decompressor may later use this value to determine
+   which dictionary has been used by the compressor. (The adler32 value
+   applies to the whole dictionary even if only a subset of the dictionary is
+   actually used by the compressor.) If a raw deflate was requested, then the
+   adler32 value is not computed and strm->adler is not set.
+
+     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent (for example if deflate has already been called for this stream
+   or if the compression method is bsort). deflateSetDictionary does not
+   perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+                                    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when several compression strategies will be
+   tried, for example when there are several ways of pre-processing the input
+   data with a filter. The streams that will be discarded should then be freed
+   by calling deflateEnd.  Note that deflateCopy duplicates the internal
+   compression state which can be quite large, so this strategy is slow and
+   can consume lots of memory.
+
+     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being NULL). msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to deflateEnd followed by deflateInit,
+   but does not free and reallocate all the internal compression state.
+   The stream will keep the same compression level and any other attributes
+   that may have been set by deflateInit2.
+
+      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+                                      int level,
+                                      int strategy));
+/*
+     Dynamically update the compression level and compression strategy.  The
+   interpretation of level and strategy is as in deflateInit2.  This can be
+   used to switch between compression and straight copy of the input data, or
+   to switch to a different kind of input data requiring a different
+   strategy. If the compression level is changed, the input available so far
+   is compressed with the old level (and may be flushed); the new level will
+   take effect only at the next call of deflate().
+
+     Before the call of deflateParams, the stream state must be set as for
+   a call of deflate(), since the currently available input may have to
+   be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+   if strm->avail_out was zero.
+*/
+
+ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
+                                    int good_length,
+                                    int max_lazy,
+                                    int nice_length,
+                                    int max_chain));
+/*
+     Fine tune deflate's internal compression parameters.  This should only be
+   used by someone who understands the algorithm used by zlib's deflate for
+   searching for the best matching string, and even then only by the most
+   fanatic optimizer trying to squeeze out the last compressed bit for their
+   specific input data.  Read the deflate.c source code for the meaning of the
+   max_lazy, good_length, nice_length, and max_chain parameters.
+
+     deflateTune() can be called after deflateInit() or deflateInit2(), and
+   returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
+ */
+
+ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
+                                       uLong sourceLen));
+/*
+     deflateBound() returns an upper bound on the compressed size after
+   deflation of sourceLen bytes.  It must be called after deflateInit()
+   or deflateInit2().  This would be used to allocate an output buffer
+   for deflation in a single pass, and so would be called before deflate().
+*/
+
+ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
+                                     int bits,
+                                     int value));
+/*
+     deflatePrime() inserts bits in the deflate output stream.  The intent
+  is that this function is used to start off the deflate output with the
+  bits leftover from a previous deflate stream when appending to it.  As such,
+  this function can only be used for raw deflate, and must be used before the
+  first deflate() call after a deflateInit2() or deflateReset().  bits must be
+  less than or equal to 16, and that many of the least significant bits of
+  value will be inserted in the output.
+
+      deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
+                                         gz_headerp head));
+/*
+      deflateSetHeader() provides gzip header information for when a gzip
+   stream is requested by deflateInit2().  deflateSetHeader() may be called
+   after deflateInit2() or deflateReset() and before the first call of
+   deflate().  The text, time, os, extra field, name, and comment information
+   in the provided gz_header structure are written to the gzip header (xflag is
+   ignored -- the extra flags are set according to the compression level).  The
+   caller must assure that, if not Z_NULL, name and comment are terminated with
+   a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
+   available there.  If hcrc is true, a gzip header crc is included.  Note that
+   the current versions of the command-line version of gzip (up through version
+   1.3.x) do not support header crc's, and will report that it is a "multi-part
+   gzip file" and give up.
+
+      If deflateSetHeader is not used, the default gzip header has text false,
+   the time set to zero, and os set to 255, with no extra, name, or comment
+   fields.  The gzip header is returned to the default state by deflateReset().
+
+      deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+                                     int  windowBits));
+
+     This is another version of inflateInit with an extra parameter. The
+   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+   before by the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library. The default value is 15 if inflateInit is used
+   instead. windowBits must be greater than or equal to the windowBits value
+   provided to deflateInit2() while compressing, or it must be equal to 15 if
+   deflateInit2() was not used. If a compressed stream with a larger window
+   size is given as input, inflate() will return with the error code
+   Z_DATA_ERROR instead of trying to allocate a larger window.
+
+     windowBits can also be -8..-15 for raw inflate. In this case, -windowBits
+   determines the window size. inflate() will then process raw deflate data,
+   not looking for a zlib or gzip header, not generating a check value, and not
+   looking for any check values for comparison at the end of the stream. This
+   is for use with other formats that use the deflate compressed data format
+   such as zip.  Those formats provide their own check values. If a custom
+   format is developed using the raw deflate format for compressed data, it is
+   recommended that a check value such as an adler32 or a crc32 be applied to
+   the uncompressed data as is done in the zlib, gzip, and zip formats.  For
+   most applications, the zlib format should be used as is. Note that comments
+   above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+     windowBits can also be greater than 15 for optional gzip decoding. Add
+   32 to windowBits to enable zlib and gzip decoding with automatic header
+   detection, or add 16 to decode only the gzip format (the zlib format will
+   return a Z_DATA_ERROR).  If a gzip stream is being decoded, strm->adler is
+   a crc32 instead of an adler32.
+
+     inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg
+   is set to null if there is no error message.  inflateInit2 does not perform
+   any decompression apart from reading the zlib header if present: this will
+   be done by inflate(). (So next_in and avail_in may be modified, but next_out
+   and avail_out are unchanged.)
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the decompression dictionary from the given uncompressed byte
+   sequence. This function must be called immediately after a call of inflate,
+   if that call returned Z_NEED_DICT. The dictionary chosen by the compressor
+   can be determined from the adler32 value returned by that call of inflate.
+   The compressor and decompressor must use exactly the same dictionary (see
+   deflateSetDictionary).  For raw inflate, this function can be called
+   immediately after inflateInit2() or inflateReset() and before any call of
+   inflate() to set the dictionary.  The application must insure that the
+   dictionary that was used for compression is provided.
+
+     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+   expected one (incorrect adler32 value). inflateSetDictionary does not
+   perform any decompression: this will be done by subsequent calls of
+   inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+    Skips invalid compressed data until a full flush point (see above the
+  description of deflate with Z_FULL_FLUSH) can be found, or until all
+  available input is skipped. No output is provided.
+
+    inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+  if no more input was provided, Z_DATA_ERROR if no flush point has been found,
+  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+  case, the application may save the current current value of total_in which
+  indicates where valid compressed data was found. In the error case, the
+  application may repeatedly call inflateSync, providing more input each time,
+  until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
+                                    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when randomly accessing a large stream.  The
+   first pass through the stream can periodically record the inflate state,
+   allowing restarting inflate at those points when randomly accessing the
+   stream.
+
+     inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being NULL). msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate all the internal decompression state.
+   The stream will keep attributes that may have been set by inflateInit2.
+
+      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
+                                     int bits,
+                                     int value));
+/*
+     This function inserts bits in the inflate input stream.  The intent is
+  that this function is used to start inflating at a bit position in the
+  middle of a byte.  The provided bits will be used before any bytes are used
+  from next_in.  This function should only be used with raw inflate, and
+  should be used before the first inflate() call after inflateInit2() or
+  inflateReset().  bits must be less than or equal to 16, and that many of the
+  least significant bits of value will be inserted in the input.
+
+      inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
+                                         gz_headerp head));
+/*
+      inflateGetHeader() requests that gzip header information be stored in the
+   provided gz_header structure.  inflateGetHeader() may be called after
+   inflateInit2() or inflateReset(), and before the first call of inflate().
+   As inflate() processes the gzip stream, head->done is zero until the header
+   is completed, at which time head->done is set to one.  If a zlib stream is
+   being decoded, then head->done is set to -1 to indicate that there will be
+   no gzip header information forthcoming.  Note that Z_BLOCK can be used to
+   force inflate() to return immediately after header processing is complete
+   and before any actual data is decompressed.
+
+      The text, time, xflags, and os fields are filled in with the gzip header
+   contents.  hcrc is set to true if there is a header CRC.  (The header CRC
+   was valid if done is set to one.)  If extra is not Z_NULL, then extra_max
+   contains the maximum number of bytes to write to extra.  Once done is true,
+   extra_len contains the actual extra field length, and extra contains the
+   extra field, or that field truncated if extra_max is less than extra_len.
+   If name is not Z_NULL, then up to name_max characters are written there,
+   terminated with a zero unless the length is greater than name_max.  If
+   comment is not Z_NULL, then up to comm_max characters are written there,
+   terminated with a zero unless the length is greater than comm_max.  When
+   any of extra, name, or comment are not Z_NULL and the respective field is
+   not present in the header, then that field is set to Z_NULL to signal its
+   absence.  This allows the use of deflateSetHeader() with the returned
+   structure to duplicate the header.  However if those fields are set to
+   allocated memory, then the application will need to save those pointers
+   elsewhere so that they can be eventually freed.
+
+      If inflateGetHeader is not used, then the header information is simply
+   discarded.  The header is always checked for validity, including the header
+   CRC if present.  inflateReset() will reset the process to discard the header
+   information.  The application would need to call inflateGetHeader() again to
+   retrieve the header from the next gzip stream.
+
+      inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
+                                        unsigned char FAR *window));
+
+     Initialize the internal stream state for decompression using inflateBack()
+   calls.  The fields zalloc, zfree and opaque in strm must be initialized
+   before the call.  If zalloc and zfree are Z_NULL, then the default library-
+   derived memory allocation routines are used.  windowBits is the base two
+   logarithm of the window size, in the range 8..15.  window is a caller
+   supplied buffer of that size.  Except for special applications where it is
+   assured that deflate was used with small window sizes, windowBits must be 15
+   and a 32K byte window must be supplied to be able to decompress general
+   deflate streams.
+
+     See inflateBack() for the usage of these routines.
+
+     inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+   the paramaters are invalid, Z_MEM_ERROR if the internal state could not
+   be allocated, or Z_VERSION_ERROR if the version of the library does not
+   match the version of the header file.
+*/
+
+typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *));
+typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
+
+ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
+                                    in_func in, void FAR *in_desc,
+                                    out_func out, void FAR *out_desc));
+/*
+     inflateBack() does a raw inflate with a single call using a call-back
+   interface for input and output.  This is more efficient than inflate() for
+   file i/o applications in that it avoids copying between the output and the
+   sliding window by simply making the window itself the output buffer.  This
+   function trusts the application to not change the output buffer passed by
+   the output function, at least until inflateBack() returns.
+
+     inflateBackInit() must be called first to allocate the internal state
+   and to initialize the state with the user-provided window buffer.
+   inflateBack() may then be used multiple times to inflate a complete, raw
+   deflate stream with each call.  inflateBackEnd() is then called to free
+   the allocated state.
+
+     A raw deflate stream is one with no zlib or gzip header or trailer.
+   This routine would normally be used in a utility that reads zip or gzip
+   files and writes out uncompressed files.  The utility would decode the
+   header and process the trailer on its own, hence this routine expects
+   only the raw deflate stream to decompress.  This is different from the
+   normal behavior of inflate(), which expects either a zlib or gzip header and
+   trailer around the deflate stream.
+
+     inflateBack() uses two subroutines supplied by the caller that are then
+   called by inflateBack() for input and output.  inflateBack() calls those
+   routines until it reads a complete deflate stream and writes out all of the
+   uncompressed data, or until it encounters an error.  The function's
+   parameters and return types are defined above in the in_func and out_func
+   typedefs.  inflateBack() will call in(in_desc, &buf) which should return the
+   number of bytes of provided input, and a pointer to that input in buf.  If
+   there is no input available, in() must return zero--buf is ignored in that
+   case--and inflateBack() will return a buffer error.  inflateBack() will call
+   out(out_desc, buf, len) to write the uncompressed data buf[0..len-1].  out()
+   should return zero on success, or non-zero on failure.  If out() returns
+   non-zero, inflateBack() will return with an error.  Neither in() nor out()
+   are permitted to change the contents of the window provided to
+   inflateBackInit(), which is also the buffer that out() uses to write from.
+   The length written by out() will be at most the window size.  Any non-zero
+   amount of input may be provided by in().
+
+     For convenience, inflateBack() can be provided input on the first call by
+   setting strm->next_in and strm->avail_in.  If that input is exhausted, then
+   in() will be called.  Therefore strm->next_in must be initialized before
+   calling inflateBack().  If strm->next_in is Z_NULL, then in() will be called
+   immediately for input.  If strm->next_in is not Z_NULL, then strm->avail_in
+   must also be initialized, and then if strm->avail_in is not zero, input will
+   initially be taken from strm->next_in[0 .. strm->avail_in - 1].
+
+     The in_desc and out_desc parameters of inflateBack() is passed as the
+   first parameter of in() and out() respectively when they are called.  These
+   descriptors can be optionally used to pass any information that the caller-
+   supplied in() and out() functions need to do their job.
+
+     On return, inflateBack() will set strm->next_in and strm->avail_in to
+   pass back any unused input that was provided by the last in() call.  The
+   return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
+   if in() or out() returned an error, Z_DATA_ERROR if there was a format
+   error in the deflate stream (in which case strm->msg is set to indicate the
+   nature of the error), or Z_STREAM_ERROR if the stream was not properly
+   initialized.  In the case of Z_BUF_ERROR, an input or output error can be
+   distinguished using strm->next_in which will be Z_NULL only if in() returned
+   an error.  If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to
+   out() returning non-zero.  (in() will always be called before out(), so
+   strm->next_in is assured to be defined if out() returns non-zero.)  Note
+   that inflateBack() cannot return Z_OK.
+*/
+
+ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
+/*
+     All memory allocated by inflateBackInit() is freed.
+
+     inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+   state was inconsistent.
+*/
+
+ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
+/* Return flags indicating compile-time options.
+
+    Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+     1.0: size of uInt
+     3.2: size of uLong
+     5.4: size of voidpf (pointer)
+     7.6: size of z_off_t
+
+    Compiler, assembler, and debug options:
+     8: DEBUG
+     9: ASMV or ASMINF -- use ASM code
+     10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+     11: 0 (reserved)
+
+    One-time table building (smaller code, but not thread-safe if true):
+     12: BUILDFIXED -- build static block decoding tables when needed
+     13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+     14,15: 0 (reserved)
+
+    Library content (indicates missing functionality):
+     16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+                          deflate code when not needed)
+     17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+                    and decode gzip streams (to avoid linking crc code)
+     18-19: 0 (reserved)
+
+    Operation variations (changes in library functionality):
+     20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+     21: FASTEST -- deflate algorithm with only one, lowest compression level
+     22,23: 0 (reserved)
+
+    The sprintf variant used by gzprintf (zero is best):
+     24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+     25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+     26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+    Remainder:
+     27-31: 0 (reserved)
+ */
+
+
+                        /* utility functions */
+
+/*
+     The following utility functions are implemented on top of the
+   basic stream-oriented functions. To simplify the interface, some
+   default options are assumed (compression level and memory usage,
+   standard memory allocation functions). The source code of these
+   utility functions can easily be modified if you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest,   uLongf *destLen,
+                                 const Bytef *source, uLong sourceLen));
+/*
+     Compresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be at least the value returned
+   by compressBound(sourceLen). Upon exit, destLen is the actual size of the
+   compressed buffer.
+     This function can be used to compress a whole file at once if the
+   input file is mmap'ed.
+     compress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest,   uLongf *destLen,
+                                  const Bytef *source, uLong sourceLen,
+                                  int level));
+/*
+     Compresses the source buffer into the destination buffer. The level
+   parameter has the same meaning as in deflateInit.  sourceLen is the byte
+   length of the source buffer. Upon entry, destLen is the total size of the
+   destination buffer, which must be at least the value returned by
+   compressBound(sourceLen). Upon exit, destLen is the actual size of the
+   compressed buffer.
+
+     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+   Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
+/*
+     compressBound() returns an upper bound on the compressed size after
+   compress() or compress2() on sourceLen bytes.  It would be used before
+   a compress() or compress2() call to allocate the destination buffer.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest,   uLongf *destLen,
+                                   const Bytef *source, uLong sourceLen));
+/*
+     Decompresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be large enough to hold the
+   entire uncompressed data. (The size of the uncompressed data must have
+   been saved previously by the compressor and transmitted to the decompressor
+   by some mechanism outside the scope of this compression library.)
+   Upon exit, destLen is the actual size of the compressed buffer.
+     This function can be used to decompress a whole file at once if the
+   input file is mmap'ed.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.
+*/
+
+
+typedef voidp gzFile;
+
+ZEXTERN gzFile ZEXPORT gzopen  OF((const char *path, const char *mode));
+/*
+     Opens a gzip (.gz) file for reading or writing. The mode parameter
+   is as in fopen ("rb" or "wb") but can also include a compression level
+   ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for
+   Huffman only compression as in "wb1h", or 'R' for run-length encoding
+   as in "wb1R". (See the description of deflateInit2 for more information
+   about the strategy parameter.)
+
+     gzopen can be used to read a file which is not in gzip format; in this
+   case gzread will directly read from the file without decompression.
+
+     gzopen returns NULL if the file could not be opened or if there was
+   insufficient memory to allocate the (de)compression state; errno
+   can be checked to distinguish the two cases (if errno is zero, the
+   zlib error is Z_MEM_ERROR).  */
+
+ZEXTERN gzFile ZEXPORT gzdopen  OF((int fd, const char *mode));
+/*
+     gzdopen() associates a gzFile with the file descriptor fd.  File
+   descriptors are obtained from calls like open, dup, creat, pipe or
+   fileno (in the file has been previously opened with fopen).
+   The mode parameter is as in gzopen.
+     The next call of gzclose on the returned gzFile will also close the
+   file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+   descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
+     gzdopen returns NULL if there was insufficient memory to allocate
+   the (de)compression state.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+     Dynamically update the compression level or strategy. See the description
+   of deflateInit2 for the meaning of these parameters.
+     gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+   opened for writing.
+*/
+
+ZEXTERN int ZEXPORT    gzread  OF((gzFile file, voidp buf, unsigned len));
+/*
+     Reads the given number of uncompressed bytes from the compressed file.
+   If the input file was not in gzip format, gzread copies the given number
+   of bytes into the buffer.
+     gzread returns the number of uncompressed bytes actually read (0 for
+   end of file, -1 for error). */
+
+ZEXTERN int ZEXPORT    gzwrite OF((gzFile file,
+                                   voidpc buf, unsigned len));
+/*
+     Writes the given number of uncompressed bytes into the compressed file.
+   gzwrite returns the number of uncompressed bytes actually written
+   (0 in case of error).
+*/
+
+ZEXTERN int ZEXPORTVA   gzprintf OF((gzFile file, const char *format, ...));
+/*
+     Converts, formats, and writes the args to the compressed file under
+   control of the format string, as in fprintf. gzprintf returns the number of
+   uncompressed bytes actually written (0 in case of error).  The number of
+   uncompressed bytes written is limited to 4095. The caller should assure that
+   this limit is not exceeded. If it is exceeded, then gzprintf() will return
+   return an error (0) with nothing written. In this case, there may also be a
+   buffer overflow with unpredictable consequences, which is possible only if
+   zlib was compiled with the insecure functions sprintf() or vsprintf()
+   because the secure snprintf() or vsnprintf() functions were not available.
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+      Writes the given null-terminated string to the compressed file, excluding
+   the terminating null character.
+      gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+      Reads bytes from the compressed file until len-1 characters are read, or
+   a newline character is read and transferred to buf, or an end-of-file
+   condition is encountered.  The string is then terminated with a null
+   character.
+      gzgets returns buf, or Z_NULL in case of error.
+*/
+
+ZEXTERN int ZEXPORT    gzputc OF((gzFile file, int c));
+/*
+      Writes c, converted to an unsigned char, into the compressed file.
+   gzputc returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT    gzgetc OF((gzFile file));
+/*
+      Reads one byte from the compressed file. gzgetc returns this byte
+   or -1 in case of end of file or error.
+*/
+
+ZEXTERN int ZEXPORT    gzungetc OF((int c, gzFile file));
+/*
+      Push one character back onto the stream to be read again later.
+   Only one character of push-back is allowed.  gzungetc() returns the
+   character pushed, or -1 on failure.  gzungetc() will fail if a
+   character has been pushed but not read yet, or if c is -1. The pushed
+   character will be discarded if the stream is repositioned with gzseek()
+   or gzrewind().
+*/
+
+ZEXTERN int ZEXPORT    gzflush OF((gzFile file, int flush));
+/*
+     Flushes all pending output into the compressed file. The parameter
+   flush is as in the deflate() function. The return value is the zlib
+   error number (see function gzerror below). gzflush returns Z_OK if
+   the flush parameter is Z_FINISH and all output could be flushed.
+     gzflush should be called only when strictly necessary because it can
+   degrade compression.
+*/
+
+ZEXTERN z_off_t ZEXPORT    gzseek OF((gzFile file,
+                                      z_off_t offset, int whence));
+/*
+      Sets the starting position for the next gzread or gzwrite on the
+   given compressed file. The offset represents a number of bytes in the
+   uncompressed data stream. The whence parameter is defined as in lseek(2);
+   the value SEEK_END is not supported.
+     If the file is opened for reading, this function is emulated but can be
+   extremely slow. If the file is opened for writing, only forward seeks are
+   supported; gzseek then compresses a sequence of zeroes up to the new
+   starting position.
+
+      gzseek returns the resulting offset location as measured in bytes from
+   the beginning of the uncompressed stream, or -1 in case of error, in
+   particular if the file is opened for writing and the new starting position
+   would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT    gzrewind OF((gzFile file));
+/*
+     Rewinds the given file. This function is supported only for reading.
+
+   gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+ZEXTERN z_off_t ZEXPORT    gztell OF((gzFile file));
+/*
+     Returns the starting position for the next gzread or gzwrite on the
+   given compressed file. This position represents a number of bytes in the
+   uncompressed data stream.
+
+   gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+     Returns 1 when EOF has previously been detected reading the given
+   input stream, otherwise zero.
+*/
+
+ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
+/*
+     Returns 1 if file is being read directly without decompression, otherwise
+   zero.
+*/
+
+ZEXTERN int ZEXPORT    gzclose OF((gzFile file));
+/*
+     Flushes all pending output if necessary, closes the compressed file
+   and deallocates all the (de)compression state. The return value is the zlib
+   error number (see function gzerror below).
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+     Returns the error message for the last error which occurred on the
+   given compressed file. errnum is set to zlib error number. If an
+   error occurred in the file system and not in the compression library,
+   errnum is set to Z_ERRNO and the application may consult errno
+   to get the exact error code.
+*/
+
+ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
+/*
+     Clears the error and end-of-file flags for file. This is analogous to the
+   clearerr() function in stdio. This is useful for continuing to read a gzip
+   file that is being written concurrently.
+*/
+
+                        /* checksum functions */
+
+/*
+     These functions are not related to compression but are exported
+   anyway because they might be useful in applications using the
+   compression library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+/*
+     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum. If buf is NULL, this function returns
+   the required initial value for the checksum.
+   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+   much faster. Usage example:
+
+     uLong adler = adler32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       adler = adler32(adler, buffer, length);
+     }
+     if (adler != original_adler) error();
+*/
+
+ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
+                                          z_off_t len2));
+/*
+     Combine two Adler-32 checksums into one.  For two sequences of bytes, seq1
+   and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
+   each, adler1 and adler2.  adler32_combine() returns the Adler-32 checksum of
+   seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.
+*/
+
+ZEXTERN uLong ZEXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));
+/*
+     Update a running CRC-32 with the bytes buf[0..len-1] and return the
+   updated CRC-32. If buf is NULL, this function returns the required initial
+   value for the for the crc. Pre- and post-conditioning (one's complement) is
+   performed within this function so it shouldn't be done by the application.
+   Usage example:
+
+     uLong crc = crc32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       crc = crc32(crc, buffer, length);
+     }
+     if (crc != original_crc) error();
+*/
+
+ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
+
+/*
+     Combine two CRC-32 check values into one.  For two sequences of bytes,
+   seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
+   calculated for each, crc1 and crc2.  crc32_combine() returns the CRC-32
+   check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
+   len2.
+*/
+
+
+                        /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
+                                      int windowBits, int memLevel,
+                                      int strategy, const char *version,
+                                      int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
+                                      const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
+                                         unsigned char FAR *window,
+                                         const char *version,
+                                         int stream_size));
+#define deflateInit(strm, level) \
+        deflateInit_((strm), (level),       ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+        inflateInit_((strm),                ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+                      (strategy),           ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+        inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+#define inflateBackInit(strm, windowBits, window) \
+        inflateBackInit_((strm), (windowBits), (window), \
+        ZLIB_VERSION, sizeof(z_stream))
+
+
+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
+    struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+ZEXTERN const char   * ZEXPORT zError           OF((int));
+ZEXTERN int            ZEXPORT inflateSyncPoint OF((z_streamp z));
+ZEXTERN const uLongf * ZEXPORT get_crc_table    OF((void));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZLIB_H */
diff --git a/src/unison/physfs-1.1.1/zlib123/zutil.c b/src/unison/physfs-1.1.1/zlib123/zutil.c
new file mode 100644 (file)
index 0000000..d55f594
--- /dev/null
@@ -0,0 +1,318 @@
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zutil.h"
+
+#ifndef NO_DUMMY_DECL
+struct internal_state      {int dummy;}; /* for buggy compilers */
+#endif
+
+const char * const z_errmsg[10] = {
+"need dictionary",     /* Z_NEED_DICT       2  */
+"stream end",          /* Z_STREAM_END      1  */
+"",                    /* Z_OK              0  */
+"file error",          /* Z_ERRNO         (-1) */
+"stream error",        /* Z_STREAM_ERROR  (-2) */
+"data error",          /* Z_DATA_ERROR    (-3) */
+"insufficient memory", /* Z_MEM_ERROR     (-4) */
+"buffer error",        /* Z_BUF_ERROR     (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+const char * ZEXPORT zlibVersion()
+{
+    return ZLIB_VERSION;
+}
+
+uLong ZEXPORT zlibCompileFlags()
+{
+    uLong flags;
+
+    flags = 0;
+    switch (sizeof(uInt)) {
+    case 2:     break;
+    case 4:     flags += 1;     break;
+    case 8:     flags += 2;     break;
+    default:    flags += 3;
+    }
+    switch (sizeof(uLong)) {
+    case 2:     break;
+    case 4:     flags += 1 << 2;        break;
+    case 8:     flags += 2 << 2;        break;
+    default:    flags += 3 << 2;
+    }
+    switch (sizeof(voidpf)) {
+    case 2:     break;
+    case 4:     flags += 1 << 4;        break;
+    case 8:     flags += 2 << 4;        break;
+    default:    flags += 3 << 4;
+    }
+    switch (sizeof(z_off_t)) {
+    case 2:     break;
+    case 4:     flags += 1 << 6;        break;
+    case 8:     flags += 2 << 6;        break;
+    default:    flags += 3 << 6;
+    }
+#ifdef DEBUG
+    flags += 1 << 8;
+#endif
+#if defined(ASMV) || defined(ASMINF)
+    flags += 1 << 9;
+#endif
+#ifdef ZLIB_WINAPI
+    flags += 1 << 10;
+#endif
+#ifdef BUILDFIXED
+    flags += 1 << 12;
+#endif
+#ifdef DYNAMIC_CRC_TABLE
+    flags += 1 << 13;
+#endif
+#ifdef NO_GZCOMPRESS
+    flags += 1L << 16;
+#endif
+#ifdef NO_GZIP
+    flags += 1L << 17;
+#endif
+#ifdef PKZIP_BUG_WORKAROUND
+    flags += 1L << 20;
+#endif
+#ifdef FASTEST
+    flags += 1L << 21;
+#endif
+#ifdef STDC
+#  ifdef NO_vsnprintf
+        flags += 1L << 25;
+#    ifdef HAS_vsprintf_void
+        flags += 1L << 26;
+#    endif
+#  else
+#    ifdef HAS_vsnprintf_void
+        flags += 1L << 26;
+#    endif
+#  endif
+#else
+        flags += 1L << 24;
+#  ifdef NO_snprintf
+        flags += 1L << 25;
+#    ifdef HAS_sprintf_void
+        flags += 1L << 26;
+#    endif
+#  else
+#    ifdef HAS_snprintf_void
+        flags += 1L << 26;
+#    endif
+#  endif
+#endif
+    return flags;
+}
+
+#ifdef DEBUG
+
+#  ifndef verbose
+#    define verbose 0
+#  endif
+int z_verbose = verbose;
+
+void z_error (m)
+    char *m;
+{
+    fprintf(stderr, "%s\n", m);
+    exit(1);
+}
+#endif
+
+/* exported to allow conversion of error code to string for compress() and
+ * uncompress()
+ */
+const char * ZEXPORT zError(err)
+    int err;
+{
+    return ERR_MSG(err);
+}
+
+#if defined(_WIN32_WCE)
+    /* The Microsoft C Run-Time Library for Windows CE doesn't have
+     * errno.  We define it as a global variable to simplify porting.
+     * Its value is always 0 and should not be used.
+     */
+    int errno = 0;
+#endif
+
+#ifndef HAVE_MEMCPY
+
+void zmemcpy(dest, source, len)
+    Bytef* dest;
+    const Bytef* source;
+    uInt  len;
+{
+    if (len == 0) return;
+    do {
+        *dest++ = *source++; /* ??? to be unrolled */
+    } while (--len != 0);
+}
+
+int zmemcmp(s1, s2, len)
+    const Bytef* s1;
+    const Bytef* s2;
+    uInt  len;
+{
+    uInt j;
+
+    for (j = 0; j < len; j++) {
+        if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+    }
+    return 0;
+}
+
+void zmemzero(dest, len)
+    Bytef* dest;
+    uInt  len;
+{
+    if (len == 0) return;
+    do {
+        *dest++ = 0;  /* ??? to be unrolled */
+    } while (--len != 0);
+}
+#endif
+
+
+#ifdef SYS16BIT
+
+#ifdef __TURBOC__
+/* Turbo C in 16-bit mode */
+
+#  define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+    voidpf org_ptr;
+    voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+    voidpf buf = opaque; /* just to make some compilers happy */
+    ulg bsize = (ulg)items*size;
+
+    /* If we allocate less than 65520 bytes, we assume that farmalloc
+     * will return a usable pointer which doesn't have to be normalized.
+     */
+    if (bsize < 65520L) {
+        buf = farmalloc(bsize);
+        if (*(ush*)&buf != 0) return buf;
+    } else {
+        buf = farmalloc(bsize + 16L);
+    }
+    if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+    table[next_ptr].org_ptr = buf;
+
+    /* Normalize the pointer to seg:0 */
+    *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+    *(ush*)&buf = 0;
+    table[next_ptr++].new_ptr = buf;
+    return buf;
+}
+
+void  zcfree (voidpf opaque, voidpf ptr)
+{
+    int n;
+    if (*(ush*)&ptr != 0) { /* object < 64K */
+        farfree(ptr);
+        return;
+    }
+    /* Find the original pointer */
+    for (n = 0; n < next_ptr; n++) {
+        if (ptr != table[n].new_ptr) continue;
+
+        farfree(table[n].org_ptr);
+        while (++n < next_ptr) {
+            table[n-1] = table[n];
+        }
+        next_ptr--;
+        return;
+    }
+    ptr = opaque; /* just to make some compilers happy */
+    Assert(0, "zcfree: ptr not found");
+}
+
+#endif /* __TURBOC__ */
+
+
+#ifdef M_I86
+/* Microsoft C in 16-bit mode */
+
+#  define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
+#  define _halloc  halloc
+#  define _hfree   hfree
+#endif
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+    if (opaque) opaque = 0; /* to make compiler happy */
+    return _halloc((long)items, size);
+}
+
+void  zcfree (voidpf opaque, voidpf ptr)
+{
+    if (opaque) opaque = 0; /* to make compiler happy */
+    _hfree(ptr);
+}
+
+#endif /* M_I86 */
+
+#endif /* SYS16BIT */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp  malloc OF((uInt size));
+extern voidp  calloc OF((uInt items, uInt size));
+extern void   free   OF((voidpf ptr));
+#endif
+
+voidpf zcalloc (opaque, items, size)
+    voidpf opaque;
+    unsigned items;
+    unsigned size;
+{
+    if (opaque) items += size - size; /* make compiler happy */
+    return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
+                              (voidpf)calloc(items, size);
+}
+
+void  zcfree (opaque, ptr)
+    voidpf opaque;
+    voidpf ptr;
+{
+    free(ptr);
+    if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
diff --git a/src/unison/physfs-1.1.1/zlib123/zutil.h b/src/unison/physfs-1.1.1/zlib123/zutil.h
new file mode 100644 (file)
index 0000000..b7d5eff
--- /dev/null
@@ -0,0 +1,269 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZUTIL_H
+#define ZUTIL_H
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+#ifdef STDC
+#  ifndef _WIN32_WCE
+#    include <stddef.h>
+#  endif
+#  include <string.h>
+#  include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+#   ifdef _WIN32_WCE
+      /* The Microsoft C Run-Time Library for Windows CE doesn't have
+       * errno.  We define it as a global variable to simplify porting.
+       * Its value is always 0 and should not be used.  We rename it to
+       * avoid conflict with other libraries that use the same workaround.
+       */
+#     define errno z_errno
+#   endif
+    extern int errno;
+#else
+#  ifndef _WIN32_WCE
+#    include <errno.h>
+#  endif
+#endif
+
+#ifndef local
+#  define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char  uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long  ulg;
+
+extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+  return (strm->msg = (char*)ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+        /* common constants */
+
+#ifndef DEF_WBITS
+#  define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+#  define DEF_MEM_LEVEL 8
+#else
+#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES    2
+/* The three kinds of block type */
+
+#define MIN_MATCH  3
+#define MAX_MATCH  258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+        /* target dependencies */
+
+#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))
+#  define OS_CODE  0x00
+#  if defined(__TURBOC__) || defined(__BORLANDC__)
+#    if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
+       /* Allow compilation with ANSI keywords only enabled */
+       void _Cdecl farfree( void *block );
+       void *_Cdecl farmalloc( unsigned long nbytes );
+#    else
+#      include <alloc.h>
+#    endif
+#  else /* MSC or DJGPP */
+#    include <malloc.h>
+#  endif
+#endif
+
+#ifdef AMIGA
+#  define OS_CODE  0x01
+#endif
+
+#if defined(VAXC) || defined(VMS)
+#  define OS_CODE  0x02
+#  define F_OPEN(name, mode) \
+     fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#if defined(ATARI) || defined(atarist)
+#  define OS_CODE  0x05
+#endif
+
+#ifdef OS2
+#  define OS_CODE  0x06
+#  ifdef M_I86
+     #include <malloc.h>
+#  endif
+#endif
+
+#if defined(MACOS) || defined(TARGET_OS_MAC)
+#  define OS_CODE  0x07
+#  if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+#    include <unix.h> /* for fdopen */
+#  else
+#    ifndef fdopen
+#      define fdopen(fd,mode) NULL /* No fdopen() */
+#    endif
+#  endif
+#endif
+
+#ifdef TOPS20
+#  define OS_CODE  0x0a
+#endif
+
+#ifdef WIN32
+#  ifndef __CYGWIN__  /* Cygwin is Unix, not Win32 */
+#    define OS_CODE  0x0b
+#  endif
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+#  define OS_CODE  0x0f
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+#  define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+#if (defined(_MSC_VER) && (_MSC_VER > 600))
+#  if defined(_WIN32_WCE)
+#    define fdopen(fd,mode) NULL /* No fdopen() */
+#    ifndef _PTRDIFF_T_DEFINED
+       typedef int ptrdiff_t;
+#      define _PTRDIFF_T_DEFINED
+#    endif
+#  else
+#    define fdopen(fd,type)  _fdopen(fd,type)
+#  endif
+#endif
+
+        /* common defaults */
+
+#ifndef OS_CODE
+#  define OS_CODE  0x03  /* assume Unix */
+#endif
+
+#ifndef F_OPEN
+#  define F_OPEN(name, mode) fopen((name), (mode))
+#endif
+
+         /* functions */
+
+#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)
+#  ifndef HAVE_VSNPRINTF
+#    define HAVE_VSNPRINTF
+#  endif
+#endif
+#if defined(__CYGWIN__)
+#  ifndef HAVE_VSNPRINTF
+#    define HAVE_VSNPRINTF
+#  endif
+#endif
+#ifndef HAVE_VSNPRINTF
+#  ifdef MSDOS
+     /* vsnprintf may exist on some MS-DOS compilers (DJGPP?),
+        but for now we just assume it doesn't. */
+#    define NO_vsnprintf
+#  endif
+#  ifdef __TURBOC__
+#    define NO_vsnprintf
+#  endif
+#  ifdef WIN32
+     /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */
+#    if !defined(vsnprintf) && !defined(NO_vsnprintf)
+#      define vsnprintf _vsnprintf
+#    endif
+#  endif
+#  ifdef __SASC
+#    define NO_vsnprintf
+#  endif
+#endif
+#ifdef VMS
+#  define NO_vsnprintf
+#endif
+
+#if defined(pyr)
+#  define NO_MEMCPY
+#endif
+#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+  * You may have to use the same strategy for Borland C (untested).
+  * The __SC__ check is for Symantec.
+  */
+#  define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+#  define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+#    define zmemcpy _fmemcpy
+#    define zmemcmp _fmemcmp
+#    define zmemzero(dest, len) _fmemset(dest, 0, len)
+#  else
+#    define zmemcpy memcpy
+#    define zmemcmp memcmp
+#    define zmemzero(dest, len) memset(dest, 0, len)
+#  endif
+#else
+   extern void zmemcpy  OF((Bytef* dest, const Bytef* source, uInt len));
+   extern int  zmemcmp  OF((const Bytef* s1, const Bytef* s2, uInt len));
+   extern void zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG
+#  include <stdio.h>
+   extern int z_verbose;
+   extern void z_error    OF((char *m));
+#  define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+#  define Trace(x) {if (z_verbose>=0) fprintf x ;}
+#  define Tracev(x) {if (z_verbose>0) fprintf x ;}
+#  define Tracevv(x) {if (z_verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+
+voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
+void   zcfree  OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) \
+           (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+#endif /* ZUTIL_H */
diff --git a/src/unison/src/vfs/FileSystem.cpp b/src/unison/src/vfs/FileSystem.cpp
new file mode 100644 (file)
index 0000000..56151b8
--- /dev/null
@@ -0,0 +1,127 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#include <unison/vfs/FileSystem.hpp>
+
+#include <fstream>
+
+#include <physfs.h>
+
+namespace Unison
+{
+   namespace VFS
+   {
+      FileSystem::FileSystem()
+      {
+#if __USE_POSIX
+         std::ifstream cmdline("/proc/self/cmdline");
+         std::string argv0;
+         std::getline(cmdline, argv0, '\0');
+         PHYSFS_init(argv0.c_str());
+#else
+         PHYSFS_init(0);
+#endif
+      }
+
+      FileSystem::~FileSystem()
+      {
+         PHYSFS_deinit();
+      }
+
+      void FileSystem::follow_sym_links(bool follow)
+      {
+         PHYSFS_permitSymbolicLinks(follow);
+      }
+
+      std::string FileSystem::get_dir_sep()
+      {
+         return PHYSFS_getDirSeparator();
+      }
+
+      std::string FileSystem::get_base_dir()
+      {
+         return PHYSFS_getBaseDir();
+      }
+
+      std::string FileSystem::get_user_dir()
+      {
+         return PHYSFS_getUserDir();
+      }
+
+      std::string FileSystem::get_write_dir()
+      {
+         return PHYSFS_getWriteDir();
+      }
+
+      void FileSystem::set_write_dir(const std::string &write_dir)
+      {
+         PHYSFS_setWriteDir(write_dir.c_str());
+      }
+
+      void FileSystem::mount(const std::string &path, const std::string &mount_point, bool append)
+      {
+         PHYSFS_mount(path.c_str(), mount_point.c_str(), append);
+      }
+
+      void FileSystem::umount(const std::string &path)
+      {
+         PHYSFS_removeFromSearchPath(path.c_str());
+      }
+
+      std::vector<std::string> FileSystem::get_search_path()
+      {
+         std::vector<std::string> paths;
+         char **search_path = PHYSFS_getSearchPath();
+         for(char **iter = search_path;*iter;++iter)
+         {
+            paths.push_back(*iter);
+         }
+         PHYSFS_freeList(search_path);
+         return paths;
+      }
+
+      std::string FileSystem::get_mount_point(const std::string &path)
+      {
+         return PHYSFS_getMountPoint(path.c_str());
+      }
+
+      void FileSystem::mkdir(const std::string &dir)
+      {
+         PHYSFS_mkdir(dir.c_str());
+      }
+
+      void FileSystem::rm(const std::string &filename)
+      {
+         PHYSFS_delete(filename.c_str());
+      }
+
+      std::vector<std::string> FileSystem::ls(const std::string &path)
+      {
+         std::vector<std::string> files;
+         char **physfs_files = PHYSFS_enumerateFiles(path.c_str());
+         for(char **iter = physfs_files;*iter;++iter)
+         {
+            files.push_back(*iter);
+         }
+         PHYSFS_freeList(physfs_files);
+         return files;
+      }
+
+      bool FileSystem::exists(const std::string &filename)
+      {
+         return PHYSFS_exists(filename.c_str());
+      }
+
+      bool FileSystem::is_dir(const std::string &filename)
+      {
+         return PHYSFS_isDirectory(filename.c_str());
+      }
+
+      std::string FileSystem::get_real_dir(const std::string &filename)
+      {
+         return PHYSFS_getRealDir(filename.c_str());
+      }
+   }
+}
diff --git a/src/unison/src/vfs/sdl/Utils.cpp b/src/unison/src/vfs/sdl/Utils.cpp
new file mode 100644 (file)
index 0000000..0e911ef
--- /dev/null
@@ -0,0 +1,79 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#include <unison/vfs/sdl/Utils.hpp>
+
+#include <fstream>
+#include <assert.h>
+
+#include <physfs.h>
+#include "SDL.h"
+
+namespace
+{
+   int rwops_seek(SDL_RWops *context, int offset, int whence)
+   {
+      PHYSFS_File *file = reinterpret_cast<PHYSFS_File *>(context->hidden.unknown.data1);
+      int res = 0;
+      switch(whence) {
+          case SEEK_SET:
+              res = PHYSFS_seek(file, offset);
+              break;
+          case SEEK_CUR:
+              res = PHYSFS_seek(file, PHYSFS_tell(file) + offset);
+              break;
+          case SEEK_END:
+              res = PHYSFS_seek(file, PHYSFS_fileLength(file) + offset);
+              break;
+          default:
+              assert(0);
+              break;
+      }
+
+      return (int) PHYSFS_tell(file);
+   }
+
+   int rwops_read(SDL_RWops *context, void *ptr, int size, int maxnum)
+   {
+      PHYSFS_File *file = reinterpret_cast<PHYSFS_File *>(context->hidden.unknown.data1);
+
+      int res = PHYSFS_read(file, ptr, size, maxnum);
+      return res;
+   }
+
+   int rwops_close(SDL_RWops *context)
+   {
+      PHYSFS_File *file = reinterpret_cast<PHYSFS_File *>(context->hidden.unknown.data1);
+
+      PHYSFS_close(file);
+      delete context;
+
+      return 0;
+   }
+}
+
+
+namespace Unison
+{
+   namespace VFS
+   {
+      namespace SDL
+      {
+         SDL_RWops *Utils::open_physfs_in(const std::string &filename)
+         {
+            PHYSFS_File *file = PHYSFS_openRead(filename.c_str());
+            assert(file);
+            SDL_RWops* ops = new SDL_RWops;
+            ops->type = 0;
+            ops->hidden.unknown.data1 = file;
+            ops->seek = rwops_seek;
+            ops->read = rwops_read;
+            ops->write = 0; 
+            ops->close = rwops_close;
+            return ops;
+         }
+      }
+   }
+}
diff --git a/src/unison/src/vfs/stream.cpp b/src/unison/src/vfs/stream.cpp
new file mode 100644 (file)
index 0000000..d4ae430
--- /dev/null
@@ -0,0 +1,158 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#include <unison/vfs/stream.hpp>
+
+#include <streambuf>
+#include <assert.h>
+#include <physfs.h>
+
+// FIXME: make streambufs more complete
+namespace
+{
+   class iphysfsfilebuf : public std::streambuf
+   {
+      public:
+         iphysfsfilebuf(const std::string &filename)
+         {
+            file = PHYSFS_openRead(filename.c_str());
+            assert(file);
+         }
+
+         ~iphysfsfilebuf()
+         {
+            PHYSFS_close(file);
+         }
+      protected:
+         int underflow()
+         {
+            if(PHYSFS_eof(file))
+            {
+               return traits_type::eof();
+            }
+            PHYSFS_sint64 bytes = PHYSFS_read(file, buffer, 1, sizeof(buffer));
+            if(bytes <= 0)
+            {
+               return traits_type::eof();
+            }
+            setg(buffer, buffer, buffer + bytes);
+            return buffer[0];
+         }
+
+         pos_type seekoff(off_type off, std::ios_base::seekdir way, std::ios_base::openmode which)
+         {
+            off_type nsp = off;
+            PHYSFS_sint64 pos = PHYSFS_tell(file);
+            switch(way)
+            {
+               case std::ios_base::beg:
+                  break;
+               case std::ios_base::cur:
+                  if(off == 0)
+                  {
+                     return pos - (egptr() - gptr());
+                  }
+                  nsp += pos - (egptr() - gptr());
+                  break;
+               case std::ios_base::end:
+                  nsp += PHYSFS_fileLength(file);
+                  break;
+               default:
+                  assert(0);
+                  break;
+            }
+            return seekpos(nsp, which);
+         }
+
+         pos_type seekpos(pos_type sp, std::ios_base::openmode /*which*/)
+         {
+            if(PHYSFS_seek(file, sp) == 0)
+            {
+               return -1;
+            }
+            setg(buffer, buffer, buffer);
+            return sp;
+         }
+      private:
+         PHYSFS_File *file;
+         char buffer[1024];
+   };
+
+   class ophysfsfilebuf : public std::streambuf
+   {
+      public:
+         ophysfsfilebuf(const std::string &filename)
+         {
+            file = PHYSFS_openWrite(filename.c_str());
+            assert(file);
+            setp(buffer, buffer + sizeof(buffer));
+         }
+
+         ~ophysfsfilebuf()
+         {
+            sync();
+            PHYSFS_close(file);
+         }
+      protected:
+         int sync()
+         {
+            return overflow(traits_type::eof());
+         }
+
+         int overflow(int c)
+         {
+            char ch = static_cast<char>(c);
+            size_t size = pptr() - pbase();
+            if(size == 0)
+            {
+               return 0;
+            }
+            PHYSFS_sint64 bytes = PHYSFS_write(file, pbase(), 1, size);
+            if(bytes <= 0)
+            {
+               return traits_type::eof();
+            }
+            if(c != traits_type::eof())
+            {
+               PHYSFS_sint64 bytes = PHYSFS_write(file, &ch, 1, 1);
+               if(bytes <= 0)
+               {
+                  return traits_type::eof();
+               }
+            }
+            setp(buffer, buffer + bytes);
+            return 0;
+         }
+      private:
+         PHYSFS_File *file;
+         char buffer[1024];
+   };
+}
+
+namespace Unison
+{
+   namespace VFS
+   {
+      istream::istream(const std::string &filename) :
+         std::istream(new iphysfsfilebuf(filename))
+      {
+      }
+
+      istream::~istream()
+      {
+         delete rdbuf();
+      }
+
+      ostream::ostream(const std::string &filename) :
+         std::ostream(new ophysfsfilebuf(filename))
+      {
+      }
+
+      ostream::~ostream()
+      {
+         delete rdbuf();
+      }
+   }
+}
diff --git a/src/unison/src/video/Blittable.cpp b/src/unison/src/video/Blittable.cpp
new file mode 100644 (file)
index 0000000..3c4b8ac
--- /dev/null
@@ -0,0 +1,78 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#include <unison/video/Blittable.hpp>
+#include <unison/video/DisplayList.hpp>
+
+namespace Unison
+{
+   namespace Video
+   {
+      Blittable::~Blittable()
+      {
+      }
+
+      void Blittable::blit_section(const SurfaceSection &section, const Point &dst_pos, const RenderOptions &options)
+      {
+         blit(section.image, dst_pos, section.clip_rect, options);
+      }
+
+      void Blittable::blit_section(const TextureSection &section, const Point &dst_pos, const RenderOptions &options)
+      {
+         blit(section.image, dst_pos, section.clip_rect, options);
+      }
+
+      void Blittable::draw(const DisplayList &list)
+      {
+         list.draw(this);
+      }
+
+      BlittableSection::BlittableSection(Blittable &image, const Rect &clip_rect) :
+         image(image),
+         clip_rect(clip_rect)
+      {
+      }
+
+      void BlittableSection::blit(const Surface &src, const Point &dst_pos, const Rect &src_rect, const RenderOptions &options)
+      {
+         Rect overlap = clip_rect.get_overlap(Rect(dst_pos, src_rect.size));
+         if(overlap == Rect())
+         {
+            return;
+         }
+         Rect clipped_src_rect(src_rect.pos, overlap.size);
+         clipped_src_rect.pos += overlap.pos;
+         clipped_src_rect.pos -= dst_pos;
+         image.blit(src, overlap.pos - clip_rect.pos, clipped_src_rect, options);
+      }
+
+      void BlittableSection::blit(const Texture &src, const Point &dst_pos, const Rect &src_rect, const RenderOptions &options)
+      {
+         Rect overlap = clip_rect.get_overlap(Rect(dst_pos, src_rect.size));
+         if(overlap == Rect())
+         {
+            return;
+         }
+         Rect clipped_src_rect(src_rect.pos, overlap.size);
+         clipped_src_rect.pos += overlap.pos;
+         clipped_src_rect.pos -= dst_pos;
+         image.blit(src, overlap.pos - clip_rect.pos, clipped_src_rect, options);
+      }
+
+      void BlittableSection::fill(const Color &color, const Rect &rect)
+      {
+         Rect overlap = clip_rect.get_overlap(rect);
+         overlap.pos -= clip_rect.pos;
+         image.fill(color, overlap);
+      }
+
+      void BlittableSection::fill_blend(const Color &color, const Rect &rect)
+      {
+         Rect overlap = clip_rect.get_overlap(rect);
+         overlap.pos -= clip_rect.pos;
+         image.fill_blend(color, overlap);
+      }
+   }
+}
diff --git a/src/unison/src/video/Blitters.cpp b/src/unison/src/video/Blitters.cpp
new file mode 100644 (file)
index 0000000..624bd3e
--- /dev/null
@@ -0,0 +1,191 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#include <unison/video/Blitters.hpp>
+#include <unison/video/Surface.hpp>
+
+#include <assert.h>
+
+namespace Unison
+{
+   namespace Video
+   {
+      void Blitters::blit_upper(const Surface &src, Rect src_rect, Surface &dst, Point dst_pos, void (*blit_lower)(const Surface &, const Rect &, Surface &, const Point &))
+      {
+         assert(src.get_pixels());
+         assert(dst.get_pixels());
+         assert(blit_lower);
+         if(src_rect == Rect())
+         {
+            src_rect.size.x = src.get_size().x;
+            src_rect.size.y = src.get_size().y;
+         }
+         if(dst_pos.x < 0)
+         {
+            if(src_rect.size.x < (unsigned int) -dst_pos.x)
+            {
+               return;
+            }
+            src_rect.pos.x += -dst_pos.x;
+            src_rect.size.x += dst_pos.x;
+            dst_pos.x = 0;
+         }
+         if(dst_pos.y < 0)
+         {
+            if(src_rect.size.y < (unsigned int) -dst_pos.y)
+            {
+               return;
+            }
+            src_rect.pos.y += -dst_pos.y;
+            src_rect.size.y += dst_pos.y;
+            dst_pos.y = 0;
+         }
+         if(src_rect.pos.x < 0)
+         {
+            if(src_rect.size.x < (unsigned int) -src_rect.pos.x)
+            {
+               return;
+            }
+            src_rect.size.x += src_rect.pos.x;
+            src_rect.pos.x = 0;
+         }
+         if(src_rect.pos.y < 0)
+         {
+            if(src_rect.size.y < (unsigned int) -src_rect.pos.y)
+            {
+               return;
+            }
+            src_rect.size.y += src_rect.pos.y;
+            src_rect.pos.y = 0;
+         }
+         if(src_rect.get_right() > (int) src.get_size().x)
+         {
+            src_rect.size.x = src.get_size().x - src_rect.pos.x;
+         }
+         if(src_rect.get_bottom() > (int) src.get_size().y)
+         {
+            src_rect.size.y = src.get_size().y - src_rect.pos.y;
+         }
+         if(dst_pos.x + src_rect.size.x > dst.get_size().x)
+         {
+            src_rect.size.x = dst.get_size().x - dst_pos.x;
+         }
+         if(dst_pos.y + src_rect.size.y > dst.get_size().y)
+         {
+            src_rect.size.y = dst.get_size().y - dst_pos.y;
+         }
+         blit_lower(src, src_rect, dst, dst_pos);
+      }
+
+      void Blitters::blit_lower_none(const Surface &src, const Rect &src_rect, Surface &dst, const Point &dst_pos)
+      {
+         if(src_rect.pos == Point() && dst_pos == Point() && src.get_size().x == dst.get_size().x && src_rect.size.x == dst.get_size().x)
+         {
+            memcpy(dst.get_pixels(), src.get_pixels(), src_rect.size.x * src_rect.size.y * sizeof(Color));
+         }
+         else
+         {
+            const Color *src_line = src.get_pixels() + src_rect.pos.y * src.get_size().x + src_rect.pos.x;
+            Color *dst_line = dst.get_pixels() + dst_pos.y * dst.get_size().x + dst_pos.x;
+            for(unsigned int y = 0;y < src_rect.size.y;y++)
+            {
+               memcpy(dst_line, src_line, src_rect.size.x * sizeof(Color));
+               src_line += src.get_size().x;
+               dst_line += dst.get_size().x;
+            }
+         }
+      }
+
+      void Blitters::blit_lower_mask(const Surface &src, const Rect &src_rect, Surface &dst, const Point &dst_pos)
+      {
+         const Color *src_pixel = src.get_pixels() + src_rect.pos.y * src.get_size().x + src_rect.pos.x;
+         Color *dst_pixel = dst.get_pixels() + dst_pos.y * dst.get_size().x + dst_pos.x;
+         for(unsigned int y = 0;y < src_rect.size.y;y++)
+         {
+            for(unsigned int x = 0;x < src_rect.size.x;x++)
+            {
+               if(src_pixel->alpha)
+               {
+                  *dst_pixel = *src_pixel;
+               }
+               src_pixel++;
+               dst_pixel++;
+            }
+            src_pixel += src.get_size().x - src_rect.size.x;
+            dst_pixel += dst.get_size().x - src_rect.size.x;
+         }
+      }
+
+      void Blitters::blit_lower_alpha(const Surface &src, const Rect &src_rect, Surface &dst, const Point &dst_pos)
+      {
+         const Color *src_pixel = src.get_pixels() + src_rect.pos.y * src.get_size().x + src_rect.pos.x;
+         Color *dst_pixel = dst.get_pixels() + dst_pos.y * dst.get_size().x + dst_pos.x;
+         for(unsigned int y = 0;y < src_rect.size.y;y++)
+         {
+            for(unsigned int x = 0;x < src_rect.size.x;x++)
+            {
+               dst_pixel->red += src_pixel->red * src_pixel->alpha - dst_pixel->red * src_pixel->alpha;
+               dst_pixel->green += src_pixel->green * src_pixel->alpha - dst_pixel->green * src_pixel->alpha;
+               dst_pixel->blue += src_pixel->blue * src_pixel->alpha - dst_pixel->green * src_pixel->blue;
+               src_pixel++;
+               dst_pixel++;
+            }
+            src_pixel += src.get_size().x - src_rect.size.x;
+            dst_pixel += dst.get_size().x - src_rect.size.x;
+         }
+      }
+
+      void Blitters::blit_lower_add(const Surface &src, const Rect &src_rect, Surface &dst, const Point &dst_pos)
+      {
+         const Color *src_pixel = src.get_pixels() + src_rect.pos.y * src.get_size().x + src_rect.pos.x;
+         Color *dst_pixel = dst.get_pixels() + dst_pos.y * dst.get_size().x + dst_pos.x;
+         for(unsigned int y = 0;y < src_rect.size.y;y++)
+         {
+            for(unsigned int x = 0;x < src_rect.size.x;x++)
+            {
+               if(src_pixel->red != 0 && dst_pixel->red != 0xff)
+               {
+                  int redsum = dst_pixel->red + src_pixel->red * src_pixel->alpha / 0xff;
+                  dst_pixel->red = redsum & ~0xff ? 0xff : redsum;
+               }
+               if(src_pixel->green != 0 && dst_pixel->green != 0xff)
+               {
+                  int greensum = dst_pixel->green + src_pixel->green * src_pixel->alpha / 0xff;
+                  dst_pixel->green = greensum & ~0xff ? 0xff : greensum;
+               }
+               if(src_pixel->blue != 0 && dst_pixel->blue != 0xff)
+               {
+                  int bluesum = dst_pixel->blue + src_pixel->blue * src_pixel->alpha / 0xff;
+                  dst_pixel->blue = bluesum & ~0xff ? 0xff : bluesum;
+               }
+               src_pixel++;
+               dst_pixel++;
+            }
+            src_pixel += src.get_size().x - src_rect.size.x;
+            dst_pixel += dst.get_size().x - src_rect.size.x;
+         }
+      }
+
+      void Blitters::blit_lower_mod(const Surface &src, const Rect &src_rect, Surface &dst, const Point &dst_pos)
+      {
+         const Color *src_pixel = src.get_pixels() + src_rect.pos.y * src.get_size().x + src_rect.pos.x;
+         Color *dst_pixel = dst.get_pixels() + dst_pos.y * dst.get_size().x + dst_pos.x;
+         for(unsigned int y = 0;y < src_rect.size.y;y++)
+         {
+            for(unsigned int x = 0;x < src_rect.size.x;x++)
+            {
+               dst_pixel->red = dst_pixel->red * src_pixel->red / 0xff;
+               dst_pixel->green = dst_pixel->green * src_pixel->green / 0xff;
+               dst_pixel->blue = dst_pixel->blue * src_pixel->blue / 0xff;
+               dst_pixel->alpha = dst_pixel->alpha * src_pixel->alpha / 0xff;
+               src_pixel++;
+               dst_pixel++;
+            }
+            src_pixel += src.get_size().x - src_rect.size.x;
+            dst_pixel += dst.get_size().x - src_rect.size.x;
+         }
+      }
+   }
+}
diff --git a/src/unison/src/video/Color.cpp b/src/unison/src/video/Color.cpp
new file mode 100644 (file)
index 0000000..c29582b
--- /dev/null
@@ -0,0 +1,21 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#include <unison/video/Color.hpp>
+
+namespace Unison
+{
+   namespace Video
+   {
+      const Color Color::BLACK(0, 0, 0);
+      const Color Color::RED(0xff, 0, 0);
+      const Color Color::GREEN(0, 0xff, 0);
+      const Color Color::BLUE(0, 0, 0xff);
+      const Color Color::CYAN(0, 0xff, 0xff);
+      const Color Color::MAGENTA(0xff, 0, 0xff);
+      const Color Color::YELLOW(0xff, 0xff, 0);
+      const Color Color::WHITE(0xff, 0xff, 0xff);
+   }
+}
diff --git a/src/unison/src/video/Renderers.cpp b/src/unison/src/video/Renderers.cpp
new file mode 100644 (file)
index 0000000..a716282
--- /dev/null
@@ -0,0 +1,98 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#include <unison/video/Renderers.hpp>
+#include <unison/video/Window.hpp>
+#include <unison/video/Texture.hpp>
+#include "auto/Renderer.hpp"
+#include "sdl/Renderer.hpp"
+#include "opengl/Renderer.hpp"
+
+#include <assert.h>
+
+namespace Unison
+{
+   namespace Video
+   {
+      Renderers::Renderers() :
+         auto_renderer(0),
+         renderer(0),
+         renderers()
+      {
+         auto_renderer = new Auto::Renderer(renderers);
+         renderer = auto_renderer;
+         add_renderer(new SDL::Renderer());
+         add_renderer(new OpenGL::Renderer());
+         renderer->init();
+      }
+
+      Renderers::~Renderers()
+      {
+         assert(renderer);
+         renderer->quit();
+         std::for_each(renderers.begin(), renderers.end(), std::ptr_fun(operator delete));
+         delete auto_renderer;
+      }
+
+      Renderers &Renderers::get()
+      {
+         static Renderers renderers;
+         return renderers;
+      }
+
+      namespace
+      {
+         bool match_name(Backend::Renderer *renderer, std::string name)
+         {
+            return renderer && renderer->get_name() == name;
+         }
+      }
+
+      void Renderers::set_renderer(const std::string &name)
+      {
+         Area window_size;
+         bool fullscreen = false;
+         if(Window::get().is_open())
+         {
+            window_size = Window::get().get_size();
+            fullscreen = Window::get().is_fullscreen();
+         }
+         std::vector<Surface> surfaces = Texture::save_textures();
+         renderer->quit();
+         if(name == "auto")
+         {
+            renderer = auto_renderer;
+         }
+         else
+         {
+            std::vector<Backend::Renderer *>::iterator found = std::find_if(renderers.begin(), renderers.end(), std::bind2nd(std::ptr_fun(match_name), name));
+            if(found == renderers.end())
+            {
+               fprintf(stderr, "Renderer '%s' not found.\n", name.c_str());
+               return;
+            }
+            renderer = *found;
+         }
+         renderer->init();
+         Texture::load_textures(surfaces);
+         if(window_size != Area())
+         {
+            Window::get().open(window_size, fullscreen);
+         }
+      }
+
+
+      Backend::Renderer &Renderers::get_renderer()
+      {
+         assert(renderer);
+         return *renderer;
+      }
+
+      void Renderers::add_renderer(Backend::Renderer *renderer)
+      {
+         renderers.push_back(renderer);
+      }
+   }
+}
diff --git a/src/unison/src/video/Surface.cpp b/src/unison/src/video/Surface.cpp
new file mode 100644 (file)
index 0000000..9ebfbdb
--- /dev/null
@@ -0,0 +1,242 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#include <unison/video/Texture.hpp>
+#include <unison/video/Window.hpp>
+#include <unison/video/Renderers.hpp>
+#include <unison/video/Color.hpp>
+#include <unison/video/sdl/Blitters.hpp>
+#include <unison/video/backend/Renderer.hpp>
+#include <unison/video/backend/Texture.hpp>
+#include <unison/vfs/stream.hpp>
+
+#include <assert.h>
+
+namespace Unison
+{
+   namespace Video
+   {
+      Surface::Surface() :
+         pixels(0)
+      {
+      }
+
+      Surface::Surface(const std::string &filename) :
+         pixels(0)
+      {
+         *this = Renderers::get().get_renderer().load_surface(filename);
+      }
+
+      Surface::Surface(const std::string &filename, const Color &colorkey) :
+         pixels(0)
+      {
+         *this = Renderers::get().get_renderer().load_surface(filename, colorkey);
+      }
+
+      Surface::Surface(const Area &size) :
+         pixels(new PixelBuffer(size))
+      {
+         //fill(Color::WHITE);
+      }
+
+      Surface::Surface(const Surface &rhs) :
+         Blittable(),
+         pixels(rhs.pixels)
+      {
+         if(pixels)
+         {
+            pixels->ref();
+         }
+      }
+
+      Surface::~Surface()
+      {
+         if(pixels)
+         {
+            pixels->unref();
+         }
+      }
+
+      Surface &Surface::operator =(const Surface &rhs)
+      {
+         if(rhs.pixels)
+         {
+            rhs.pixels->ref();
+         }
+         if(pixels)
+         {
+            pixels->unref();
+         }
+         pixels = rhs.pixels;
+         return *this;
+      }
+
+      void Surface::save(const std::string &filename) const
+      {
+         Renderers::get().get_renderer().save_surface(*this, filename);
+      }
+
+      void Surface::blit(const Surface &src, const Point &dst_pos, const Rect &src_rect, const RenderOptions &options)
+      {
+         cow();
+         assert(pixels);
+         Renderers::get().get_renderer().blit(src, src_rect, *this, dst_pos, options);
+      }
+
+      void Surface::blit(const Texture &src, const Point &dst_pos, const Rect &src_rect, const RenderOptions &options)
+      {
+         cow();
+         assert(pixels);
+         Renderers::get().get_renderer().blit(Backend::Texture::get_texture(src.get_id()), src_rect, *this, dst_pos, options);
+      }
+
+      void Surface::fill(const Color &color, const Rect &rect)
+      {
+         cow();
+         assert(pixels);
+         Renderers::get().get_renderer().fill(*this, color, rect);
+      }
+
+      void Surface::fill_blend(const Color &color, const Rect &rect)
+      {
+         cow();
+         assert(pixels);
+         Renderers::get().get_renderer().fill_blend(*this, color, rect);
+      }
+
+      namespace
+      {
+         Color merge(const Color &color0, const Color &color1, int rem, int total)
+         {
+            return Color((color0.red * (total - rem) + color1.red * rem) / total,
+                         (color0.green * (total - rem) + color1.green * rem) / total,
+                         (color0.blue * (total - rem) + color1.blue * rem) / total,
+                         (color0.alpha * (total - rem) + color1.alpha * rem) / total);
+         }
+      }
+
+      Surface Surface::scale(unsigned int numerator, unsigned int denominator) const
+      {
+         assert(pixels);
+         if(numerator == denominator)
+         {
+            return *this;
+         }
+         else
+         {
+            Surface scaled(get_size() * numerator / denominator);
+            for(unsigned int y = 0;y < scaled.get_size().y;y++)
+            {
+               for(unsigned int x = 0;x < scaled.get_size().x;x++)
+               {
+                  unsigned int srcx = x * denominator / numerator;
+                  unsigned int srcy = y * denominator / numerator;
+                  //scaled.set_pixel(Point(x, y), get_pixel(Point(srcx, srcy)));
+                  int incx = (srcx + 1 == get_size().x ? 0 : 1);
+                  int incy = (srcy + 1 == get_size().y ? 0 : 1);
+                  Color color00 = get_pixel(srcx, srcy);
+                  Color color01 = get_pixel(srcx + incx, srcy);
+                  Color color10 = get_pixel(srcx, srcy + incy);
+                  Color color11 = get_pixel(srcx + incx, srcy + incy);
+                  int remx = x * denominator % numerator;
+                  Color color0 = merge(color00, color01, remx, numerator);
+                  Color color1 = merge(color10, color11, remx, numerator);
+                  int remy = y * denominator % numerator;
+                  Color color = merge(color0, color1, remy, numerator);
+                  scaled.get_pixel(x, y) = color;
+               }
+            }
+            return scaled;
+         }
+      }
+
+      Surface Surface::h_flip() const
+      {
+         assert(pixels);
+         Surface flipped(get_size());
+         for(unsigned int y = 0;y < get_size().y;y++)
+         {
+            for(unsigned int x = 0;x < get_size().x;x++)
+            {
+               flipped.get_pixel(x, y) = get_pixel(get_size().x - x - 1, y);
+            }
+         }
+         return flipped;
+      }
+
+      Surface Surface::v_flip() const
+      {
+         assert(pixels);
+         Surface flipped(get_size());
+         for(unsigned int y = 0;y < get_size().y;y++)
+         {
+            for(unsigned int x = 0;x < get_size().x;x++)
+            {
+               flipped.get_pixel(x, y) = get_pixel(x, get_size().y - y - 1);
+            }
+         }
+         return flipped;
+      }
+
+      Surface Surface::modulate(const Color &color) const
+      {
+         assert(pixels);
+         if(color == Color::WHITE)
+         {
+            return *this;
+         }
+         else
+         {
+            Surface modulated(get_size());
+            for(unsigned int y = 0;y < get_size().y;y++)
+            {
+               for(unsigned int x = 0;x < get_size().x;x++)
+               {
+                  Color pixel = get_pixel(x, y);
+                  pixel.red = pixel.red * color.red / 0xff;
+                  pixel.green = pixel.green * color.green / 0xff;
+                  pixel.blue = pixel.blue * color.blue / 0xff;
+                  pixel.alpha = pixel.alpha * color.alpha / 0xff;
+                  modulated.get_pixel(x, y) = pixel;
+               }
+            }
+            return modulated;
+         }
+      }
+
+      Surface Surface::modulate(unsigned char alpha) const
+      {
+         assert(pixels);
+         if(alpha == 0xff)
+         {
+            return *this;
+         }
+         else
+         {
+            Surface modulated(get_size());
+            for(unsigned int y = 0;y < get_size().y;y++)
+            {
+               for(unsigned int x = 0;x < get_size().x;x++)
+               {
+                  Color pixel = get_pixel(x, y);
+                  pixel.alpha = pixel.alpha * alpha / 0xff;
+                  modulated.get_pixel(x, y) = pixel;
+               }
+            }
+            return modulated;
+         }
+      }
+
+      void Surface::cow()
+      {
+         if(pixels && pixels->refcount > 1)
+         {
+            PixelBuffer *original = pixels;
+            pixels = new PixelBuffer(pixels->size);
+            memcpy(pixels->buffer, original->buffer, pixels->size.x * pixels->size.y * sizeof(Color));
+         }
+      }
+   }
+}
diff --git a/src/unison/src/video/Texture.cpp b/src/unison/src/video/Texture.cpp
new file mode 100644 (file)
index 0000000..ac26976
--- /dev/null
@@ -0,0 +1,172 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#include <unison/video/Texture.hpp>
+#include <unison/video/backend/Texture.hpp>
+
+#include <assert.h>
+
+namespace Unison
+{
+   namespace Video
+   {
+      std::set<Texture *> Texture::textures = std::set<Texture*>();
+
+      Texture::Texture() :
+         id(INVALID_TEXTURE_ID)
+      {
+      }
+
+      Texture::Texture(const std::string &filename) :
+         id(Backend::Texture::get_texture_id(filename))
+      {
+         assert(id != INVALID_TEXTURE_ID);
+         Backend::Texture::get_texture(id)->ref();
+         textures.insert(this);
+      }
+
+      Texture::Texture(const std::string &filename, const Color &colorkey) :
+         id(Backend::Texture::get_texture_id(filename, colorkey))
+      {
+         assert(id != INVALID_TEXTURE_ID);
+         Backend::Texture::get_texture(id)->ref();
+         textures.insert(this);
+      }
+
+      Texture::Texture(const Surface &surface) :
+         id(Backend::Texture::get_texture_id(surface))
+      {
+         assert(id != INVALID_TEXTURE_ID);
+         Backend::Texture::get_texture(id)->ref();
+         textures.insert(this);
+      }
+
+      Texture::Texture(const Texture &rhs) :
+         Blittable(),
+         id(rhs.id)
+      {
+         if(id != INVALID_TEXTURE_ID)
+         {
+            Backend::Texture::get_texture(id)->ref();
+         }
+         textures.insert(this);
+      }
+
+      Texture::~Texture()
+      {
+         textures.erase(this);
+         if(id != INVALID_TEXTURE_ID)
+         {
+            Backend::Texture::get_texture(id)->unref();
+         }
+      }
+
+      Texture &Texture::operator =(const Texture &rhs)
+      {
+         if(rhs.id != INVALID_TEXTURE_ID)
+         {
+            Backend::Texture::get_texture(rhs.id)->ref();
+         }
+         if(id != INVALID_TEXTURE_ID)
+         {
+            Backend::Texture::get_texture(id)->unref();
+         }
+         id = rhs.id;
+         return *this;
+      }
+
+      TextureID Texture::get_id() const
+      {
+         return id;
+      }
+
+      Area Texture::get_size() const
+      {
+         assert(id != INVALID_TEXTURE_ID);
+         return Backend::Texture::get_texture(id)->get_size();
+      }
+
+      void Texture::blit(const Surface &src, const Point &dst_pos, const Rect &src_rect, const RenderOptions &options)
+      {
+         assert(id != INVALID_TEXTURE_ID);
+         cow();
+         Backend::Texture::get_texture(id)->blit(src, dst_pos, src_rect, options);
+      }
+
+      void Texture::blit(const Texture &src, const Point &dst_pos, const Rect &src_rect, const RenderOptions &options)
+      {
+         assert(id != INVALID_TEXTURE_ID);
+         cow();
+         Backend::Texture::get_texture(id)->blit(src, dst_pos, src_rect, options);
+      }
+
+      void Texture::fill(const Color &color, const Rect &rect)
+      {
+         assert(id != INVALID_TEXTURE_ID);
+         cow();
+         Backend::Texture::get_texture(id)->fill(color, rect);
+      }
+
+      void Texture::fill_blend(const Color &color, const Rect &rect)
+      {
+         assert(id != INVALID_TEXTURE_ID);
+         cow();
+         Backend::Texture::get_texture(id)->fill_blend(color, rect);
+      }
+
+      std::vector<Surface> Texture::save_textures()
+      {
+         recover_texture_ids();
+         return Backend::Texture::save_textures();
+      }
+
+      namespace
+      {
+         void ref(Texture *texture)
+         {
+            assert(texture);
+            TextureID id = texture->get_id();
+            if(id != INVALID_TEXTURE_ID)
+            {
+               Backend::Texture::get_texture(id)->ref();
+            }
+         }
+      }
+
+      void Texture::load_textures(const std::vector<Surface> &surfaces)
+      {
+         Backend::Texture::load_textures(surfaces);
+         std::for_each(textures.begin(), textures.end(), ref);
+      }
+
+      void Texture::recover_texture_ids()
+      {
+         std::map<TextureID, TextureID> change_map = Backend::Texture::recover_texture_ids();
+         if(!change_map.empty())
+         {
+            for(std::set<Texture *>::iterator iter = textures.begin(), end = textures.end();iter != end;++iter)
+            {
+               if(change_map.find((*iter)->id) != change_map.end())
+               {
+                  (*iter)->id = change_map[(*iter)->id];
+               }
+            }
+         }
+      }
+
+      void Texture::cow()
+      {
+         assert(id != INVALID_TEXTURE_ID);
+         if(Backend::Texture::get_texture(id)->get_refcount() > 1)
+         {
+            TextureID old = id;
+            id = Backend::Texture::get_texture_id(Backend::Texture::get_texture(id)->get_surface());
+            assert(id != INVALID_TEXTURE_ID);
+            Backend::Texture::get_texture(id)->ref();
+            Backend::Texture::get_texture(old)->unref();
+         }
+      }
+   }
+}
diff --git a/src/unison/src/video/Window.cpp b/src/unison/src/video/Window.cpp
new file mode 100644 (file)
index 0000000..ca60883
--- /dev/null
@@ -0,0 +1,129 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#include <unison/video/Window.hpp>
+#include <unison/video/Surface.hpp>
+#include <unison/video/Texture.hpp>
+#include <unison/video/Renderers.hpp>
+#include <unison/video/backend/Renderer.hpp>
+#include <unison/video/backend/Window.hpp>
+
+#include <assert.h>
+
+namespace Unison
+{
+   namespace Video
+   {
+      Window::Window() :
+         logical_size(),
+         title(),
+         icon(Surface(Area(1, 1))),
+         window(0),
+         list(),
+         layers()
+      {
+      }
+
+      Window::~Window()
+      {
+      }
+
+      Window &Window::get()
+      {
+         // FIXME: fix init order more naturally
+         Renderers::get();
+         static Window window;
+         return window;
+      }
+
+      void Window::set_logical_size(const Area &logical_size)
+      {
+         this->logical_size = logical_size;
+         if(window)
+         {
+            std::vector<Surface> surfaces = Texture::save_textures();
+            open(get_size(), is_fullscreen());
+            Texture::load_textures(surfaces);
+         }
+      }
+
+      Area Window::get_logical_size() const
+      {
+         return logical_size;
+      }
+
+      void Window::open(const Area &size, bool fullscreen)
+      {
+         std::vector<Surface> surfaces = Texture::save_textures();
+         if(logical_size.x == 0 || logical_size.y == 0)
+         {
+            logical_size = size;
+         }
+         delete window;
+         window = Renderers::get().get_renderer().create_window(size, logical_size, fullscreen);
+         assert(window);
+         Texture::load_textures(surfaces);
+         window->set_title(title);
+         window->set_icon(icon);
+         redraw();
+      }
+
+      void Window::take_screenshot(const std::string &filename) const
+      {
+         assert(window);
+         window->take_screenshot(filename);
+      }
+
+      void Window::flip()
+      {
+         list = layers;
+         layers.clear();
+         redraw();
+      }
+
+      void Window::redraw()
+      {
+         assert(window);
+         fill(Color::BLACK);
+         window->draw(list);
+         window->flip();
+      }
+
+      void Window::set_title(const std::string &title)
+      {
+         this->title = title;
+         if(window)
+         {
+            window->set_title(title);
+         }
+      }
+
+      void Window::set_icon(const Surface &icon)
+      {
+         this->icon = icon.get_size() == Area() ? Surface(Area(1, 1)) : icon;
+         if(window)
+         {
+            window->set_icon(icon);
+         }
+      }
+
+      Area Window::get_size() const
+      {
+         assert(window);
+         return window->get_size();
+      }
+
+      bool Window::is_fullscreen() const
+      {
+         assert(window);
+         return window->is_fullscreen();
+      }
+
+      bool Window::is_open() const
+      {
+         return window;
+      }
+   }
+}
diff --git a/src/unison/src/video/auto/Renderer.cpp b/src/unison/src/video/auto/Renderer.cpp
new file mode 100644 (file)
index 0000000..c813fcd
--- /dev/null
@@ -0,0 +1,113 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#include "Renderer.hpp"
+#include <unison/video/Surface.hpp>
+#include <unison/video/Window.hpp>
+
+#include <assert.h>
+
+namespace Unison
+{
+   namespace Video
+   {
+      namespace Auto
+      {
+         Renderer::Renderer(const std::vector<Backend::Renderer *> &renderers) :
+            renderer(0),
+            renderers(renderers)
+         {
+         }
+
+         Renderer::~Renderer()
+         {
+         }
+
+         void Renderer::init()
+         {
+            assert(!renderer);
+            std::vector<Backend::Renderer *>::const_reverse_iterator found = std::find_if(renderers.rbegin(), renderers.rend(), std::mem_fun(&Unison::Video::Backend::Renderer::is_usable));
+            if(found == renderers.rend())
+            {
+               fputs("No usable renderers found\n", stderr);
+               return;
+            }
+            renderer = *found;
+            renderer->init();
+         }
+
+         void Renderer::quit()
+         {
+            assert(renderer);
+            renderer->quit();
+            renderer = 0;
+         }
+
+         std::string Renderer::get_name()
+         {
+            return "auto";
+         }
+
+         bool Renderer::is_usable()
+         {
+            return std::find_if(renderers.begin(), renderers.end(), std::mem_fun(&Unison::Video::Backend::Renderer::is_usable)) != renderers.end();
+         }
+
+         Surface Renderer::load_surface(const std::string &filename)
+         {
+            assert(renderer);
+            return renderer->load_surface(filename);
+         }
+
+         Surface Renderer::load_surface(const std::string &filename, const Color &colorkey)
+         {
+            assert(renderer);
+            return renderer->load_surface(filename, colorkey);
+         }
+
+         void Renderer::save_surface(const Surface &surface, const std::string &filename)
+         {
+            assert(renderer);
+            return renderer->save_surface(surface, filename);
+         }
+
+         void Renderer::blit(const Surface &src, const Rect &src_rect, Surface &dst, const Point &dst_pos, const RenderOptions &options)
+         {
+            assert(renderer);
+            renderer->blit(src, src_rect, dst, dst_pos, options);
+         }
+
+         void Renderer::blit(Backend::Texture *src, const Rect &src_rect, Surface &dst, const Point &dst_pos, const RenderOptions &options)
+         {
+            assert(renderer);
+            renderer->blit(src, src_rect, dst, dst_pos, options);
+         }
+
+         void Renderer::fill(Surface &dst, const Color &color, const Rect &rect)
+         {
+            assert(renderer);
+            renderer->fill(dst, color, rect);
+         }
+
+         void Renderer::fill_blend(Surface &dst, const Color &color, const Rect &rect)
+         {
+            assert(renderer);
+            renderer->fill_blend(dst, color, rect);
+         }
+
+         Backend::Window *Renderer::create_window(const Area &size, const Area &logical_size, bool fullscreen)
+         {
+            assert(renderer);
+            return renderer->create_window(size, logical_size, fullscreen);
+         }
+
+         Backend::Texture *Renderer::create_texture(const Surface &surface)
+         {
+            assert(renderer);
+            return renderer->create_texture(surface);
+         }
+      }
+   }
+}
diff --git a/src/unison/src/video/auto/Renderer.hpp b/src/unison/src/video/auto/Renderer.hpp
new file mode 100644 (file)
index 0000000..3b429d4
--- /dev/null
@@ -0,0 +1,57 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef UNISON_VIDEO_AUTO_RENDERER_HPP
+#define UNISON_VIDEO_AUTO_RENDERER_HPP
+
+#include <unison/video/backend/Renderer.hpp>
+
+#include <string> 
+#include <vector> 
+
+namespace Unison
+{
+   namespace Video
+   {
+      namespace Backend
+      {
+         class Texture;
+         class Window;
+      }
+      namespace Auto
+      {
+         /// Does rendering tasks like blits and color fills using SDL
+         class Renderer : public Backend::Renderer
+         {
+            public:
+               Renderer(const std::vector<Backend::Renderer *> &renderers);
+               ~Renderer();
+
+               void init();
+               void quit();
+
+               std::string get_name();
+               bool is_usable();
+
+               Surface load_surface(const std::string &filename);
+               Surface load_surface(const std::string &filename, const Color &colorkey);
+               void save_surface(const Surface &surface, const std::string &filename);
+
+               void blit(const Surface &src, const Rect &src_rect, Surface &dst, const Point &dst_pos, const RenderOptions &options);
+               void blit(Backend::Texture *src, const Rect &src_rect, Surface &dst, const Point &dst_pos, const RenderOptions &options);
+               void fill(Surface &dst, const Color &color, const Rect &rect);
+               void fill_blend(Surface &dst, const Color &color, const Rect &rect);
+
+               Backend::Window *create_window(const Area &size, const Area &logical_size, bool fullscreen);
+               Backend::Texture *create_texture(const Surface &surface);
+            private:
+               Backend::Renderer *renderer;
+               const std::vector<Backend::Renderer *> &renderers;
+         };
+      }
+   }
+}
+
+#endif
diff --git a/src/unison/src/video/backend/Texture.cpp b/src/unison/src/video/backend/Texture.cpp
new file mode 100644 (file)
index 0000000..6b41b62
--- /dev/null
@@ -0,0 +1,209 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#include <unison/video/backend/Texture.hpp>
+#include <unison/video/Renderers.hpp>
+#include <unison/video/backend/Renderer.hpp>
+
+#include <assert.h>
+#include <algorithm>
+
+namespace Unison
+{
+   namespace Video
+   {
+      namespace Backend
+      {
+         std::vector<Texture *> Texture::textures = std::vector<Texture *>();
+         std::map<std::string, TextureID> Texture::named_textures = std::map<std::string, TextureID>();
+
+         Texture::Texture(const Surface &surface) :
+            surface(surface),
+            size(surface.get_size()),
+            refcount(0)
+         {
+            assert(surface.get_size() != Area());
+         }
+
+         Texture::~Texture()
+         {
+         }
+
+         Area Texture::get_size()
+         {
+            return size;
+         }
+
+         void Texture::ref()
+         {
+            refcount++;
+         }
+
+         void Texture::unref()
+         {
+            assert(refcount > 0);
+            refcount--;
+            if(refcount == 0)
+            {
+               std::string name = get_name(get_texture_id(this));
+               *std::find(textures.begin(), textures.end(), this) = 0;
+               if(!name.empty())
+               {
+                  named_textures.erase(name);
+               }
+               delete this;
+            }
+         }
+
+         int Texture::get_refcount()
+         {
+            return refcount;
+         }
+
+         namespace
+         {
+            class TextureSaver
+            {
+               public:
+                  void operator () (Texture *texture)
+                  {
+                     if(texture)
+                     {
+                        texture->save();
+                        surfaces.push_back(texture->get_surface());
+                     }
+                     else
+                     {
+                        surfaces.push_back(Surface());
+                     }
+                     delete texture;
+                  }
+                  std::vector<Surface> surfaces;
+            };
+
+            class TextureLoader
+            {
+               public:
+                  void operator () (Surface surface)
+                  {
+                     if(surface.get_size() != Area())
+                     {
+                        textures.push_back(Renderers::get().get_renderer().create_texture(surface));
+                     }
+                     else
+                     {
+                        textures.push_back(0);
+                     }
+                  }
+                  std::vector<Texture *> textures;
+            };
+         }
+
+         std::vector<Surface> Texture::save_textures()
+         {
+            std::vector<Surface> surfaces = std::for_each(textures.begin(), textures.end(), TextureSaver()).surfaces;
+            textures.clear();
+            return surfaces;
+         }
+
+         void Texture::load_textures(const std::vector<Surface> &surfaces)
+         {
+            assert(textures.empty());
+            textures = std::for_each(surfaces.begin(), surfaces.end(), TextureLoader()).textures;
+         }
+
+         std::map<TextureID, TextureID> Texture::recover_texture_ids()
+         {
+            std::map<TextureID, TextureID> change_map;
+            std::vector<Texture *> new_textures;
+            bool null_texture_found = false;
+            for(std::vector<Texture *>::iterator iter = textures.begin(), end = textures.end();iter != end;++iter)
+            {
+               if(*iter)
+               {
+                  new_textures.push_back(*iter);
+                  if(null_texture_found)
+                  {
+                     change_map[iter - textures.begin()] = new_textures.size() -1;
+                  }
+               }
+               else
+               {
+                  null_texture_found = true;
+               }
+            }
+            textures = new_textures;
+            return change_map;
+         }
+
+         TextureID Texture::get_texture_id(const std::string &filename)
+         {
+            if(named_textures.find(filename) != named_textures.end())
+            {
+               return named_textures[filename];
+            }
+            textures.push_back(Renderers::get().get_renderer().create_texture(Surface(filename)));
+            named_textures[filename] = textures.size() - 1;
+            return textures.size() - 1;
+         }
+
+         TextureID Texture::get_texture_id(const std::string &filename, const Color&colorkey)
+         {
+            if(named_textures.find(filename) != named_textures.end())
+            {
+               return named_textures[filename];
+            }
+            textures.push_back(Renderers::get().get_renderer().create_texture(Surface(filename, colorkey)));
+            named_textures[filename] = textures.size() - 1;
+            return textures.size() - 1;
+         }
+
+         TextureID Texture::get_texture_id(const Surface &surface)
+         {
+            textures.push_back(Renderers::get().get_renderer().create_texture(surface));
+            return textures.size() - 1;
+         }
+
+         TextureID Texture::get_texture_id(Texture *texture)
+         {
+            std::vector<Texture *>::iterator found = std::find(textures.begin(), textures.end(), texture);
+            if(found != textures.end())
+            {
+               return found - textures.begin();
+            }
+            return INVALID_TEXTURE_ID;
+         }
+
+         Texture *Texture::get_texture(TextureID id)
+         {
+            assert(id < textures.size());
+            assert(textures[id]);
+            return textures[id];
+         }
+
+         namespace
+         {
+            bool match_id(std::pair<std::string, TextureID> pair, TextureID id)
+            {
+               return pair.second == id;
+            }
+         }
+
+         std::string Texture::get_name(TextureID id)
+         {
+            if(id == INVALID_TEXTURE_ID)
+            {
+               return std::string();
+            }
+            std::map<std::string, TextureID>::iterator found = std::find_if(named_textures.begin(), named_textures.end(), std::bind2nd(std::ptr_fun(match_id), id));
+            if(found == named_textures.end())
+            {
+               return std::string();
+            }
+            return found->first;
+         }
+      }
+   }
+}
diff --git a/src/unison/src/video/opengl/Renderer.cpp b/src/unison/src/video/opengl/Renderer.cpp
new file mode 100644 (file)
index 0000000..fd87b6b
--- /dev/null
@@ -0,0 +1,194 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#include "Renderer.hpp"
+#include "Texture.hpp"
+#include "Window.hpp"
+#include <unison/video/Surface.hpp>
+#include <unison/video/Window.hpp>
+#include <unison/video/sdl/Blitters.hpp>
+#include <unison/video/backend/Texture.hpp>
+#include <unison/vfs/sdl/Utils.hpp>
+
+#include <assert.h>
+
+#include "SDL.h"
+#include "SDL_image.h"
+
+namespace Unison
+{
+   namespace Video
+   {
+      namespace OpenGL
+      {
+         Renderer::Renderer()
+         {
+         }
+
+         Renderer::~Renderer()
+         {
+         }
+
+         void Renderer::init()
+         {
+            SDL_InitSubSystem(SDL_INIT_VIDEO);
+
+            glLoad(0);
+         }
+
+         void Renderer::quit()
+         {
+            SDL_QuitSubSystem(SDL_INIT_VIDEO);
+         }
+
+         std::string Renderer::get_name()
+         {
+            return "opengl";
+         }
+
+         bool Renderer::is_usable()
+         {
+            SDL_InitSubSystem(SDL_INIT_VIDEO);
+
+            if(SDL_GL_LoadLibrary(0))
+            {
+               SDL_QuitSubSystem(SDL_INIT_VIDEO);
+               return false;
+            }
+
+            if(!SDL_ListModes(0, SDL_OPENGL))
+            {
+               SDL_QuitSubSystem(SDL_INIT_VIDEO);
+               return false;
+            }
+
+            /*const SDL_VideoInfo *info = SDL_GetVideoInfo();
+            if(SDL_VideoModeOK(info->current_w, info->current_h, 0, SDL_OPENGL | SDL_FULLSCREEN))
+            {
+               SDL_QuitSubSystem(SDL_INIT_VIDEO);
+               return false;
+            }*/
+
+            SDL_QuitSubSystem(SDL_INIT_VIDEO);
+
+            return true;
+         }
+
+         Surface Renderer::load_surface(const std::string &filename)
+         {
+            SDL_Surface *image = IMG_Load_RW(VFS::SDL::Utils::open_physfs_in(filename), 1);
+            assert(image);
+            Surface surface = Surface(Area(image->w, image->h));
+            SDL_Surface *sdl_surface = SDL::Blitters::create_sdl_surface_from(surface);
+            assert(sdl_surface);
+            SDL::Blitters::blit_blend_none(image, Rect(), sdl_surface, Point());
+            SDL_FreeSurface(sdl_surface);
+            return surface;
+         }
+
+         Surface Renderer::load_surface(const std::string &filename, const Color &colorkey)
+         {
+            SDL_Surface *image = IMG_Load_RW(VFS::SDL::Utils::open_physfs_in(filename), 1);
+            assert(image);
+            Surface surface = Surface(Area(image->w, image->h));
+            SDL_Surface *sdl_surface = SDL::Blitters::create_sdl_surface_from(surface);
+            assert(sdl_surface);
+            SDL_SetColorKey(image, SDL_SRCCOLORKEY, SDL_MapRGB(image->format, colorkey.red, colorkey.blue, colorkey.alpha));
+            SDL::Blitters::blit_blend_none(image, Rect(), sdl_surface, Point());
+            SDL_FreeSurface(sdl_surface);
+            return surface;
+         }
+
+         void Renderer::save_surface(const Surface &surface, const std::string &filename)
+         {
+            SDL_Surface *sdl_surface = SDL::Blitters::create_sdl_surface_from(surface);
+            assert(sdl_surface);
+            SDL_SaveBMP(sdl_surface, filename.c_str());
+            SDL_FreeSurface(sdl_surface);
+         }
+
+         void Renderer::blit(const Surface &src, const Rect &src_rect, Surface &dst, const Point &dst_pos, const RenderOptions &options)
+         {
+            Surface fragment;
+            if(src_rect.pos == Point() && (src_rect.size == Area() || src_rect.size == src.get_size()))
+            {
+               fragment = src;
+            }
+            else
+            {
+               fragment = Surface(src_rect.size);
+               Blitters::blit_blend_none(src, src_rect, fragment, Point());
+            }
+            if(options.h_flip)
+            {
+               fragment = fragment.h_flip();
+            }
+            if(options.v_flip)
+            {
+               fragment = fragment.v_flip();
+            }
+            SDL_Surface *src_surface = SDL::Blitters::create_sdl_surface_from(fragment.modulate(options.color).modulate(options.alpha));
+            assert(src_surface);
+
+            SDL_Surface *dst_surface = SDL::Blitters::create_sdl_surface_from(dst);
+            assert(dst_surface);
+
+
+            SDL::Blitters::blit_blend(src_surface, Rect(Point(), fragment.get_size()), dst_surface, dst_pos, options.blend);
+
+            SDL_FreeSurface(dst_surface);
+            SDL_FreeSurface(src_surface);
+         }
+
+         void Renderer::blit(Backend::Texture *src, const Rect &src_rect, Surface &dst, const Point &dst_pos, const RenderOptions &options)
+         {
+            assert(src);
+            assert(dst.get_size() != Area());
+
+            blit(src->get_surface(), src_rect, dst, dst_pos, options);
+         }
+
+         void Renderer::fill(Surface &dst, const Color &color, const Rect &rect)
+         {
+            SDL_Surface *dst_surface = SDL::Blitters::create_sdl_surface_from(dst);
+            assert(dst_surface);
+
+            Uint32 mapped = SDL_MapRGBA(dst_surface->format, color.red, color.green, color.blue, color.alpha);
+            SDL_FillRect(dst_surface, &rect, mapped);
+         }
+
+         void Renderer::fill_blend(Surface &dst, const Color &color, const Rect &rect)
+         {
+            SDL_Surface *dst_surface = SDL::Blitters::create_sdl_surface_from(dst);
+            assert(dst_surface);
+
+            Uint32 mapped = SDL_MapRGBA(dst_surface->format, color.red, color.green, color.blue, color.alpha);
+            if(color.alpha == 0xff)
+            {
+               SDL_FillRect(dst_surface, &rect, mapped);
+            }
+            else if(color.alpha != 0x00)
+            {
+               SDL_Surface *temp = SDL_CreateRGBSurface(dst_surface->flags, rect.size.x, rect.size.y, dst_surface->format->BitsPerPixel, dst_surface->format->Rmask, dst_surface->format->Gmask, dst_surface->format->Bmask, dst_surface->format->Amask);
+
+               SDL_FillRect(temp, 0, mapped);
+               SDL_SetAlpha(temp, SDL_SRCALPHA | SDL_RLEACCEL, color.alpha);
+               SDL_BlitSurface(temp, 0, dst_surface, &rect);
+               SDL_FreeSurface(temp);
+            }
+         }
+
+         Backend::Window *Renderer::create_window(const Area &size, const Area &logical_size, bool fullscreen)
+         {
+            return new Window(size, logical_size, fullscreen);
+         }
+
+         Backend::Texture *Renderer::create_texture(const Surface &surface)
+         {
+            return new Texture(surface);
+         }
+      }
+   }
+}
diff --git a/src/unison/src/video/opengl/Renderer.hpp b/src/unison/src/video/opengl/Renderer.hpp
new file mode 100644 (file)
index 0000000..c5682f5
--- /dev/null
@@ -0,0 +1,98 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef UNISON_VIDEO_OPENGL_RENDERER_HPP
+#define UNISON_VIDEO_OPENGL_RENDERER_HPP
+
+#include <unison/video/backend/Renderer.hpp>
+
+#include <string>
+
+#include "SDL.h"
+
+namespace Unison
+{
+   namespace Video
+   {
+      namespace Backend
+      {
+         class Texture;
+         class Window;
+      }
+      namespace OpenGL
+      {
+         /// Does rendering tasks like blits and color fills using OpenGL
+         class Renderer : public Backend::Renderer
+         {
+            public:
+               /// Default constructor
+               Renderer();
+
+               /// Destructor
+               ~Renderer();
+
+               /// Initialize the backend
+               void init();
+
+               /// Cleanup the backend
+               void quit();
+
+               /// Get the name of the renderer
+               /// \return the name of the renderer
+               std::string get_name();
+
+               /// Check if the backend is usable
+               /// \return Whether the backend is usable
+               bool is_usable();
+
+               Surface load_surface(const std::string &filename);
+               Surface load_surface(const std::string &filename, const Color &colorkey);
+               void save_surface(const Surface &surface, const std::string &filename);
+
+               /// Does a surface-to-surface blit
+               /// \param[in] src The source surface
+               /// \param[in] src_rect The part of the source surface to blit from
+               /// \param[in] dst The destination surface
+               /// \param[in] dst_pos The position to blit to
+               /// \param[in] options Extra blit options
+               void blit(const Surface &src, const Rect &src_rect, Surface &dst, const Point &dst_pos, const RenderOptions &options);
+
+               /// Does a texture-to-surface blit
+               /// \param[in] src The source texture
+               /// \param[in] src_rect The part of the source texture to blit from
+               /// \param[in] dst The destination surface
+               /// \param[in] dst_pos The position to blit to
+               /// \param[in] options Extra blit options
+               void blit(Backend::Texture *src, const Rect &src_rect, Surface &dst, const Point &dst_pos, const RenderOptions &options);
+
+               /// Fills a portion of a surface with the given color
+               /// \param[in] dst The destination surface
+               /// \param[in] color The color
+               /// \param[in] rect The portion to fill
+               void fill(Surface &dst, const Color &color, const Rect &rect);
+
+               /// Fills with alpha blend a portion of a surface with the given color
+               /// \param[in] dst The destination surface
+               /// \param[in] color The color
+               /// \param[in] rect The portion to fill
+               void fill_blend(Surface &dst, const Color &color, const Rect &rect);
+
+               /// Create a window
+               /// \param[in] size The size of the window
+               /// \param[in] logical_size The logical size of the window
+               /// \param[in] fullscreen Whether to open in fullscreen mode
+               /// \return The created window
+               Backend::Window *create_window(const Area &size, const Area &logical_size, bool fullscreen);
+
+               /// Create a texture for the given surface
+               /// \param[in] surface The surface to convert
+               /// \return The texture for the surface
+               Backend::Texture *create_texture(const Surface &surface);
+         };
+      }
+   }
+}
+
+#endif
diff --git a/src/unison/src/video/opengl/SDL_gl.c b/src/unison/src/video/opengl/SDL_gl.c
new file mode 100644 (file)
index 0000000..e147338
--- /dev/null
@@ -0,0 +1,24 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#include "SDL.h"
+#include "SDL_gl.h"
+
+#define GL_PROC(ret, func, params) ret (*func) params;
+#include "SDL_glfuncs.h"
+#undef GL_PROC
+
+int glLoad(const char *path)
+{
+   int ret = SDL_GL_LoadLibrary(path);
+   if(ret)
+   {
+      return ret;
+   }
+#define GL_PROC(ret, func, params) func = SDL_GL_GetProcAddress(#func);
+#include "SDL_glfuncs.h"
+#undef GL_PROC
+   return 0;
+}
diff --git a/src/unison/src/video/opengl/SDL_gl.h b/src/unison/src/video/opengl/SDL_gl.h
new file mode 100644 (file)
index 0000000..eac9f65
--- /dev/null
@@ -0,0 +1,67 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef _SDL_GL_H
+#define _SDL_GL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef unsigned int GLenum;
+typedef unsigned char GLboolean;
+typedef unsigned int GLbitfield;
+typedef void GLvoid;
+typedef signed char GLbyte;
+typedef short GLshort;
+typedef int GLint;
+typedef unsigned char GLubyte;
+typedef unsigned short GLushort;
+typedef unsigned int GLuint;
+typedef int GLsizei;
+typedef float GLfloat;
+typedef float GLclampf;
+typedef double GLdouble;
+typedef double GLclampd;
+
+#define GL_UNSIGNED_BYTE 0x1401
+#define GL_QUADS 0x0007
+#define GL_MODELVIEW 0x1700
+#define GL_PROJECTION 0x1701
+#define GL_FRONT 0x0404
+#define GL_BACK 0x0405
+#define GL_DEPTH_TEST 0x0B71
+#define GL_CULL_FACE 0x0B44
+#define GL_BLEND 0x0BE2
+#define GL_ZERO 0x0
+#define GL_ONE 0x1
+#define GL_SRC_COLOR 0x0300
+#define GL_SRC_ALPHA 0x0302
+#define GL_ONE_MINUS_SRC_ALPHA 0x0303
+#define GL_DST_COLOR 0x0306
+#define GL_RGB 0x1907
+#define GL_RGBA 0x1908
+#define GL_MAX_TEXTURE_SIZE 0x0D33
+#define GL_UNPACK_ALIGNMENT 0x0CF5
+#define GL_TEXTURE_2D 0x0DE1
+#define GL_TEXTURE_WRAP_S 0x2802
+#define GL_TEXTURE_WRAP_T 0x2803
+#define GL_TEXTURE_MAG_FILTER 0x2800
+#define GL_TEXTURE_MIN_FILTER 0x2801
+#define GL_CLAMP 0x2900
+#define GL_LINEAR 0x2601
+#define GL_COLOR_BUFFER_BIT 0x00004000
+
+#define GL_PROC(ret, func, params) extern ret (*func) params;
+#include "SDL_glfuncs.h"
+#undef GL_PROC
+
+int glLoad(const char *path);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/unison/src/video/opengl/SDL_glfuncs.h b/src/unison/src/video/opengl/SDL_glfuncs.h
new file mode 100644 (file)
index 0000000..2d72150
--- /dev/null
@@ -0,0 +1,38 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+GL_PROC(void, glClearColor, (GLclampf, GLclampf, GLclampf, GLclampf))
+GL_PROC(void, glClear, (GLbitfield))
+GL_PROC(void, glBlendFunc, (GLenum, GLenum))
+GL_PROC(void, glDrawBuffer, (GLenum))
+GL_PROC(void, glReadBuffer, (GLenum))
+GL_PROC(void, glEnable, (GLenum))
+GL_PROC(void, glDisable, (GLenum))
+GL_PROC(void, glGetIntegerv, (GLenum, GLint *))
+GL_PROC(GLenum, glGetError, (void))
+GL_PROC(const GLubyte *, glGetString, (GLenum))
+GL_PROC(void, glMatrixMode, (GLenum))
+GL_PROC(void, glOrtho, (GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble))
+GL_PROC(void, glViewport, (GLint, GLint, GLsizei, GLsizei))
+GL_PROC(void, glPushMatrix, (void))
+GL_PROC(void, glPopMatrix, (void))
+GL_PROC(void, glLoadIdentity, (void))
+GL_PROC(void, glRotatef, (GLfloat, GLfloat, GLfloat))
+GL_PROC(void, glScalef, (GLfloat, GLfloat, GLfloat))
+GL_PROC(void, glTranslatef, (GLfloat, GLfloat, GLfloat))
+GL_PROC(void, glBegin, (GLenum))
+GL_PROC(void, glEnd, (void))
+GL_PROC(void, glVertex2i, (GLint, GLint))
+GL_PROC(void, glColor4ub, (GLubyte, GLubyte, GLubyte, GLubyte))
+GL_PROC(void, glReadPixels, (GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoid *))
+GL_PROC(void, glTexCoord2f, (GLfloat, GLfloat))
+GL_PROC(void, glPixelStorei, (GLenum, GLint))
+GL_PROC(void, glTexParameteri, (GLenum, GLenum, GLint))
+GL_PROC(void, glTexImage2D, (GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *))
+GL_PROC(void, glTexSubImage2D, (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *))
+GL_PROC(void, glGetTexImage, (GLenum, GLint, GLenum, GLenum, GLvoid *))
+GL_PROC(void, glGenTextures, (GLsizei, GLuint *))
+GL_PROC(void, glDeleteTextures, (GLsizei, GLuint *))
+GL_PROC(void, glBindTexture, (GLsizei, GLuint))
diff --git a/src/unison/src/video/opengl/Texture.cpp b/src/unison/src/video/opengl/Texture.cpp
new file mode 100644 (file)
index 0000000..8d27796
--- /dev/null
@@ -0,0 +1,252 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#include "Texture.hpp"
+#include <unison/video/Surface.hpp>
+#include <unison/video/Window.hpp>
+#include <unison/video/Renderers.hpp>
+#include <unison/video/backend/Renderer.hpp>
+
+#include <assert.h>
+#include <algorithm>
+
+namespace
+{
+   int next_power_of_two(int val)
+   {
+      int result = 1;
+      while(result < val)
+         result *= 2;
+      return result;
+   }
+}
+
+namespace Unison
+{
+   namespace Video
+   {
+      namespace OpenGL
+      {
+         Texture::Texture(const Surface &surface) :
+            Backend::Texture(surface),
+            handles()
+         {
+         }
+
+         /*Texture::Texture(const Surface &surface, const std::string &name) :
+            Backend::Texture(surface, name),
+            handles()
+         {
+         }
+
+         Texture::Texture(Backend::Texture *texture) :
+            Backend::Texture(texture),
+            handles()
+         {
+         }*/
+
+         Texture::~Texture()
+         {
+            for(std::vector<Handle>::iterator iter = handles.begin(), end = handles.end();iter != end;++iter)
+            {
+               glDeleteTextures(1, &iter->texture);
+            }
+         }
+
+         const Surface Texture::get_surface()
+         {
+            if(surface.get_size() == Area())
+            {
+               assert(!handles.empty());
+               surface = Surface(size);
+               for(std::vector<Handle>::iterator iter = handles.begin(), end = handles.end();iter != end;++iter)
+               {
+                  Surface section(iter->rect.size);
+                  glBindTexture(GL_TEXTURE_2D, iter->texture);
+                  glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, section.get_pixels());
+                  surface.blit(section, iter->rect.pos, Rect(), BLEND_NONE);
+               }
+               assert(!glGetError());
+            }
+            return surface;
+         }
+
+         void Texture::save()
+         {
+            get_surface();
+            for(std::vector<Handle>::iterator iter = handles.begin(), end = handles.end();iter != end;++iter)
+            {
+               glDeleteTextures(1, &iter->texture);
+            }
+            handles.clear();
+         }
+
+         void Texture::blit(const Surface &src, const Point &dst_pos, const Rect &src_rect, const RenderOptions &options)
+         {
+            save();
+            Renderers::get().get_renderer().blit(src, src_rect, surface, dst_pos, options);
+         }
+
+         void Texture::blit(const Video::Texture &src, const Point &dst_pos, const Rect &src_rect, const RenderOptions &options)
+         {
+            save();
+            Texture *texture = dynamic_cast<Texture *>(Backend::Texture::get_texture(src.get_id()));
+            Renderers::get().get_renderer().blit(texture, src_rect, surface, dst_pos, options);
+         }
+
+         void Texture::fill(const Color &color, const Rect &rect)
+         {
+            save();
+            Renderers::get().get_renderer().fill(surface, color, rect);
+         }
+
+         void Texture::fill_blend(const Color &color, const Rect &rect)
+         {
+            save();
+            Renderers::get().get_renderer().fill_blend(surface, color, rect);
+         }
+
+         void Texture::blit_draw_buffer(const Rect &src_rect, const Point &dst_pos, const RenderOptions &options)
+         {
+            if(handles.empty())
+            {
+               assert(surface.get_size() != Area());
+               GLint max_size;
+               glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_size);
+               for(unsigned int y = 0;y < surface.get_size().y;y += max_size)
+               {
+                  for(unsigned int x = 0;x < surface.get_size().x;x += max_size)
+                  {
+                     Rect rect;
+                     rect.pos.x = x;
+                     rect.pos.y = y;
+                     rect.size.x = std::min(surface.get_size().x - x, (unsigned int)max_size);
+                     rect.size.y = std::min(surface.get_size().y - y, (unsigned int)max_size);
+                     handles.push_back(create_handle(surface, rect));
+                  }
+               }
+               surface = Surface();
+            }
+
+            glColor4ub(options.color.red, options.color.green, options.color.blue, options.alpha);
+            switch(options.blend)
+            {
+               case BLEND_NONE:
+                  glDisable(GL_BLEND);
+                  //glBlendFunc(GL_ONE, GL_ZERO);
+                  break;
+               case BLEND_MASK:
+                  assert(0 && "Mask blending not implemented");
+                  return;
+               case BLEND_ALPHA:
+                  glEnable(GL_BLEND);
+                  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+                  break;
+               case BLEND_ADD:
+                  glEnable(GL_BLEND);
+                  glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+                  break;
+               case BLEND_MOD:
+                  glEnable(GL_BLEND);
+                  glBlendFunc(GL_ZERO, GL_SRC_COLOR);
+                  break;
+               default:
+                  assert(0 && "Unrecognized blend mode");
+                  return;
+            }
+
+            glPushMatrix();
+
+            glTranslatef(dst_pos.x - src_rect.pos.x, dst_pos.y - src_rect.pos.y, 0);
+
+            for(std::vector<Handle>::iterator iter = handles.begin(), end = handles.end();iter != end;++iter)
+            {
+               Rect overlap = iter->rect.get_overlap(src_rect);
+               if(overlap != Rect())
+               {
+                  GLfloat uv_left = GLfloat(overlap.get_left()) / iter->rect.size.x;
+                  GLfloat uv_top = GLfloat(overlap.get_top()) / iter->rect.size.y;
+                  GLfloat uv_right = GLfloat(overlap.get_right()) / iter->rect.size.x;
+                  GLfloat uv_bottom = GLfloat(overlap.get_bottom()) / iter->rect.size.y;
+
+                  if(options.h_flip)
+                  {
+                     std::swap(uv_left, uv_right);
+                  }
+
+                  if(options.v_flip)
+                  {
+                     std::swap(uv_top, uv_bottom);
+                  }
+
+                  glPushMatrix();
+
+                  glTranslatef(overlap.pos.x, overlap.pos.y, 0);
+
+                  glBindTexture(GL_TEXTURE_2D, iter->texture);
+                  glBegin(GL_QUADS);
+                     glTexCoord2f(uv_left, uv_top);
+                     glVertex2i(0, 0);
+
+                     glTexCoord2f(uv_right, uv_top);
+                     glVertex2i(overlap.size.x, 0);
+
+                     glTexCoord2f(uv_right, uv_bottom);
+                     glVertex2i(overlap.size.x, overlap.size.y);
+
+                     glTexCoord2f(uv_left, uv_bottom);
+                     glVertex2i(0, overlap.size.y);
+                  glEnd();
+
+                  glPopMatrix();
+               }
+            }
+
+            glPopMatrix();
+
+            //glColor4ub(0xff, 0xff, 0xff, 0xff);
+            //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+         }
+
+         Texture::Handle Texture::create_handle(const Surface &surface, const Rect &rect)
+         {
+            Texture::Handle handle;
+            handle.rect = rect;
+            handle.rect.size.x = next_power_of_two(rect.size.x);
+            handle.rect.size.y = next_power_of_two(rect.size.y);
+            Surface convert(handle.rect.size);
+            convert.blit(surface, Point(), rect, BLEND_NONE);
+
+
+            glGenTextures(1, &handle.texture);
+            assert(!glGetError());
+            try
+            {
+               glBindTexture(GL_TEXTURE_2D, handle.texture);
+               //glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+               //surface.lock();
+               glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
+                     handle.rect.size.x, handle.rect.size.y,
+                     0, GL_RGBA, GL_UNSIGNED_BYTE, convert.get_pixels());
+               //surface.unlock();
+
+               assert(!glGetError());
+
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+            }
+            catch(...)
+            {
+               glDeleteTextures(1, &handle.texture);
+               throw;
+            }
+            return handle;
+         }
+      }
+   }
+}
diff --git a/src/unison/src/video/opengl/Texture.hpp b/src/unison/src/video/opengl/Texture.hpp
new file mode 100644 (file)
index 0000000..25f2090
--- /dev/null
@@ -0,0 +1,55 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef UNISON_VIDEO_OPENGL_TEXTURE_HPP
+#define UNISON_VIDEO_OPENGL_TEXTURE_HPP
+
+#include <unison/video/backend/Texture.hpp>
+#include <unison/video/Surface.hpp>
+
+#include <string>
+#include <vector>
+
+#include "SDL.h"
+#include "SDL_gl.h"
+
+namespace Unison
+{
+   namespace Video
+   {
+      namespace OpenGL
+      {
+         class Texture : public Backend::Texture
+         {
+            public:
+               Texture(const Surface &surface);
+               //Texture(const Surface &surface, const std::string &name);
+               //Texture(Backend::Texture *texture);
+               Texture();
+               ~Texture();
+
+               const Surface get_surface();
+               void save();
+               void blit(const Surface &src, const Point &dst_pos, const Rect &src_rect, const RenderOptions &options);
+               void blit(const Video::Texture &src, const Point &dst_pos, const Rect &src_rect, const RenderOptions &options);
+               void fill(const Color &color, const Rect &rect);
+               void fill_blend(const Color &color, const Rect &rect);
+
+               void blit_draw_buffer(const Rect &src_rect, const Point &dst_pos, const RenderOptions &options);
+            private:
+               struct Handle
+               {
+                  GLuint texture;
+                  Rect rect;
+               };
+               std::vector<Handle> handles;
+
+               static Handle create_handle(const Surface &surface, const Rect &rect);
+         };
+      }
+   }
+}
+
+#endif
diff --git a/src/unison/src/video/opengl/Window.cpp b/src/unison/src/video/opengl/Window.cpp
new file mode 100644 (file)
index 0000000..924edb7
--- /dev/null
@@ -0,0 +1,191 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#include "Window.hpp"
+#include "Texture.hpp"
+#include <unison/video/Window.hpp>
+#include <unison/video/Surface.hpp>
+#include <unison/video/Texture.hpp>
+#include <unison/video/Renderers.hpp>
+#include <unison/video/sdl/Blitters.hpp>
+#include <unison/video/backend/Renderer.hpp>
+#include <unison/video/backend/Texture.hpp>
+
+#include <assert.h>
+
+#include "SDL.h"
+
+namespace Unison
+{
+   namespace Video
+   {
+      namespace OpenGL
+      {
+         Window::Window(const Area &size, const Area &logical_size, bool fullscreen) :
+            logical_size(logical_size),
+            window(0)
+         {
+            assert(size.x);
+            assert(size.y);
+
+            SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+            //SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
+            SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
+            SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
+            SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
+            SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
+
+            window = SDL_SetVideoMode(size.x, size.y, 0, SDL_OPENGL | (fullscreen ? SDL_FULLSCREEN : 0));
+            assert(window);
+
+            glDisable(GL_DEPTH_TEST);
+            glDisable(GL_CULL_FACE);
+            glEnable(GL_TEXTURE_2D);
+            //glEnable(GL_BLEND);
+
+            glMatrixMode(GL_PROJECTION);
+            glLoadIdentity();
+            glOrtho(0, logical_size.x, logical_size.y, 0, -1.0, 1.0);
+            glMatrixMode(GL_MODELVIEW);
+            glViewport(0, 0, size.x, size.y);
+            glLoadIdentity();
+            //glTranslatef(0, 0, 0);
+            //glScalef(GLfloat(size.x) / logical_size.x, GLfloat(size.y) / logical_size.y, 1);
+            //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+            glClearColor(0, 0, 0, 1);
+            glClear(GL_COLOR_BUFFER_BIT);
+            assert(!glGetError());
+         }
+
+         Window::~Window()
+         {
+         }
+
+         void Window::take_screenshot(const std::string &filename) const
+         {
+            //Surface surface(logical_size);
+            Surface surface(get_size());
+            glReadBuffer(GL_FRONT);
+            glReadPixels(0, 0, get_size().x, get_size().y, GL_RGBA, GL_UNSIGNED_BYTE, surface.get_pixels());
+            //glReadPixels(0, 0, logical_size.x, logical_size.y, GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels);
+            surface.v_flip().save(filename);
+         }
+
+         void Window::flip()
+         {
+            SDL_GL_SwapBuffers();
+         }
+
+         void Window::set_title(const std::string &title)
+         {
+            SDL_WM_SetCaption(title.c_str(), title.c_str());
+         }
+
+         void Window::set_icon(const Surface &icon)
+         {
+            SDL_Surface *icon_surface = SDL::Blitters::create_sdl_surface_from(icon);
+            assert(icon_surface);
+            SDL_WM_SetIcon(icon_surface, 0);
+            SDL_FreeSurface(icon_surface);
+         }
+
+         Area Window::get_size() const
+         {
+            return Area(window->w, window->h);
+         }
+
+         bool Window::is_fullscreen() const
+         {
+            return window->flags & SDL_FULLSCREEN;
+         }
+
+         void Window::blit(const Surface &src, const Point &dst_pos, const Rect &src_rect, const RenderOptions &options)
+         {
+            Video::Texture texture(src);
+            blit(src, dst_pos, src_rect, options);
+         }
+
+         void Window::blit(const Video::Texture &src, const Point &dst_pos, const Rect &src_rect, const RenderOptions &options)
+         {
+            Texture *texture = dynamic_cast<Texture *>(Backend::Texture::get_texture(src.get_id()));
+            assert(texture);
+            assert(window);
+
+            texture->blit_draw_buffer(src_rect, dst_pos, options);
+         }
+
+         void Window::fill(const Color &color, const Rect &rect)
+         {
+            assert(window);
+
+            glDisable(GL_BLEND);
+            glDisable(GL_TEXTURE_2D);
+            glColor4ub(color.red, color.green, color.blue, color.alpha);
+            if(rect == Rect())
+            {
+               glBegin(GL_QUADS);
+                  glVertex2i(0, 0);
+                  glVertex2i(get_size().x, 0);
+                  glVertex2i(get_size().x, get_size().y);
+                  glVertex2i(0, get_size().y);
+               glEnd();
+            }
+            else
+            {
+               glPushMatrix();
+
+               glTranslatef(rect.pos.x, rect.pos.y, 0);
+
+               glBegin(GL_QUADS);
+                  glVertex2i(0, 0);
+                  glVertex2i(rect.size.x, 0);
+                  glVertex2i(rect.size.x, rect.size.y);
+                  glVertex2i(0, rect.size.y);
+               glEnd();
+
+               glPopMatrix();
+            }
+            glEnable(GL_TEXTURE_2D);
+            //glColor4ub(0xff, 0xff, 0xff, 0xff);
+         }
+
+         void Window::fill_blend(const Color &color, const Rect &rect)
+         {
+            assert(window);
+
+            glEnable(GL_BLEND);
+            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+            glDisable(GL_TEXTURE_2D);
+            glColor4ub(color.red, color.green, color.blue, color.alpha);
+            if(rect == Rect())
+            {
+               glBegin(GL_QUADS);
+                  glVertex2i(0, 0);
+                  glVertex2i(get_size().x, 0);
+                  glVertex2i(get_size().x, get_size().y);
+                  glVertex2i(0, get_size().y);
+               glEnd();
+            }
+            else
+            {
+               glPushMatrix();
+
+               glTranslatef(rect.pos.x, rect.pos.y, 0);
+
+               glBegin(GL_QUADS);
+                  glVertex2i(0, 0);
+                  glVertex2i(rect.size.x, 0);
+                  glVertex2i(rect.size.x, rect.size.y);
+                  glVertex2i(0, rect.size.y);
+               glEnd();
+
+               glPopMatrix();
+            }
+            glEnable(GL_TEXTURE_2D);
+            //glColor4ub(0xff, 0xff, 0xff, 0xff);
+         }
+      }
+   }
+}
diff --git a/src/unison/src/video/opengl/Window.hpp b/src/unison/src/video/opengl/Window.hpp
new file mode 100644 (file)
index 0000000..cdd37a6
--- /dev/null
@@ -0,0 +1,53 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef UNISON_VIDEO_OPENGL_WINDOW_HPP
+#define UNISON_VIDEO_OPENGL_WINDOW_HPP
+
+#include <unison/video/backend/Window.hpp>
+#include <unison/video/RenderOptions.hpp>
+
+#include <string>
+
+#include "SDL.h"
+
+namespace Unison
+{
+   namespace Video
+   {
+      namespace Backend
+      {
+         class Texture;
+      }
+      namespace OpenGL
+      {
+         class Window : public Backend::Window
+         {
+            public:
+               Window(const Area &size, const Area &logical_size, bool fullscreen = false);
+
+               ~Window();
+               void take_screenshot(const std::string &filename) const;
+               void flip();
+               void set_title(const std::string &title);
+               void set_icon(const Surface &icon);
+               Area get_size() const;
+               bool is_fullscreen() const;
+               void blit(const Surface &src, const Point &dst_pos, const Rect &src_rect, const RenderOptions &options);
+               void blit(const Video::Texture &src, const Point &dst_pos, const Rect &src_rect, const RenderOptions &options);
+               void fill(const Color &color, const Rect &rect);
+               void fill_blend(const Color &color, const Rect &rect);
+            private:
+               /// The logical size of the window;
+               Area logical_size;
+
+               /// The window
+               SDL_Surface *window;
+         };
+      }
+   }
+}
+
+#endif
diff --git a/src/unison/src/video/sdl/Blitters.cpp b/src/unison/src/video/sdl/Blitters.cpp
new file mode 100644 (file)
index 0000000..554fd6c
--- /dev/null
@@ -0,0 +1,607 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#include <unison/video/sdl/Blitters.hpp>
+#include <unison/video/Surface.hpp>
+
+#include <assert.h>
+
+#include "SDL.h"
+
+namespace
+{
+   unsigned char add_saturate(unsigned char lhs, int rhs)
+   {
+      if(lhs + rhs < 0x00)
+      {
+         return 0x00;
+      }
+      if(lhs + rhs > 0xff)
+      {
+         return 0xff;
+      }
+      return lhs + rhs;
+   }
+}
+
+
+namespace Unison
+{
+   namespace Video
+   {
+      namespace SDL
+      {
+         /*SDL_Surface *Blitters::optimize(const Surface &src)
+         {
+            bool colors[(1 << 12)];
+            memset(colors, 0, (1 << 12) * sizeof(bool));
+
+            Surface dst(src);
+            Color *iter = dst.get_pixels();
+            for(unsigned int y = 0;y < dst.get_size().y;y++)
+            {
+               for(unsigned int x = 0;x < dst.get_size().x;x++, iter++)
+               {
+                  unsigned char oldalpha = iter->alpha;
+                  unsigned char newalpha = oldalpha & 0x80 ? 0xff : 0x00;
+                  iter->alpha = newalpha;
+                  int error = oldalpha - newalpha;
+                  if(x != dst.get_size().x - 1)
+                  {
+                     (iter + 1)->alpha = add_saturate((iter + 1)->alpha, error * 7 / 16);
+                  }
+                  if(y != dst.get_size().y - 1)
+                  {
+                     if(x != 0)
+                     {
+                        (iter + dst.get_size().x - 1)->alpha = add_saturate((iter + dst.get_size().x - 1)->alpha, error * 3 / 16);
+                     }
+                     (iter + dst.get_size().x)->alpha = add_saturate((iter + dst.get_size().x)->alpha, error * 5 / 16);
+                     if(x != dst.get_size().x - 1)
+                     {
+                        (iter + dst.get_size().x + 1)->alpha = add_saturate((iter + dst.get_size().x + 1)->alpha, error * 1 / 16);
+                     }
+                  }
+                  if(newalpha != 0)
+                  {
+                     colors[((iter->red & 0xf0) << 4) | (iter->green & 0xf0) | ((iter->blue & 0xf0) >> 4)] = true;
+                  }
+               }
+            }
+
+            int keycolor = -1;
+            for(int i = 0;i < (1 << 12);i++)
+            {
+               if(!colors[i])
+               {
+                  keycolor = i;
+                  break;
+               }
+            }
+            if(keycolor == -1)
+            {
+               SDL_Surface *converted = create_sdl_surface_from(src);
+               SDL_Surface *optimized = SDL_DisplayFormatAlpha(converted);
+               SDL_FreeSurface(converted);
+               return optimized;
+            }
+
+            Color key(((keycolor & 0xf00) >> 4) | 0xf, (keycolor & 0x0f0) | 0xf, ((keycolor & 0x00f) << 4) | 0xf);
+
+            Color *end = dst.get_pixels() + dst.get_size().x * dst.get_size().y;
+            for(iter = dst.get_pixels();iter != end;++iter)
+            {
+               if(iter->alpha == 0x00)
+               {
+                  *iter = key;
+               }
+            }
+
+            SDL_Surface *converted = create_sdl_surface_from(dst);
+            SDL_SetColorKey(converted, SDL_SRCCOLORKEY | SDL_RLEACCEL, SDL_MapRGB(converted->format, key.red, key.green, key.blue));
+            SDL_Surface *optimized = SDL_DisplayFormat(converted);
+            SDL_FreeSurface(converted);
+            return optimized;
+         }*/
+         SDL_Surface *Blitters::optimize(const Surface &src)
+         {
+            unsigned int transparent = 0;
+            unsigned int opaque = 0;
+            unsigned int semitransparent = 0;
+            unsigned int alphasum = 0;
+            unsigned int squaredalphasum = 0;
+            bool colors[(1 << 12)];
+            memset(colors, 0, (1 << 12) * sizeof(bool));
+
+            const Color *src_end = src.get_pixels() + src.get_size().x * src.get_size().y;
+            for(const Color *iter = src.get_pixels();iter != src_end;++iter)
+            {
+               if(iter->alpha < 16)
+               {
+                  transparent++;
+               }
+               else if(iter->alpha > 240)
+               {
+                  opaque++;
+                  alphasum += iter->alpha;
+                  squaredalphasum += iter->alpha * iter->alpha;
+               }
+               else
+               {
+                  semitransparent++;
+                  squaredalphasum += iter->alpha * iter->alpha;
+               }
+               if(iter->alpha != 0)
+               {
+                  colors[((iter->red & 0xf0) << 4) | (iter->green & 0xf0) | ((iter->blue & 0xf0) >> 4)] = true;
+               }
+            }
+
+            unsigned int avgalpha = (opaque + semitransparent) ? alphasum / (opaque + semitransparent) : 0;
+            unsigned int avgsquaredalpha = (opaque + semitransparent) ? squaredalphasum / (opaque + semitransparent) : 0;
+            unsigned int alphavariance = avgsquaredalpha - avgalpha * avgalpha;
+            if(semitransparent > ((transparent + opaque + semitransparent) / 8) && alphavariance > 16)
+            {
+               SDL_Surface *converted = create_sdl_surface_from(src);
+               SDL_Surface *optimized = SDL_DisplayFormatAlpha(converted);
+               SDL_FreeSurface(converted);
+               return optimized;
+            }
+
+            int keycolor = -1;
+            for(int i = 0;i < (1 << 12);i++)
+            {
+               if(!colors[i])
+               {
+                  keycolor = i;
+                  break;
+               }
+            }
+            if(keycolor == -1)
+            {
+               SDL_Surface *converted = create_sdl_surface_from(src);
+               SDL_Surface *optimized = SDL_DisplayFormatAlpha(converted);
+               SDL_FreeSurface(converted);
+               return optimized;
+            }
+
+            Color key(((keycolor & 0xf00) >> 4) | 0xf, (keycolor & 0x0f0) | 0xf, ((keycolor & 0x00f) << 4) | 0xf);
+            Surface dst(src.get_size());
+            Color *dst_end = dst.get_pixels() + dst.get_size().x * dst.get_size().y;
+            const Color *src_iter = src.get_pixels();
+            Color *dst_iter = dst.get_pixels();
+            for(;dst_iter != dst_end;++dst_iter, ++src_iter)
+            {
+               *dst_iter = (src_iter->alpha < avgalpha / 4) ? key : *src_iter;
+            }
+
+            SDL_Surface *converted = create_sdl_surface_from(dst);
+            if(avgalpha < 240)
+            {
+               SDL_SetAlpha(converted, SDL_SRCALPHA | SDL_RLEACCEL, avgalpha);
+            }
+            SDL_SetColorKey(converted, SDL_SRCCOLORKEY | SDL_RLEACCEL, SDL_MapRGB(converted->format, key.red, key.green, key.blue));
+            SDL_Surface *optimized = SDL_DisplayFormat(converted);
+            SDL_FreeSurface(converted);
+            return optimized;
+         }
+
+         void Blitters::blit_upper(SDL_Surface *src, Rect src_rect, SDL_Surface *dst, Point dst_pos, void (*blit_lower)(SDL_Surface *, const Rect &, SDL_Surface *, const Point &))
+         {
+            assert(src);
+            assert(dst);
+            assert(blit_lower);
+            if(src_rect == Rect())
+            {
+               src_rect.size.x = src->w;
+               src_rect.size.y = src->h;
+            }
+            if(dst_pos.x < 0)
+            {
+               if(src_rect.size.x < (unsigned int) -dst_pos.x)
+               {
+                  return;
+               }
+               src_rect.pos.x += -dst_pos.x;
+               src_rect.size.x += dst_pos.x;
+               dst_pos.x = 0;
+            }
+            if(dst_pos.y < 0)
+            {
+               if(src_rect.size.y < (unsigned int) -dst_pos.y)
+               {
+                  return;
+               }
+               src_rect.pos.y += -dst_pos.y;
+               src_rect.size.y += dst_pos.y;
+               dst_pos.y = 0;
+            }
+            if(src_rect.pos.x < 0)
+            {
+               if(src_rect.size.x < (unsigned int) -src_rect.pos.x)
+               {
+                  return;
+               }
+               src_rect.size.x += src_rect.pos.x;
+               src_rect.pos.x = 0;
+            }
+            if(src_rect.pos.y < 0)
+            {
+               if(src_rect.size.y < (unsigned int) -src_rect.pos.y)
+               {
+                  return;
+               }
+               src_rect.size.y += src_rect.pos.y;
+               src_rect.pos.y = 0;
+            }
+            if(src_rect.get_right() > src->w)
+            {
+               src_rect.size.x = src->w - src_rect.pos.x;
+            }
+            if(src_rect.get_bottom() > src->h)
+            {
+               src_rect.size.y = src->h - src_rect.pos.y;
+            }
+            if(int(dst_pos.x + src_rect.size.x) > dst->w)
+            {
+               src_rect.size.x = dst->w - dst_pos.x;
+            }
+            if(int(dst_pos.y + src_rect.size.y) > dst->h)
+            {
+               src_rect.size.y = dst->h - dst_pos.y;
+            }
+            blit_lower(src, src_rect, dst, dst_pos);
+         }
+
+         void Blitters::blit_lower_none(SDL_Surface *src, const Rect &src_rect, SDL_Surface *dst, const Point &dst_pos)
+         {
+            SDL_Rect sdl_src_rect = {src_rect.pos.x, src_rect.pos.y, src_rect.size.x, src_rect.size.y};
+            SDL_Rect sdl_dst_rect = {dst_pos.x, dst_pos.y, 0, 0};
+
+            Uint8 alpha = src->format->alpha;
+            SDL_SetAlpha(src, 0, 0);
+            SDL_BlitSurface(src, &sdl_src_rect, dst, &sdl_dst_rect);
+            SDL_SetAlpha(src, SDL_SRCALPHA | SDL_RLEACCEL, alpha);
+         }
+
+         void Blitters::blit_lower_mask(SDL_Surface *src, const Rect &src_rect, SDL_Surface *dst, const Point &dst_pos)
+         {
+            if(SDL_MUSTLOCK(src))
+            {
+               SDL_LockSurface(src);
+            }
+            if(SDL_MUSTLOCK(dst))
+            {
+               SDL_LockSurface(dst);
+            }
+            int src_bpp = src->format->BytesPerPixel;
+            int dst_bpp = dst->format->BytesPerPixel;
+            Uint8 *src_pixel = (Uint8 *)src->pixels + src_rect.pos.y * src->pitch + src_rect.pos.x * src_bpp;
+            Uint8 *dst_pixel = (Uint8 *)dst->pixels + dst_pos.y * dst->pitch + dst_pos.x * dst_bpp;
+            for(unsigned int y = 0;y < src_rect.size.y;y++)
+            {
+               for(unsigned int x = 0;x < src_rect.size.x;x++)
+               {
+                  Uint32 src_mapped = 0;
+                  switch(src_bpp) {
+                     case 1:
+                        src_mapped = *src_pixel;
+                        break;
+                     case 2:
+                        src_mapped = *(Uint16 *)src_pixel;
+                        break;
+                     case 3:
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+                        src_mapped |= src_pixel[0] << 16;
+                        src_mapped |= src_pixel[1] << 8;
+                        src_mapped |= src_pixel[2] << 0;
+#else
+                        src_mapped |= src_pixel[0] << 0;
+                        src_mapped |= src_pixel[1] << 8;
+                        src_mapped |= src_pixel[2] << 16;
+#endif
+                        break;
+                     case 4:
+                        src_mapped = *(Uint32 *)src_pixel;
+                        break;
+                  }
+                  Uint8 src_red, src_green, src_blue, src_alpha;
+                  SDL_GetRGBA(src_mapped, src->format, &src_red, &src_green, &src_blue, &src_alpha);
+                  if(src_alpha)
+                  {
+                     Uint32 blend_mapped = SDL_MapRGBA(dst->format, src_red, src_green, src_blue, src_alpha);
+                     switch(dst_bpp) {
+                        case 1:
+                           *dst_pixel = blend_mapped;
+                           break;
+                        case 2:
+                           *(Uint16 *)dst_pixel = blend_mapped;
+                           break;
+                        case 3:
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+                           dst_pixel[0] = (blend_mapped >> 16) & 0xff;
+                           dst_pixel[1] = (blend_mapped >> 8) & 0xff;
+                           dst_pixel[2] = (blend_mapped >> 0) & 0xff;
+#else
+                           dst_pixel[0] = (blend_mapped >> 0) & 0xff;
+                           dst_pixel[1] = (blend_mapped >> 8) & 0xff;
+                           dst_pixel[2] = (blend_mapped >> 16) & 0xff;
+#endif
+                           break;
+                        case 4:
+                           *(Uint32 *)dst_pixel = blend_mapped;
+                           break;
+                     }
+                  }
+                  src_pixel += src_bpp;
+                  dst_pixel += dst_bpp;
+               }
+               src_pixel += src->pitch - src_rect.size.x * src_bpp;
+               dst_pixel += dst->pitch - src_rect.size.x * dst_bpp;
+            }
+            if(SDL_MUSTLOCK(dst))
+            {
+               SDL_UnlockSurface(dst);
+            }
+            if(SDL_MUSTLOCK(src))
+            {
+               SDL_UnlockSurface(src);
+            }
+         }
+
+         void Blitters::blit_lower_alpha(SDL_Surface *src, const Rect &src_rect, SDL_Surface *dst, const Point &dst_pos)
+         {
+            SDL_Rect sdl_src_rect = {src_rect.pos.x, src_rect.pos.y, src_rect.size.x, src_rect.size.y};
+            SDL_Rect sdl_dst_rect = {dst_pos.x, dst_pos.y, 0, 0};
+
+            SDL_BlitSurface(src, &sdl_src_rect, dst, &sdl_dst_rect);
+         }
+
+         void Blitters::blit_lower_add(SDL_Surface *src, const Rect &src_rect, SDL_Surface *dst, const Point &dst_pos)
+         {
+            if(SDL_MUSTLOCK(src))
+            {
+               SDL_LockSurface(src);
+            }
+            if(SDL_MUSTLOCK(dst))
+            {
+               SDL_LockSurface(dst);
+            }
+            int src_bpp = src->format->BytesPerPixel;
+            int dst_bpp = dst->format->BytesPerPixel;
+            Uint8 *src_pixel = (Uint8 *)src->pixels + src_rect.pos.y * src->pitch + src_rect.pos.x * src_bpp;
+            Uint8 *dst_pixel = (Uint8 *)dst->pixels + dst_pos.y * dst->pitch + dst_pos.x * dst_bpp;
+            for(unsigned int y = 0;y < src_rect.size.y;y++)
+            {
+               for(unsigned int x = 0;x < src_rect.size.x;x++)
+               {
+                  Uint32 src_mapped = 0;
+                  switch(src_bpp) {
+                     case 1:
+                        src_mapped = *src_pixel;
+                        break;
+                     case 2:
+                        src_mapped = *(Uint16 *)src_pixel;
+                        break;
+                     case 3:
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+                        src_mapped |= src_pixel[0] << 16;
+                        src_mapped |= src_pixel[1] << 8;
+                        src_mapped |= src_pixel[2] << 0;
+#else
+                        src_mapped |= src_pixel[0] << 0;
+                        src_mapped |= src_pixel[1] << 8;
+                        src_mapped |= src_pixel[2] << 16;
+#endif
+                        break;
+                     case 4:
+                        src_mapped = *(Uint32 *)src_pixel;
+                        break;
+                  }
+                  Uint8 src_red, src_green, src_blue, src_alpha;
+                  SDL_GetRGBA(src_mapped, src->format, &src_red, &src_green, &src_blue, &src_alpha);
+                  Uint32 dst_mapped = 0;
+                  switch(dst_bpp) {
+                     case 1:
+                        dst_mapped = *dst_pixel;
+                        break;
+                     case 2:
+                        dst_mapped = *(Uint16 *)dst_pixel;
+                        break;
+                     case 3:
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+                        dst_mapped |= dst_pixel[0] << 16;
+                        dst_mapped |= dst_pixel[1] << 8;
+                        dst_mapped |= dst_pixel[2] << 0;
+#else
+                        dst_mapped |= dst_pixel[0] << 0;
+                        dst_mapped |= dst_pixel[1] << 8;
+                        dst_mapped |= dst_pixel[2] << 16;
+#endif
+                        break;
+                     case 4:
+                        dst_mapped = *(Uint32 *)dst_pixel;
+                        break;
+                  }
+                  Uint8 dst_red, dst_green, dst_blue, dst_alpha;
+                  SDL_GetRGBA(dst_mapped, dst->format, &dst_red, &dst_green, &dst_blue, &dst_alpha);
+                  Uint8 blend_red = src_red, blend_green = src_green, blend_blue = src_blue, blend_alpha = src_alpha;
+                  if(src_red != 0 && dst_red != 0xff)
+                  {
+                     int redsum = dst_red + src_red * src_alpha / 0xff;
+                     blend_red = redsum & ~0xff ? 0xff : redsum;
+                  }
+                  else
+                  {
+                  }
+                  if(src_green != 0 && dst_green != 0xff)
+                  {
+                     int greensum = dst_green + src_green * src_alpha / 0xff;
+                     blend_green = greensum & ~0xff ? 0xff : greensum;
+                  }
+                  if(src_blue != 0 && dst_blue != 0xff)
+                  {
+                     int bluesum = dst_blue + src_blue * src_alpha / 0xff;
+                     blend_blue = bluesum & ~0xff ? 0xff : bluesum;
+                  }
+                  if(src_red != blend_red || src_green != blend_green || src_blue != blend_blue || src_alpha != blend_alpha)
+                  {
+                     Uint32 blend_mapped = SDL_MapRGBA(dst->format, blend_red, blend_green, blend_blue, blend_alpha);
+                     switch(dst_bpp) {
+                        case 1:
+                           *dst_pixel = blend_mapped;
+                           break;
+                        case 2:
+                           *(Uint16 *)dst_pixel = blend_mapped;
+                           break;
+                        case 3:
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+                           dst_pixel[0] = (blend_mapped >> 16) & 0xff;
+                           dst_pixel[1] = (blend_mapped >> 8) & 0xff;
+                           dst_pixel[2] = (blend_mapped >> 0) & 0xff;
+#else
+                           dst_pixel[0] = (blend_mapped >> 0) & 0xff;
+                           dst_pixel[1] = (blend_mapped >> 8) & 0xff;
+                           dst_pixel[2] = (blend_mapped >> 16) & 0xff;
+#endif
+                           break;
+                        case 4:
+                           *(Uint32 *)dst_pixel = blend_mapped;
+                           break;
+                     }
+                  }
+                  src_pixel += src_bpp;
+                  dst_pixel += dst_bpp;
+               }
+               src_pixel += src->pitch - src_rect.size.x * src_bpp;
+               dst_pixel += dst->pitch - src_rect.size.x * dst_bpp;
+            }
+            if(SDL_MUSTLOCK(dst))
+            {
+               SDL_UnlockSurface(dst);
+            }
+            if(SDL_MUSTLOCK(src))
+            {
+               SDL_UnlockSurface(src);
+            }
+         }
+
+         void Blitters::blit_lower_mod(SDL_Surface *src, const Rect &src_rect, SDL_Surface *dst, const Point &dst_pos)
+         {
+            if(SDL_MUSTLOCK(src))
+            {
+               SDL_LockSurface(src);
+            }
+            if(SDL_MUSTLOCK(dst))
+            {
+               SDL_LockSurface(dst);
+            }
+            int src_bpp = src->format->BytesPerPixel;
+            int dst_bpp = dst->format->BytesPerPixel;
+            Uint8 *src_pixel = (Uint8 *)src->pixels + src_rect.pos.y * src->pitch + src_rect.pos.x * src_bpp;
+            Uint8 *dst_pixel = (Uint8 *)dst->pixels + dst_pos.y * dst->pitch + dst_pos.x * dst_bpp;
+            for(unsigned int y = 0;y < src_rect.size.y;y++)
+            {
+               for(unsigned int x = 0;x < src_rect.size.x;x++)
+               {
+                  Uint32 src_mapped = 0;
+                  switch(src_bpp) {
+                     case 1:
+                        src_mapped = *src_pixel;
+                        break;
+                     case 2:
+                        src_mapped = *(Uint16 *)src_pixel;
+                        break;
+                     case 3:
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+                        src_mapped |= src_pixel[0] << 16;
+                        src_mapped |= src_pixel[1] << 8;
+                        src_mapped |= src_pixel[2] << 0;
+#else
+                        src_mapped |= src_pixel[0] << 0;
+                        src_mapped |= src_pixel[1] << 8;
+                        src_mapped |= src_pixel[2] << 16;
+#endif
+                        break;
+                     case 4:
+                        src_mapped = *(Uint32 *)src_pixel;
+                        break;
+                  }
+                  Uint8 src_red, src_green, src_blue, src_alpha;
+                  SDL_GetRGBA(src_mapped, src->format, &src_red, &src_green, &src_blue, &src_alpha);
+                  Uint32 dst_mapped = 0;
+                  switch(dst_bpp) {
+                     case 1:
+                        dst_mapped = *dst_pixel;
+                        break;
+                     case 2:
+                        dst_mapped = *(Uint16 *)dst_pixel;
+                        break;
+                     case 3:
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+                        dst_mapped |= dst_pixel[0] << 16;
+                        dst_mapped |= dst_pixel[1] << 8;
+                        dst_mapped |= dst_pixel[2] << 0;
+#else
+                        dst_mapped |= dst_pixel[0] << 0;
+                        dst_mapped |= dst_pixel[1] << 8;
+                        dst_mapped |= dst_pixel[2] << 16;
+#endif
+                        break;
+                     case 4:
+                        dst_mapped = *(Uint32 *)dst_pixel;
+                        break;
+                  }
+                  Uint8 dst_red, dst_green, dst_blue, dst_alpha;
+                  SDL_GetRGBA(dst_mapped, dst->format, &dst_red, &dst_green, &dst_blue, &dst_alpha);
+                  Uint8 blend_red, blend_green, blend_blue, blend_alpha;
+                  blend_red = dst_red * src_red / 0xff;
+                  blend_green = dst_green * src_green / 0xff;
+                  blend_blue = dst_blue * src_blue / 0xff;
+                  blend_alpha = dst_alpha * src_alpha / 0xff;
+                  if(src_red != blend_red || src_green != blend_green || src_blue != blend_blue || src_alpha != blend_alpha)
+                  {
+                     Uint32 blend_mapped = SDL_MapRGBA(dst->format, blend_red, blend_green, blend_blue, blend_alpha);
+                     switch(dst_bpp) {
+                        case 1:
+                           *dst_pixel = blend_mapped;
+                           break;
+                        case 2:
+                           *(Uint16 *)dst_pixel = blend_mapped;
+                           break;
+                        case 3:
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+                           dst_pixel[0] = (blend_mapped >> 16) & 0xff;
+                           dst_pixel[1] = (blend_mapped >> 8) & 0xff;
+                           dst_pixel[2] = (blend_mapped >> 0) & 0xff;
+#else
+                           dst_pixel[0] = (blend_mapped >> 0) & 0xff;
+                           dst_pixel[1] = (blend_mapped >> 8) & 0xff;
+                           dst_pixel[2] = (blend_mapped >> 16) & 0xff;
+#endif
+                           break;
+                        case 4:
+                           *(Uint32 *)dst_pixel = blend_mapped;
+                           break;
+                     }
+                  }
+                  src_pixel += src_bpp;
+                  dst_pixel += dst_bpp;
+               }
+               src_pixel += src->pitch - src_rect.size.x * src_bpp;
+               dst_pixel += dst->pitch - src_rect.size.x * dst_bpp;
+            }
+            if(SDL_MUSTLOCK(dst))
+            {
+               SDL_UnlockSurface(dst);
+            }
+            if(SDL_MUSTLOCK(src))
+            {
+               SDL_UnlockSurface(src);
+            }
+         }
+      }
+   }
+}
diff --git a/src/unison/src/video/sdl/Renderer.cpp b/src/unison/src/video/sdl/Renderer.cpp
new file mode 100644 (file)
index 0000000..cbf94ab
--- /dev/null
@@ -0,0 +1,183 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#include "Renderer.hpp"
+#include "Texture.hpp"
+#include "Window.hpp"
+#include <unison/video/Surface.hpp>
+#include <unison/video/Window.hpp>
+#include <unison/video/sdl/Blitters.hpp>
+#include <unison/video/backend/Texture.hpp>
+#include <unison/vfs/sdl/Utils.hpp>
+
+#include <assert.h>
+
+#include "SDL.h"
+#include "SDL_image.h"
+
+namespace Unison
+{
+   namespace Video
+   {
+      namespace SDL
+      {
+         Renderer::Renderer()
+         {
+         }
+
+         Renderer::~Renderer()
+         {
+         }
+
+         void Renderer::init()
+         {
+            SDL_InitSubSystem(SDL_INIT_VIDEO);
+         }
+
+         void Renderer::quit()
+         {
+            SDL_QuitSubSystem(SDL_INIT_VIDEO);
+         }
+
+         std::string Renderer::get_name()
+         {
+            return "sdl";
+         }
+
+         bool Renderer::is_usable()
+         {
+            SDL_InitSubSystem(SDL_INIT_VIDEO);
+
+            if(!SDL_ListModes(0, SDL_SWSURFACE))
+            {
+               SDL_QuitSubSystem(SDL_INIT_VIDEO);
+               return false;
+            }
+
+            /*const SDL_VideoInfo *info = SDL_GetVideoInfo();
+            if(SDL_VideoModeOK(info->current_w, info->current_h, 0, SDL_SWSURFACE | SDL_FULLSCREEN))
+            {
+               SDL_QuitSubSystem(SDL_INIT_VIDEO);
+               return false;
+            }*/
+
+            SDL_QuitSubSystem(SDL_INIT_VIDEO);
+
+            return true;
+         }
+
+         Surface Renderer::load_surface(const std::string &filename)
+         {
+            SDL_Surface *image = IMG_Load_RW(VFS::SDL::Utils::open_physfs_in(filename), 1);
+            assert(image);
+            Surface surface = Surface(Area(image->w, image->h));
+            SDL_Surface *sdl_surface = SDL::Blitters::create_sdl_surface_from(surface);
+            assert(sdl_surface);
+            SDL::Blitters::blit_blend_none(image, Rect(), sdl_surface, Point());
+            SDL_FreeSurface(sdl_surface);
+            return surface;
+         }
+
+         Surface Renderer::load_surface(const std::string &filename, const Color &colorkey)
+         {
+            SDL_Surface *image = IMG_Load_RW(VFS::SDL::Utils::open_physfs_in(filename), 1);
+            assert(image);
+            Surface surface = Surface(Area(image->w, image->h));
+            SDL_Surface *sdl_surface = SDL::Blitters::create_sdl_surface_from(surface);
+            assert(sdl_surface);
+            SDL_SetColorKey(image, SDL_SRCCOLORKEY, SDL_MapRGB(image->format, colorkey.red, colorkey.blue, colorkey.alpha));
+            SDL::Blitters::blit_blend_none(image, Rect(), sdl_surface, Point());
+            SDL_FreeSurface(sdl_surface);
+            return surface;
+         }
+
+         void Renderer::save_surface(const Surface &surface, const std::string &filename)
+         {
+            SDL_Surface *sdl_surface = SDL::Blitters::create_sdl_surface_from(surface);
+            assert(sdl_surface);
+            SDL_SaveBMP(sdl_surface, filename.c_str());
+            SDL_FreeSurface(sdl_surface);
+         }
+
+         void Renderer::blit(const Surface &src, const Rect &src_rect, Surface &dst, const Point &dst_pos, const RenderOptions &options)
+         {
+            Surface fragment;
+            if(src_rect.pos == Point() && (src_rect.size == Area() || src_rect.size == src.get_size()))
+            {
+               fragment = src;
+            }
+            else
+            {
+               fragment = Surface(src_rect.size);
+               Video::Blitters::blit_blend_none(src, src_rect, fragment, Point());
+            }
+            if(options.h_flip)
+            {
+               fragment = fragment.h_flip();
+            }
+            if(options.v_flip)
+            {
+               fragment = fragment.v_flip();
+            }
+            SDL_Surface *src_surface = Blitters::create_sdl_surface_from(fragment.modulate(options.color).modulate(options.alpha));
+            assert(src_surface);
+
+            SDL_Surface *dst_surface = Blitters::create_sdl_surface_from(dst);
+            assert(dst_surface);
+
+
+            Blitters::blit_blend(src_surface, Rect(Point(), fragment.get_size()), dst_surface, dst_pos, options.blend);
+
+            SDL_FreeSurface(dst_surface);
+            SDL_FreeSurface(src_surface);
+         }
+
+         void Renderer::blit(Backend::Texture *src, const Rect &src_rect, Surface &dst, const Point &dst_pos, const RenderOptions &options)
+         {
+            blit(src->get_surface(), src_rect, dst, dst_pos, options);
+         }
+
+         void Renderer::fill(Surface &dst, const Color &color, const Rect &rect)
+         {
+            SDL_Surface *dst_surface = Blitters::create_sdl_surface_from(dst);
+            assert(dst_surface);
+
+            Uint32 mapped = SDL_MapRGBA(dst_surface->format, color.red, color.green, color.blue, color.alpha);
+            SDL_FillRect(dst_surface, &rect, mapped);
+         }
+
+         void Renderer::fill_blend(Surface &dst, const Color &color, const Rect &rect)
+         {
+            SDL_Surface *dst_surface = Blitters::create_sdl_surface_from(dst);
+            assert(dst_surface);
+
+            Uint32 mapped = SDL_MapRGBA(dst_surface->format, color.red, color.green, color.blue, color.alpha);
+            if(color.alpha == 0xff)
+            {
+               SDL_FillRect(dst_surface, &rect, mapped);
+            }
+            else if(color.alpha != 0x00)
+            {
+               SDL_Surface *temp = SDL_CreateRGBSurface(dst_surface->flags, rect.size.x, rect.size.y, dst_surface->format->BitsPerPixel, dst_surface->format->Rmask, dst_surface->format->Gmask, dst_surface->format->Bmask, dst_surface->format->Amask);
+
+               SDL_FillRect(temp, 0, mapped);
+               SDL_SetAlpha(temp, SDL_SRCALPHA | SDL_RLEACCEL, color.alpha);
+               SDL_BlitSurface(temp, 0, dst_surface, &rect);
+               SDL_FreeSurface(temp);
+            }
+         }
+
+         Backend::Window *Renderer::create_window(const Area &size, const Area &logical_size, bool fullscreen)
+         {
+            return new Window(size, logical_size, fullscreen);
+         }
+
+         Backend::Texture *Renderer::create_texture(const Surface &surface)
+         {
+            return new Texture(surface);
+         }
+      }
+   }
+}
diff --git a/src/unison/src/video/sdl/Renderer.hpp b/src/unison/src/video/sdl/Renderer.hpp
new file mode 100644 (file)
index 0000000..a7ed887
--- /dev/null
@@ -0,0 +1,97 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef UNISON_VIDEO_SDL_RENDERER_HPP
+#define UNISON_VIDEO_SDL_RENDERER_HPP
+
+#include <unison/video/backend/Renderer.hpp>
+
+#include <string> 
+#include "SDL.h"
+
+namespace Unison
+{
+   namespace Video
+   {
+      namespace Backend
+      {
+         class Texture;
+         class Window;
+      }
+      namespace SDL
+      {
+         /// Does rendering tasks like blits and color fills using SDL
+         class Renderer : public Backend::Renderer
+         {
+            public:
+               /// Default constructor
+               Renderer();
+
+               /// Destructor
+               ~Renderer();
+
+               /// Initialize the backend
+               void init();
+
+               /// Cleanup the backend
+               void quit();
+
+               /// Get the name of the renderer
+               /// \return the name of the renderer
+               std::string get_name();
+
+               /// Check if the backend is usable
+               /// \return Whether the backend is usable
+               bool is_usable();
+
+               Surface load_surface(const std::string &filename);
+               Surface load_surface(const std::string &filename, const Color &colorkey);
+               void save_surface(const Surface &surface, const std::string &filename);
+
+               /// Does a surface-to-surface blit
+               /// \param[in] src The source surface
+               /// \param[in] src_rect The part of the source surface to blit from
+               /// \param[in] dst The destination surface
+               /// \param[in] dst_pos The position to blit to
+               /// \param[in] options Extra blit options
+               void blit(const Surface &src, const Rect &src_rect, Surface &dst, const Point &dst_pos, const RenderOptions &options);
+
+               /// Does a texture-to-surface blit
+               /// \param[in] src The source texture
+               /// \param[in] src_rect The part of the source texture to blit from
+               /// \param[in] dst The destination surface
+               /// \param[in] dst_pos The position to blit to
+               /// \param[in] options Extra blit options
+               void blit(Backend::Texture *src, const Rect &src_rect, Surface &dst, const Point &dst_pos, const RenderOptions &options);
+
+               /// Fills a portion of a surface with the given color
+               /// \param[in] dst The destination surface
+               /// \param[in] color The color
+               /// \param[in] rect The portion to fill
+               void fill(Surface &dst, const Color &color, const Rect &rect);
+
+               /// Fills with alpha blend a portion of a surface with the given color
+               /// \param[in] dst The destination surface
+               /// \param[in] color The color
+               /// \param[in] rect The portion to fill
+               void fill_blend(Surface &dst, const Color &color, const Rect &rect);
+
+               /// Create a window
+               /// \param[in] size The size of the window
+               /// \param[in] logical_size The logical size of the window
+               /// \param[in] fullscreen Whether to open in fullscreen mode
+               /// \return The created window
+               Backend::Window *create_window(const Area &size, const Area &logical_size, bool fullscreen);
+
+               /// Create a texture data for the given surface
+               /// \param[in] surface The surface to convert
+               /// \return The texture data for the surface
+               Backend::Texture *create_texture(const Surface &surface);
+         };
+      }
+   }
+}
+
+#endif
diff --git a/src/unison/src/video/sdl/Texture.cpp b/src/unison/src/video/sdl/Texture.cpp
new file mode 100644 (file)
index 0000000..3e61de2
--- /dev/null
@@ -0,0 +1,118 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#include "Texture.hpp"
+#include <unison/video/Surface.hpp>
+#include <unison/video/Window.hpp>
+#include <unison/video/Renderers.hpp>
+#include <unison/video/sdl/Blitters.hpp>
+#include <unison/video/backend/Renderer.hpp>
+
+#include <assert.h>
+
+namespace Unison
+{
+   namespace Video
+   {
+      namespace SDL
+      {
+         Texture::Texture(const Surface &surface) :
+            Backend::Texture(surface),
+            scaled(),
+            n_cache(),
+            h_cache(),
+            v_cache(),
+            d_cache()
+         {
+         }
+         /*Texture::Texture(const Surface &surface, const std::string &name) :
+            Backend::Texture(surface, name),
+            scaled(),
+            n_cache(),
+            h_cache(),
+            v_cache(),
+            d_cache()
+         {
+         }
+
+         Texture::Texture(Backend::Texture *texture) :
+            Backend::Texture(texture),
+            scaled(),
+            n_cache(),
+            h_cache(),
+            v_cache(),
+            d_cache()
+         {
+         }*/
+
+         Texture::~Texture()
+         {
+         }
+
+         const Surface Texture::get_surface()
+         {
+            return surface;
+         }
+
+         void Texture::save()
+         {
+            scaled = Surface();
+            n_cache.clear();
+            h_cache.clear();
+            v_cache.clear();
+            d_cache.clear();
+         }
+
+         void Texture::blit(const Surface &src, const Point &dst_pos, const Rect &src_rect, const RenderOptions &options)
+         {
+            save();
+            Renderers::get().get_renderer().blit(src, src_rect, surface, dst_pos, options);
+         }
+
+         void Texture::blit(const Video::Texture &src, const Point &dst_pos, const Rect &src_rect, const RenderOptions &options)
+         {
+            save();
+            Texture *texture = dynamic_cast<Texture *>(Backend::Texture::get_texture(src.get_id()));
+            Renderers::get().get_renderer().blit(texture, src_rect, surface, dst_pos, options);
+         }
+
+         void Texture::fill(const Color &color, const Rect &rect)
+         {
+            save();
+            Renderers::get().get_renderer().fill(surface, color, rect);
+         }
+
+         void Texture::fill_blend(const Color &color, const Rect &rect)
+         {
+            save();
+            Renderers::get().get_renderer().fill_blend(surface, color, rect);
+         }
+
+         SDL_Surface *Texture::get_transform(const RenderOptions &options, unsigned int numerator, unsigned int denominator)
+         {
+            if(scaled.get_size() == Area())
+            {
+               scaled = surface.scale(numerator, denominator);
+            }
+            assert(scaled.get_size() == surface.get_size() * numerator / denominator);
+            std::map<Color, AlphaMap> &cache = options.h_flip ? (options.v_flip ? d_cache : h_cache) : (options.v_flip ? v_cache : n_cache);
+            if(!cache[options.color][options.alpha])
+            {
+               Surface transformed = scaled.modulate(options.color).modulate(options.alpha);
+               if(options.h_flip)
+               {
+                  transformed = transformed.h_flip();
+               }
+               if(options.v_flip)
+               {
+                  transformed = transformed.v_flip();
+               }
+               cache[options.color][options.alpha] = Blitters::optimize(transformed);
+            }
+            return cache[options.color][options.alpha];
+         }
+      }
+   }
+}
diff --git a/src/unison/src/video/sdl/Texture.hpp b/src/unison/src/video/sdl/Texture.hpp
new file mode 100644 (file)
index 0000000..fabf01e
--- /dev/null
@@ -0,0 +1,85 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef UNISON_VIDEO_SDL_TEXTURE_HPP
+#define UNISON_VIDEO_SDL_TEXTURE_HPP
+
+#include <unison/video/backend/Texture.hpp>
+#include <unison/video/Surface.hpp>
+
+#include <string>
+#include <map>
+
+#include "SDL.h"
+
+namespace Unison
+{
+   namespace Video
+   {
+      namespace SDL
+      {
+         class Texture : public Backend::Texture
+         {
+            public:
+               Texture(const Surface &surface);
+               //Texture(const Surface &surface, const std::string &name);
+               //Texture(Backend::Texture *texture);
+               ~Texture();
+
+               const Surface get_surface();
+               void save();
+               void blit(const Surface &src, const Point &dst_pos, const Rect &src_rect, const RenderOptions &options);
+               void blit(const Video::Texture &src, const Point &dst_pos, const Rect &src_rect, const RenderOptions &options);
+               void fill(const Color &color, const Rect &rect);
+               void fill_blend(const Color &color, const Rect &rect);
+
+               SDL_Surface *get_transform(const RenderOptions &options, unsigned int numerator, unsigned int denominator);
+            private:
+               Surface scaled;
+               struct AlphaMap
+               {
+                  static void ref(SDL_Surface *surface)
+                  {
+                    if(surface)
+                    {
+                      surface->refcount++;
+                    }
+                  }
+
+                  SDL_Surface *data[256];
+
+                  AlphaMap()
+                  {
+                     memset(data, 0, 256 * sizeof(SDL_Surface *));
+                  }
+
+                  ~AlphaMap()
+                  {
+                     std::for_each(data, data + 256, SDL_FreeSurface);
+                  }
+
+                  void operator = (const AlphaMap &other)
+                  {
+                     std::for_each(other.data, other.data + 256, ref);
+                     std::for_each(data, data + 256, SDL_FreeSurface);
+                     memcpy(data, other.data, 256 * sizeof(SDL_Surface *));
+                  }
+
+                  SDL_Surface *&operator [] (Uint8 alpha)
+                  {
+                     return data[alpha];
+                  }
+               };
+               //std::map<Color, AlphaMap> cache;
+               std::map<Color, AlphaMap> n_cache;
+               std::map<Color, AlphaMap> h_cache;
+               std::map<Color, AlphaMap> v_cache;
+               std::map<Color, AlphaMap> d_cache;
+         };
+      }
+   }
+}
+
+#endif
diff --git a/src/unison/src/video/sdl/Window.cpp b/src/unison/src/video/sdl/Window.cpp
new file mode 100644 (file)
index 0000000..9ed0d0f
--- /dev/null
@@ -0,0 +1,229 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#include "Window.hpp"
+#include "Texture.hpp"
+#include <unison/video/Window.hpp>
+#include <unison/video/Surface.hpp>
+#include <unison/video/Texture.hpp>
+#include <unison/video/Renderers.hpp>
+#include <unison/video/sdl/Blitters.hpp>
+#include <unison/video/backend/Renderer.hpp>
+#include <unison/video/backend/Texture.hpp>
+
+#include <functional>
+#include <assert.h>
+
+#include "SDL.h"
+
+namespace Unison
+{
+   namespace Video
+   {
+      namespace SDL
+      {
+         Window::Window(const Area &size, const Area &logical_size, bool fullscreen) :
+            scale_numerator(1),
+            scale_denominator(1),
+            offset(),
+            window(0)
+         {
+            assert(size.x);
+            assert(size.y);
+            unsigned int xratio = size.x * logical_size.y;
+            unsigned int yratio = size.y * logical_size.x;
+            if(xratio < yratio)
+            {
+               scale_numerator = size.x;
+               scale_denominator = logical_size.x;
+            }
+            else
+            {
+               scale_numerator = size.y;
+               scale_denominator = logical_size.y;
+            }
+            offset = (size - logical_size * scale_numerator / scale_denominator) / 2;
+            window = SDL_SetVideoMode(size.x, size.y, 0, SDL_ANYFORMAT | SDL_SWSURFACE | (fullscreen ? SDL_FULLSCREEN : 0));
+            assert(window);
+            Uint32 black = SDL_MapRGB(window->format, 0, 0, 0);
+            SDL_FillRect(window, 0, black);
+         }
+
+         Window::~Window()
+         {
+         }
+
+         void Window::take_screenshot(const std::string &filename) const
+         {
+            assert(window);
+            SDL_SaveBMP(window, filename.c_str());
+         }
+
+         void Window::flip()
+         {
+            assert(window);
+            SDL_Flip(window);
+         }
+
+         void Window::set_title(const std::string &title)
+         {
+            SDL_WM_SetCaption(title.c_str(), title.c_str());
+         }
+
+         void Window::set_icon(const Surface &icon)
+         {
+            SDL_Surface *icon_surface = Blitters::create_sdl_surface_from(icon);
+            assert(icon_surface);
+            SDL_WM_SetIcon(icon_surface, 0);
+            SDL_FreeSurface(icon_surface);
+         }
+
+         Area Window::get_size() const
+         {
+            return Area(window->w, window->h);
+         }
+
+         bool Window::is_fullscreen() const
+         {
+            return window->flags & SDL_FULLSCREEN;
+         }
+
+         void Window::blit(const Surface &src, const Point &dst_pos, const Rect &src_rect, const RenderOptions &options)
+         {
+            assert(src.get_pixels());
+            assert(window);
+
+            Surface fragment;
+            if(src_rect.pos == Point() && (src_rect.size == Area() || src_rect.size == src.get_size()))
+            {
+               fragment = src;
+            }
+            else
+            {
+               fragment = Surface(src_rect.size);
+               Video::Blitters::blit_blend_none(src, src_rect, fragment, Point());
+            }
+            fragment = fragment.scale(scale_numerator, scale_denominator);
+            if(options.h_flip)
+            {
+               fragment = fragment.h_flip();
+            }
+            if(options.v_flip)
+            {
+               fragment = fragment.v_flip();
+            }
+            SDL_Surface *src_surface = Blitters::create_sdl_surface_from(fragment.modulate(options.color).modulate(options.alpha));
+            assert(src_surface);
+
+            Point scaled_dst_pos(dst_pos);
+            scaled_dst_pos *= scale_numerator;
+            scaled_dst_pos /= scale_denominator;
+            scaled_dst_pos += offset;
+
+            Blitters::blit_blend(src_surface, Rect(Point(), fragment.get_size()), window, scaled_dst_pos, options.blend);
+
+            SDL_FreeSurface(src_surface);
+         }
+
+         void Window::blit(const Video::Texture &src, const Point &dst_pos, const Rect &src_rect, const RenderOptions &options)
+         {
+            Texture *texture = dynamic_cast<Texture *>(Backend::Texture::get_texture(src.get_id()));
+            assert(texture);
+            assert(window);
+
+            Rect scaled_src_rect(src_rect);
+            /*if(options.h_flip)
+            {
+               scaled_src_rect.pos.x = src.get_size().x - src_rect.pos.x - src_rect.size.x;
+            }
+            if(options.v_flip)
+            {
+               scaled_src_rect.pos.y = src.get_size().y - src_rect.pos.y - src_rect.size.y;
+            }*/
+            if(dst_pos.x < 0)
+            {
+               if(scaled_src_rect.size.x < (unsigned int) -dst_pos.x)
+               {
+                  return;
+               }
+               scaled_src_rect.pos.x += -dst_pos.x;
+               scaled_src_rect.size.x += dst_pos.x;
+            }
+            if(dst_pos.y < 0)
+            {
+               if(scaled_src_rect.size.y < (unsigned int) -dst_pos.y)
+               {
+                  return;
+               }
+               scaled_src_rect.pos.y += -dst_pos.y;
+               scaled_src_rect.size.y += dst_pos.y;
+            }
+            scaled_src_rect.pos *= scale_numerator;
+            scaled_src_rect.pos /= scale_denominator;
+            scaled_src_rect.size *= scale_numerator;
+            scaled_src_rect.size /= scale_denominator;
+
+            Point scaled_dst_pos(dst_pos);
+            if(dst_pos.x < 0)
+            {
+               scaled_dst_pos.x = 0;
+            }
+            if(dst_pos.y < 0)
+            {
+               scaled_dst_pos.y = 0;
+            }
+            scaled_dst_pos *= scale_numerator;
+            scaled_dst_pos /= scale_denominator;
+            scaled_dst_pos += offset;
+
+            Blitters::blit_blend(texture->get_transform(options, scale_numerator, scale_denominator), scaled_src_rect, window, scaled_dst_pos, options.blend);
+         }
+
+         void Window::fill(const Color &color, const Rect &rect)
+         {
+            assert(window);
+
+            Uint32 mapped = SDL_MapRGBA(window->format, color.red, color.green, color.blue, color.alpha);
+
+            Rect scaled_rect(rect);
+            scaled_rect.pos *= scale_numerator;
+            scaled_rect.pos /= scale_denominator;
+            scaled_rect.size *= scale_numerator;
+            scaled_rect.size /= scale_denominator;
+            scaled_rect.pos += offset;
+
+            SDL_FillRect(window, &scaled_rect, mapped);
+         }
+
+         void Window::fill_blend(const Color &color, const Rect &rect)
+         {
+            assert(window);
+
+            Uint32 mapped = SDL_MapRGB(window->format, color.red, color.green, color.blue);
+
+            Rect scaled_rect(rect);
+            scaled_rect.pos *= scale_numerator;
+            scaled_rect.pos /= scale_denominator;
+            scaled_rect.size *= scale_numerator;
+            scaled_rect.size /= scale_denominator;
+            scaled_rect.pos += offset;
+
+            if(color.alpha == 0xff)
+            {
+               SDL_FillRect(window, &scaled_rect, mapped);
+            }
+            else if(color.alpha != 0x00)
+            {
+               SDL_Surface *temp = SDL_CreateRGBSurface(window->flags, scaled_rect.size.x, scaled_rect.size.y, window->format->BitsPerPixel, window->format->Rmask, window->format->Gmask, window->format->Bmask, window->format->Amask);
+
+               SDL_FillRect(temp, 0, mapped);
+               SDL_SetAlpha(temp, SDL_SRCALPHA | SDL_RLEACCEL, color.alpha);
+               SDL_BlitSurface(temp, 0, window, &scaled_rect);
+               SDL_FreeSurface(temp);
+            }
+         }
+      }
+   }
+}
diff --git a/src/unison/src/video/sdl/Window.hpp b/src/unison/src/video/sdl/Window.hpp
new file mode 100644 (file)
index 0000000..ff07a35
--- /dev/null
@@ -0,0 +1,55 @@
+//          Copyright Timothy Goya 2007.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef UNISON_VIDEO_SDL_WINDOW_HPP
+#define UNISON_VIDEO_SDL_WINDOW_HPP
+
+#include <unison/video/backend/Window.hpp>
+#include <unison/video/RenderOptions.hpp>
+#include <string>
+
+#include "SDL.h"
+
+namespace Unison
+{
+   namespace Video
+   {
+      class Texture;
+      namespace SDL
+      {
+         class Window : public Backend::Window
+         {
+            public:
+               Window(const Area &size, const Area &logical_size, bool fullscreen = false);
+
+               ~Window();
+               void take_screenshot(const std::string &filename) const;
+               void flip();
+               void set_title(const std::string &title);
+               void set_icon(const Surface &icon);
+               Area get_size() const;
+               bool is_fullscreen() const;
+               void blit(const Surface &src, const Point &dst_pos, const Rect &src_rect, const RenderOptions &options);
+               void blit(const Video::Texture &src, const Point &dst_pos, const Rect &src_rect, const RenderOptions &options);
+               void fill(const Color &color, const Rect &rect);
+               void fill_blend(const Color &color, const Rect &rect);
+            private:
+               /// The numerator of the scaling ratio
+               unsigned int scale_numerator;
+
+               /// The denominator of the scaling ratio
+               unsigned int scale_denominator;
+
+               /// The offset used to center the drawing area
+               Point offset;
+
+               /// The window
+               SDL_Surface *window;
+         };
+      }
+   }
+}
+
+#endif
index f0bd76d..0fa97b1 100644 (file)
@@ -1,8 +1,7 @@
 //  $Id$
 //
 //  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de> //
 //  This program is free software; you can redistribute it and/or
 //  modify it under the terms of the GNU General Public License
 //  as published by the Free Software Foundation; either version 2
@@ -24,6 +23,8 @@
 #include <assert.h>
 #include "log.hpp"
 
+#include <unison/video/Color.hpp>
+
 class Color
 {
 public:
@@ -76,6 +77,16 @@ public:
     return greyscale() < other.greyscale();
   }
 
+  Unison::Video::Color to_unison_color() const
+  {
+    Unison::Video::Color color;
+    color.red = (unsigned char) (red * 0xff);
+    color.green = (unsigned char) (green * 0xff);
+    color.blue =(unsigned char)  (blue * 0xff);
+    color.alpha = (unsigned char) (alpha * 0xff);
+    return color;
+  }
+
   float red, green, blue, alpha;
 
   static const Color BLACK;
index 7ca3e26..8255de1 100644 (file)
 #include <algorithm>
 #include <cassert>
 #include <iostream>
-#include <SDL_image.h>
+//#include <SDL_image.h>
 #include <sstream>
 #include <iomanip>
 #include <physfs.h>
 
 #include "drawing_context.hpp"
-#include "drawing_request.hpp"
-#include "video_systems.hpp"
-#include "renderer.hpp"
-#include "lightmap.hpp"
+//#include "drawing_request.hpp"
+//#include "video_systems.hpp"
+//#include "renderer.hpp"
+//#include "lightmap.hpp"
 #include "surface.hpp"
 #include "main.hpp"
 #include "gameconfig.hpp"
-#include "texture.hpp"
-#include "texture_manager.hpp"
-#include "obstack/obstackpp.hpp"
+//#include "texture.hpp"
+//#include "texture_manager.hpp"
+//#include "obstack/obstackpp.hpp"
 
-static inline int next_po2(int val)
+#include "math/vector.hpp"
+#include "math/rect.hpp"
+
+#include <unison/video/Renderers.hpp>
+
+/*static inline int next_po2(int val)
 {
   int result = 1;
   while(result < val)
     result *= 2;
 
   return result;
-}
+}*/
 
-DrawingContext::DrawingContext() :
-  renderer(0), lightmap(0), ambient_color(1.0f, 1.0f, 1.0f, 1.0f), target(NORMAL), screenshot_requested(false)
+DrawingContext::DrawingContext()
+  /*renderer(0), lightmap(0), ambient_color(1.0f, 1.0f, 1.0f, 1.0f), target(NORMAL), screenshot_requested(false)*/
 {
-  requests = &drawing_requests;
-  obstack_init(&obst);
+  ambient_color = Color(1.0f, 1.0f, 1.0f, 1.0f);
+  target = NORMAL;
+  screenshot_requested = false;
+  draw_target = &normal_list;
+  /*requests = &drawing_requests;
+  obstack_init(&obst);*/
 }
 
 DrawingContext::~DrawingContext()
 {
-  delete renderer;
+  /*delete renderer;
   delete lightmap;
 
-  obstack_free(&obst, NULL);
+  obstack_free(&obst, NULL);*/
 }
 
 void
 DrawingContext::init_renderer()
 {
-  delete renderer;
+  Unison::Video::Renderers::get().set_renderer(config->video);
+  Unison::Video::Window::get().set_logical_size(Unison::Video::Area(SCREEN_WIDTH, SCREEN_HEIGHT));
+  Unison::Video::Window::get().open(Unison::Video::Area(config->screenwidth, config->screenheight), config->use_fullscreen);
+  lightmap = Unison::Video::Surface(Unison::Video::Area(SCREEN_WIDTH, SCREEN_HEIGHT));
+  /*delete renderer;
   delete lightmap;
 
   renderer = new_renderer();
-  lightmap = new_lightmap();
+  lightmap = new_lightmap();*/
 }
 
 void
@@ -80,7 +93,19 @@ DrawingContext::draw_surface(const Surface* surface, const Vector& position,
 {
   assert(surface != 0);
 
-  DrawingRequest* request = new(obst) DrawingRequest();
+  Unison::Video::RenderOptions options;
+  options.color = color.to_unison_color();
+  options.alpha = (unsigned char) transform.alpha * 0xff;
+  options.blend = blend.to_unison_blend();
+  options.h_flip = surface->get_flipx() != (transform.drawing_effect == HORIZONTAL_FLIP);
+  options.v_flip = (transform.drawing_effect == VERTICAL_FLIP);
+
+  Vector transformed = transform.apply(position);
+  Unison::Video::Point dst_pos((int) transformed.x, (int) transformed.y);
+
+  (*draw_target)[layer].blit_section(surface->get_texture(), dst_pos, options);
+
+  /*DrawingRequest* request = new(obst) DrawingRequest();
 
   request->target = target;
   request->type = SURFACE;
@@ -100,7 +125,7 @@ DrawingContext::draw_surface(const Surface* surface, const Vector& position,
 
   request->request_data = const_cast<Surface*> (surface);
 
-  requests->push_back(request);
+  requests->push_back(request);*/
 }
 
 void
@@ -116,7 +141,23 @@ DrawingContext::draw_surface_part(const Surface* surface, const Vector& source,
 {
   assert(surface != 0);
 
-  DrawingRequest* request = new(obst) DrawingRequest();
+  Unison::Video::TextureSection texture = surface->get_texture();
+  texture.clip_rect.pos.x += (int) source.x;
+  texture.clip_rect.pos.y += (int) source.y;
+  texture.clip_rect.size.x += (unsigned int) size.x;
+  texture.clip_rect.size.y += (unsigned int) size.y;
+
+  Unison::Video::RenderOptions options;
+  options.alpha = (unsigned char) transform.alpha * 0xff;
+  options.h_flip = surface->get_flipx() != (transform.drawing_effect == HORIZONTAL_FLIP);
+  options.v_flip = (transform.drawing_effect == VERTICAL_FLIP);
+
+  Vector transformed = transform.apply(dest);
+  Unison::Video::Point dst_pos((int) transformed.x, (int) transformed.y);
+
+  (*draw_target)[layer].blit_section(texture, dst_pos, options);
+
+  /*DrawingRequest* request = new(obst) DrawingRequest();
 
   request->target = target;
   request->type = SURFACE_PART;
@@ -147,14 +188,17 @@ DrawingContext::draw_surface_part(const Surface* surface, const Vector& source,
   }
   request->request_data = surfacepartrequest;
 
-  requests->push_back(request);
+  requests->push_back(request);*/
 }
 
 void
 DrawingContext::draw_text(const Font* font, const std::string& text,
     const Vector& position, FontAlignment alignment, int layer)
 {
-  DrawingRequest* request = new(obst) DrawingRequest();
+  font->draw((*draw_target)[layer], text, transform.apply(position),
+      alignment, transform.drawing_effect, transform.alpha);
+
+  /*DrawingRequest* request = new(obst) DrawingRequest();
 
   request->target = target;
   request->type = TEXT;
@@ -169,7 +213,7 @@ DrawingContext::draw_text(const Font* font, const std::string& text,
   textrequest->alignment = alignment;
   request->request_data = textrequest;
 
-  requests->push_back(request);
+  requests->push_back(request);*/
 }
 
 void
@@ -180,10 +224,41 @@ DrawingContext::draw_center_text(const Font* font, const std::string& text,
       ALIGN_CENTER, layer);
 }
 
+namespace
+{
+  class GradientRequest : public Unison::Video::DisplayList::Request
+  {
+    public:
+      GradientRequest(const Color &top, const Color &bottom) :
+        top(top),
+        bottom(bottom)
+      {
+      }
+
+      void do_request(Unison::Video::Blittable *dst) const
+      {
+        for(int y = 0;y < SCREEN_HEIGHT;++y)
+        {
+          Unison::Video::Color color;
+          color.red = (Uint8)((((float)(top.red-bottom.red)/(0-SCREEN_HEIGHT)) * y + top.red) * 255);
+          color.green = (Uint8)((((float)(top.green-bottom.green)/(0-SCREEN_HEIGHT)) * y + top.green) * 255);
+          color.green = (Uint8)((((float)(top.blue-bottom.blue)/(0-SCREEN_HEIGHT)) * y + top.blue) * 255);
+          color.alpha = (Uint8)((((float)(top.alpha-bottom.alpha)/(0-SCREEN_HEIGHT)) * y + top.alpha) * 255);
+          dst->fill(color, Unison::Video::Rect(0, y, SCREEN_WIDTH, 1));
+        }
+      }
+    private:
+      Color top;
+      Color bottom;
+  };
+}
+
 void
 DrawingContext::draw_gradient(const Color& top, const Color& bottom, int layer)
 {
-  DrawingRequest* request = new(obst) DrawingRequest();
+  (*draw_target)[layer].add_request(new GradientRequest(top, bottom));
+
+  /*DrawingRequest* request = new(obst) DrawingRequest();
 
   request->target = target;
   request->type = GRADIENT;
@@ -198,14 +273,23 @@ DrawingContext::draw_gradient(const Color& top, const Color& bottom, int layer)
   gradientrequest->bottom = bottom;
   request->request_data = gradientrequest;
 
-  requests->push_back(request);
+  requests->push_back(request);*/
 }
 
 void
 DrawingContext::draw_filled_rect(const Vector& topleft, const Vector& size,
                                  const Color& color, int layer)
 {
-  DrawingRequest* request = new(obst) DrawingRequest();
+  Vector transformed = transform.apply(topleft);
+
+  Unison::Video::Rect rect;
+  rect.pos = Unison::Video::Point((int) transformed.x, (int) transformed.y);
+  rect.size.x = (unsigned int) size.x;
+  rect.size.y = (unsigned int) size.y;
+
+  (*draw_target)[layer].fill_blend(color.to_unison_color(), rect);
+
+  /*DrawingRequest* request = new(obst) DrawingRequest();
 
   request->target = target;
   request->type = FILLRECT;
@@ -221,14 +305,24 @@ DrawingContext::draw_filled_rect(const Vector& topleft, const Vector& size,
   fillrectrequest->color.alpha = color.alpha * transform.alpha;
   request->request_data = fillrectrequest;
 
-  requests->push_back(request);
+  requests->push_back(request);*/
 }
 
 void
 DrawingContext::draw_filled_rect(const Rect& rect, const Color& color,
                                  int layer)
 {
-  DrawingRequest* request = new(obst) DrawingRequest();
+  Vector transformed = transform.apply(rect.p1);
+
+  Unison::Video::Rect unison_rect;
+  unison_rect.pos.x = (int) transformed.x;
+  unison_rect.pos.y = (int) transformed.y;
+  unison_rect.size.x = (unsigned int) rect.get_width();
+  unison_rect.size.y = (unsigned int) rect.get_height();
+
+  (*draw_target)[layer].fill_blend(color.to_unison_color(), unison_rect);
+
+  /*DrawingRequest* request = new(obst) DrawingRequest();
 
   request->target = target;
   request->type = FILLRECT;
@@ -244,7 +338,7 @@ DrawingContext::draw_filled_rect(const Rect& rect, const Color& color,
   fillrectrequest->color.alpha = color.alpha * transform.alpha;
   request->request_data = fillrectrequest;
 
-  requests->push_back(request);
+  requests->push_back(request);*/
 }
 
 void
@@ -256,23 +350,27 @@ DrawingContext::get_light(const Vector& position, Color* color)
     return;
   }
 
-  DrawingRequest* request = new(obst) DrawingRequest();
+  /*DrawingRequest* request = new(obst) DrawingRequest();
   request->target = target;
   request->type = GETLIGHT;
-  request->pos = transform.apply(position);
+  request->pos = transform.apply(position);*/
 
   //There is no light offscreen.
-  if(request->pos.x >= SCREEN_WIDTH || request->pos.y >= SCREEN_HEIGHT
-      || request->pos.x < 0 || request->pos.y < 0){
+  if(position.x >= SCREEN_WIDTH || position.y >= SCREEN_HEIGHT
+      || position.x < 0 || position.y < 0){
     *color = Color( 0, 0, 0);
     return;
   }
 
-  request->layer = LAYER_GUI; //make sure all get_light requests are handled last.
+  Vector transformed = transform.apply(position);
+  Unison::Video::Point pos((int) transformed.x, (int) transformed.y);
+  get_light_requests.push_back(std::make_pair(pos, color));
+
+  /*request->layer = LAYER_GUI; //make sure all get_light requests are handled last.
   GetLightRequest* getlightrequest = new(obst) GetLightRequest();
   getlightrequest->color_ptr = color;
   request->request_data = getlightrequest;
-  lightmap_requests.push_back(request);
+  lightmap_requests.push_back(request);*/
 }
 
 void
@@ -291,29 +389,39 @@ DrawingContext::do_drawing()
 
   // PART1: create lightmap
   if(use_lightmap) {
-    lightmap->start_draw(ambient_color);
-    handle_drawing_requests(lightmap_requests);
-    lightmap->end_draw();
+    lightmap.fill(ambient_color.to_unison_color());
+    lightmap.draw(lightmap_list);
+    //lightmap->start_draw(ambient_color);
+    //handle_drawing_requests(lightmap_requests);
+    //lightmap->end_draw();
   }
 
-  handle_drawing_requests(drawing_requests);
+  Unison::Video::Window::get().draw(normal_list);
+
+  //handle_drawing_requests(drawing_requests);
   if(use_lightmap) {
-    lightmap->do_draw();
+    Unison::Video::Window::get().blit(lightmap, Unison::Video::Point(), Unison::Video::Rect(), Unison::Video::BLEND_MOD);
+    //lightmap->do_draw();
   }
-  obstack_free(&obst, NULL);
-  obstack_init(&obst);
+  //obstack_free(&obst, NULL);
+  //obstack_init(&obst);
 
   // if a screenshot was requested, take one
   if (screenshot_requested) {
-    renderer->do_take_screenshot();
+    // FIXME renderer->do_take_screenshot();
     screenshot_requested = false;
   }
 
-  renderer->flip();
+  //renderer->flip();
+  Unison::Video::Window::get().flip();
+
+  normal_list.clear();
+  lightmap_list.clear();
 }
 
-class RequestPtrCompare
+/*class RequestPtrCompare
   :  public std::binary_function<const DrawingRequest*,
+  std::vector<std::pair<Unison::Video::Point, Color *> > get_light_requests;
                                  const DrawingRequest*, 
                                  bool>
 {
@@ -389,7 +497,7 @@ DrawingContext::handle_drawing_requests(DrawingRequests& requests)
     }
   }
   requests.clear();
-}
+}*/
 
 void
 DrawingContext::push_transform()
@@ -448,10 +556,10 @@ DrawingContext::set_target(Target target)
 {
   this->target = target;
   if(target == LIGHTMAP) {
-    requests = &lightmap_requests;
+    draw_target = &lightmap_list;
   } else {
     assert(target == NORMAL);
-    requests = &drawing_requests;
+    draw_target = &normal_list;
   }
 }
 
index c8f9012..28b15fc 100644 (file)
 #include <string>
 #include <memory>
 
-#include <stdint.h>
+//#include <stdint.h>
 
-#include <SDL_video.h>
-
-#include "glutil.hpp"
-#include "obstack/obstack.h"
-#include "math/vector.hpp"
-#include "math/rect.hpp"
+//#include "obstack/obstack.h"
+//#include "math/vector.hpp"
+//#include "math/rect.hpp"
 #include "drawing_request.hpp"
 #include "font.hpp"
 #include "color.hpp"
 
+#include <unison/video/Texture.hpp>
+#include <unison/video/Window.hpp>
+#include <unison/video/DisplayList.hpp>
+
+class Vector;
+class Rect;
+
 class Surface;
-class Texture;
+/*class Texture;
 struct DrawingRequest;
 class Renderer;
-class Lightmap;
+class Lightmap;*/
 
 /**
  * This class provides functions for drawing things on screen. It also
@@ -135,8 +139,15 @@ private:
     }
   };
 
-  Renderer *renderer;
-  Lightmap *lightmap;
+  Unison::Video::Surface lightmap;
+  std::vector<std::pair<Unison::Video::Point, Color *> > get_light_requests;
+
+  std::map<int, Unison::Video::DisplayList> normal_list;
+  std::map<int, Unison::Video::DisplayList> lightmap_list;
+  std::map<int, Unison::Video::DisplayList> *draw_target;
+
+  //Renderer *renderer;
+  //Lightmap *lightmap;
 
   /// the transform stack
   std::vector<Transform> transformstack;
@@ -146,21 +157,21 @@ private:
   std::vector<Blend> blend_stack;
   Blend blend_mode;
 
-  typedef std::vector<DrawingRequest*> DrawingRequests;
+  /*typedef std::vector<DrawingRequest*> DrawingRequests;
 
   void handle_drawing_requests(DrawingRequests& requests);
 
   DrawingRequests drawing_requests;
   DrawingRequests lightmap_requests;
 
-  DrawingRequests* requests;
+  DrawingRequests* requests;*/
   Color ambient_color;
 
   Target target;
   std::vector<Target> target_stack;
 
   /* obstack holding the memory of the drawing requests */
-  struct obstack obst;
+  //struct obstack obst;
 
   bool screenshot_requested; /**< true if a screenshot should be taken after the next frame has been rendered */
 };
index 24e0c02..b63f851 100644 (file)
 #include <string>
 #include <memory>
 
-#include <stdint.h>
+#include <assert.h>
 
-#include <SDL_video.h>
+//#include <stdint.h>
+
+//#include <SDL_video.h>
 
 #include "glutil.hpp"
-#include "math/vector.hpp"
-#include "color.hpp"
-#include "font.hpp"
+//#include "math/vector.hpp"
+//#include "color.hpp"
+//#include "font.hpp"
+#include <unison/video/RenderOptions.hpp>
 
 class Surface;
 
@@ -62,13 +65,37 @@ public:
   Blend(GLenum s, GLenum d)
     : sfactor(s), dfactor(d)
   {}
+
+  Unison::Video::BlendMode to_unison_blend() const
+  {
+    if(sfactor == GL_ONE && dfactor == GL_ZERO)
+    {
+      return Unison::Video::BLEND_NONE;
+    }
+    else if(sfactor == GL_SRC_ALPHA && dfactor == GL_ONE_MINUS_SRC_ALPHA)
+    {
+      return Unison::Video::BLEND_ALPHA;
+    }
+    else if(sfactor == GL_SRC_ALPHA && dfactor == GL_ONE)
+    {
+      return Unison::Video::BLEND_ADD;
+    }
+    else if(sfactor == GL_ZERO && dfactor == GL_SRC_COLOR)
+    {
+      return Unison::Video::BLEND_MOD;
+    }
+    else
+    {
+      assert(0 && "Unsupported blend factors");
+    }
+  }
 };
 
 enum Target {
   NORMAL, LIGHTMAP
 };
 
-enum RequestType
+/*enum RequestType
 {
   SURFACE, SURFACE_PART, TEXT, GRADIENT, FILLRECT, GETLIGHT
 };
@@ -127,7 +154,7 @@ struct DrawingRequest
 struct GetLightRequest
 {
   Color* color_ptr;
-};
+};*/
 
 #endif
 
index e5b6bb1..cc23a73 100644 (file)
@@ -31,7 +31,8 @@
 #include "lisp/lisp.hpp"
 #include "screen.hpp"
 #include "font.hpp"
-#include "renderer.hpp"
+//#include "renderer.hpp"
+#include <unison/video/Blittable.hpp>
 #include "drawing_context.hpp"
 #include "log.hpp"
 
@@ -267,7 +268,7 @@ Font::wrap_to_width(const std::string& s, float width, std::string* overflow)
 }
 
 void
-Font::draw(Renderer *renderer, const std::string& text, const Vector& pos_,
+Font::draw(Unison::Video::Blittable &dst, const std::string& text, const Vector& pos_,
            FontAlignment alignment, DrawingEffect drawing_effect,
            float alpha) const
 {
@@ -293,7 +294,7 @@ Font::draw(Renderer *renderer, const std::string& text, const Vector& pos_,
           // no bluring as we would get with subpixel positions
           pos.x = static_cast<int>(pos.x);
 
-          draw_text(renderer, temp, pos, drawing_effect, alpha);
+          draw_text(dst, temp, pos, drawing_effect, alpha);
 
           if (i == text.size())
             break;
@@ -305,7 +306,7 @@ Font::draw(Renderer *renderer, const std::string& text, const Vector& pos_,
 }
 
 void
-Font::draw_text(Renderer *renderer, const std::string& text, const Vector& pos,
+Font::draw_text(Unison::Video::Blittable &dst, const std::string& text, const Vector& pos,
                 DrawingEffect drawing_effect, float alpha) const
 {
   if(shadowsize > 0)
@@ -313,11 +314,11 @@ Font::draw_text(Renderer *renderer, const std::string& text, const Vector& pos,
       // FIXME: shadow_glyph_surface and glyph_surface do currently
       // share the same glyph array, this is incorrect and should be
       // fixed, it is however hardly noticable
-      draw_chars(renderer, shadow_glyph_surface, text,
+      draw_chars(dst, shadow_glyph_surface, text,
                  pos + Vector(shadowsize, shadowsize), drawing_effect, alpha);
     }
 
-  draw_chars(renderer, glyph_surface, text, pos, drawing_effect, alpha);
+  draw_chars(dst, glyph_surface, text, pos, drawing_effect, alpha);
 }
 
 int
@@ -343,7 +344,7 @@ Font::chr2glyph(uint32_t chr) const
 }
 
 void
-Font::draw_chars(Renderer *renderer, Surface* pchars, const std::string& text,
+Font::draw_chars(Unison::Video::Blittable &dst, Surface* pchars, const std::string& text,
                  const Vector& pos, DrawingEffect drawing_effect,
                  float alpha) const
 {
@@ -365,7 +366,26 @@ Font::draw_chars(Renderer *renderer, Surface* pchars, const std::string& text,
       else
         {
           const Glyph& glyph = glyphs[font_index];
-          DrawingRequest request;
+
+          assert(pchars != 0);
+
+          Unison::Video::TextureSection texture = pchars->get_texture();
+          texture.clip_rect.pos.x += (int) glyph.rect.p1.x;
+          texture.clip_rect.pos.y += (int) glyph.rect.p1.y;
+          texture.clip_rect.size.x += (unsigned int) glyph.rect.get_width();
+          texture.clip_rect.size.y += (unsigned int) glyph.rect.get_height();
+
+          Unison::Video::RenderOptions options;
+          options.alpha = (unsigned char) alpha * 0xff;
+          options.h_flip = (drawing_effect == HORIZONTAL_FLIP);
+          options.v_flip = (drawing_effect == VERTICAL_FLIP);
+
+          Vector transformed = p + glyph.offset;
+          Unison::Video::Point dst_pos((int) transformed.x, (int) transformed.y);
+
+          dst.blit_section(texture, dst_pos, options);
+
+          /*DrawingRequest request;
 
           request.pos = p + glyph.offset;
           request.drawing_effect = drawing_effect;
@@ -379,7 +399,7 @@ Font::draw_chars(Renderer *renderer, Surface* pchars, const std::string& text,
           request.request_data = &surfacepartrequest;
           renderer->draw_surface_part(request);
 
-          p.x += glyphs[font_index].advance;
+          p.x += glyphs[font_index].advance;*/
         }
     }
 }
index 5625be1..ea542c9 100644 (file)
@@ -28,7 +28,7 @@
 #include "math/vector.hpp"
 #include "math/rect.hpp"
 
-class Renderer;
+class Unison::Video::Blittable;
 
 enum FontAlignment {
   ALIGN_LEFT,
@@ -87,7 +87,7 @@ public:
 
   /** Draws the given text to the screen. Also needs the position.
    * Type of alignment, drawing effect and alpha are optional. */
-  void draw(Renderer *renderer, const std::string& text, const Vector& pos,
+  void draw(Unison::Video::Blittable &dst, const std::string& text, const Vector& pos,
             FontAlignment allignment = ALIGN_LEFT,
             DrawingEffect drawing_effect = NO_EFFECT,
             float alpha = 1.0f) const;
@@ -95,11 +95,11 @@ public:
 private:
   friend class DrawingContext;
 
-  void draw_text(Renderer *renderer, const std::string& text, const Vector& pos,
+  void draw_text(Unison::Video::Blittable &dst, const std::string& text, const Vector& pos,
                  DrawingEffect drawing_effect = NO_EFFECT,
                  float alpha = 1.0f) const;
 
-  void draw_chars(Renderer *renderer, Surface* pchars, const std::string& text,
+  void draw_chars(Unison::Video::Blittable &dst, Surface* pchars, const std::string& text,
                   const Vector& position, DrawingEffect drawing_effect,
                   float alpha) const;
 
diff --git a/src/video/gl_lightmap.cpp b/src/video/gl_lightmap.cpp
deleted file mode 100644 (file)
index 014fb73..0000000
+++ /dev/null
@@ -1,311 +0,0 @@
-//  $Id: gl_lightmap.cpp 5063 2007-05-27 11:32:00Z matzeb $
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-#include <config.h>
-
-#ifdef HAVE_OPENGL
-
-#include <functional>
-#include <algorithm>
-#include <cassert>
-#include <math.h>
-#include <iostream>
-#include <SDL_image.h>
-#include <sstream>
-#include <iomanip>
-#include <physfs.h>
-
-#include "glutil.hpp"
-#include "gl_lightmap.hpp"
-#include "gl_surface_data.hpp"
-#include "drawing_context.hpp"
-#include "drawing_request.hpp"
-#include "renderer.hpp"
-#include "surface.hpp"
-#include "font.hpp"
-#include "main.hpp"
-#include "gameconfig.hpp"
-#include "gl_texture.hpp"
-#include "texture_manager.hpp"
-#include "obstack/obstackpp.hpp"
-
-namespace
-{
-  inline void intern_draw(float left, float top, float right, float bottom,
-                                  float uv_left, float uv_top,
-                                  float uv_right, float uv_bottom,
-                                  float angle, float alpha,
-                                  const Color& color,
-                                  const Blend& blend,
-                                  DrawingEffect effect)
-  {
-    if(effect & HORIZONTAL_FLIP)
-      std::swap(uv_left, uv_right);
-    if(effect & VERTICAL_FLIP) {
-      std::swap(uv_top, uv_bottom);
-    }
-
-    float center_x = (left + right) / 2;
-    float center_y = (top + bottom) / 2;
-
-    float sa = sinf(angle/180.0f*M_PI);
-    float ca = cosf(angle/180.0f*M_PI);
-
-    left  -= center_x;
-    right -= center_x;
-
-    top    -= center_y;
-    bottom -= center_y;
-
-    glBlendFunc(blend.sfactor, blend.dfactor);
-    glColor4f(color.red, color.green, color.blue, color.alpha * alpha);
-    glBegin(GL_QUADS);
-    glTexCoord2f(uv_left, uv_top);
-    glVertex2f(left*ca - top*sa + center_x,
-               left*sa + top*ca + center_y);
-
-    glTexCoord2f(uv_right, uv_top);
-    glVertex2f(right*ca - top*sa + center_x,
-               right*sa + top*ca + center_y);
-
-    glTexCoord2f(uv_right, uv_bottom);
-    glVertex2f(right*ca - bottom*sa + center_x,
-               right*sa + bottom*ca + center_y);
-
-    glTexCoord2f(uv_left, uv_bottom);
-    glVertex2f(left*ca - bottom*sa + center_x,
-               left*sa + bottom*ca + center_y);
-    glEnd();
-
-    // FIXME: find a better way to restore the blend mode
-    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
-    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-  }
-}
-
-namespace GL
-{
-  static inline int next_po2(int val)
-  {
-    int result = 1;
-    while(result < val)
-      result *= 2;
-
-    return result;
-  }
-
-  Lightmap::Lightmap()
-  {
-    screen = SDL_GetVideoSurface();
-
-    lightmap_width = screen->w / LIGHTMAP_DIV;
-    lightmap_height = screen->h / LIGHTMAP_DIV;
-    unsigned int width = next_po2(lightmap_width);
-    unsigned int height = next_po2(lightmap_height);
-
-    lightmap = new Texture(width, height);
-
-    lightmap_uv_right = static_cast<float>(lightmap_width) / static_cast<float>(width);
-    lightmap_uv_bottom = static_cast<float>(lightmap_height) / static_cast<float>(height);
-    texture_manager->register_texture(lightmap);
-  }
-
-  Lightmap::~Lightmap()
-  {
-    texture_manager->remove_texture(lightmap);
-    delete lightmap;
-  }
-
-  void
-  Lightmap::start_draw(const Color &ambient_color)
-  {
-    glViewport(0, screen->h - lightmap_height, lightmap_width, lightmap_height);
-    glMatrixMode(GL_PROJECTION);
-    glLoadIdentity();
-    glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1.0, 1.0);
-    glMatrixMode(GL_MODELVIEW);
-    glLoadIdentity();
-
-    glClearColor( ambient_color.red, ambient_color.green, ambient_color.blue, 1 );
-    glClear(GL_COLOR_BUFFER_BIT);
-  }
-
-  void
-  Lightmap::end_draw()
-  {
-    glDisable(GL_BLEND);
-    glBindTexture(GL_TEXTURE_2D, lightmap->get_handle());
-    glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, screen->h - lightmap_height, lightmap_width, lightmap_height);
-
-    glViewport(0, 0, screen->w, screen->h);
-    glMatrixMode(GL_PROJECTION);
-    glLoadIdentity();
-    glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1.0, 1.0);
-    glMatrixMode(GL_MODELVIEW);
-    glLoadIdentity();
-    glEnable(GL_BLEND);
-    //glClear(GL_COLOR_BUFFER_BIT);
-  }
-
-  void
-  Lightmap::do_draw()
-  {
-    const Texture* texture = lightmap;
-
-    // multiple the lightmap with the framebuffer
-    glBlendFunc(GL_DST_COLOR, GL_ZERO);
-
-    glBindTexture(GL_TEXTURE_2D, texture->get_handle());
-    glBegin(GL_QUADS);
-
-    glTexCoord2f(0, lightmap_uv_bottom);
-    glVertex2f(0, 0);
-
-    glTexCoord2f(lightmap_uv_right, lightmap_uv_bottom);
-    glVertex2f(SCREEN_WIDTH, 0);
-
-    glTexCoord2f(lightmap_uv_right, 0);
-    glVertex2f(SCREEN_WIDTH, SCREEN_HEIGHT);
-
-    glTexCoord2f(0, 0);
-    glVertex2f(0, SCREEN_HEIGHT);
-
-    glEnd();
-
-    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-  }
-
-  void
-  Lightmap::draw_surface(const DrawingRequest& request)
-  {
-    const Surface* surface = (const Surface*) request.request_data;
-    GL::Texture *gltexture = dynamic_cast<GL::Texture *>(surface->get_texture());
-    GL::SurfaceData *surface_data = reinterpret_cast<GL::SurfaceData *>(surface->get_surface_data());
-
-    glBindTexture(GL_TEXTURE_2D, gltexture->get_handle());
-    intern_draw(request.pos.x, request.pos.y,
-                request.pos.x + surface->get_width(),
-                request.pos.y + surface->get_height(),
-                surface_data->get_uv_left(),
-                surface_data->get_uv_top(),
-                surface_data->get_uv_right(),
-                surface_data->get_uv_bottom(),
-                request.angle,
-                request.alpha,
-                request.color,
-                request.blend,
-                request.drawing_effect);
-  }
-
-  void
-  Lightmap::draw_surface_part(const DrawingRequest& request)
-  {
-    const SurfacePartRequest* surfacepartrequest
-      = (SurfacePartRequest*) request.request_data;
-    const Surface *surface = surfacepartrequest->surface;
-    GL::Texture *gltexture = dynamic_cast<GL::Texture *>(surface->get_texture());
-    GL::SurfaceData *surface_data = reinterpret_cast<GL::SurfaceData *>(surface->get_surface_data());
-
-    float uv_width = surface_data->get_uv_right() - surface_data->get_uv_left();
-    float uv_height = surface_data->get_uv_bottom() - surface_data->get_uv_top();
-
-    float uv_left = surface_data->get_uv_left() + (uv_width * surfacepartrequest->source.x) / surface->get_width();
-    float uv_top = surface_data->get_uv_top() + (uv_height * surfacepartrequest->source.y) / surface->get_height();
-    float uv_right = surface_data->get_uv_left() + (uv_width * (surfacepartrequest->source.x + surfacepartrequest->size.x)) / surface->get_width();
-    float uv_bottom = surface_data->get_uv_top() + (uv_height * (surfacepartrequest->source.y + surfacepartrequest->size.y)) / surface->get_height();
-
-    glBindTexture(GL_TEXTURE_2D, gltexture->get_handle());
-    intern_draw(request.pos.x, request.pos.y,
-                request.pos.x + surfacepartrequest->size.x,
-                request.pos.y + surfacepartrequest->size.y,
-                uv_left,
-                uv_top,
-                uv_right,
-                uv_bottom,
-                0.0,
-                request.alpha,
-                Color(1.0, 1.0, 1.0),
-                Blend(),
-                request.drawing_effect);
-  }
-
-  void
-  Lightmap::draw_gradient(const DrawingRequest& request)
-  {
-    const GradientRequest* gradientrequest 
-      = (GradientRequest*) request.request_data;
-    const Color& top = gradientrequest->top;
-    const Color& bottom = gradientrequest->bottom;
-
-    glDisable(GL_TEXTURE_2D);
-    glBegin(GL_QUADS);
-    glColor4f(top.red, top.green, top.blue, top.alpha);
-    glVertex2f(0, 0);
-    glVertex2f(SCREEN_WIDTH, 0);
-    glColor4f(bottom.red, bottom.green, bottom.blue, bottom.alpha);
-    glVertex2f(SCREEN_WIDTH, SCREEN_HEIGHT);
-    glVertex2f(0, SCREEN_HEIGHT);
-    glEnd();
-    glEnable(GL_TEXTURE_2D);
-    glColor4f(1, 1, 1, 1);
-  }
-
-  void
-  Lightmap::draw_filled_rect(const DrawingRequest& request)
-  {
-    const FillRectRequest* fillrectrequest
-      = (FillRectRequest*) request.request_data;
-
-    float x = request.pos.x;
-    float y = request.pos.y;
-    float w = fillrectrequest->size.x;
-    float h = fillrectrequest->size.y;
-
-    glDisable(GL_TEXTURE_2D);
-    glColor4f(fillrectrequest->color.red, fillrectrequest->color.green,
-              fillrectrequest->color.blue, fillrectrequest->color.alpha);
-
-    glBegin(GL_QUADS);
-    glVertex2f(x, y);
-    glVertex2f(x+w, y);
-    glVertex2f(x+w, y+h);
-    glVertex2f(x, y+h);
-    glEnd();
-    glEnable(GL_TEXTURE_2D);
-    glColor4f(1, 1, 1, 1);
-  }
-
-  void
-  Lightmap::get_light(const DrawingRequest& request) const
-  {
-    const GetLightRequest* getlightrequest 
-      = (GetLightRequest*) request.request_data;
-
-    float pixels[3];
-    for( int i = 0; i<3; i++)
-      pixels[i] = 0.0f; //set to black
-
-    float posX = request.pos.x * lightmap_width / SCREEN_WIDTH;
-    float posY = screen->h - request.pos.y * lightmap_height / SCREEN_HEIGHT;
-    glReadPixels((GLint) posX, (GLint) posY , 1, 1, GL_RGB, GL_FLOAT, pixels);
-    *(getlightrequest->color_ptr) = Color( pixels[0], pixels[1], pixels[2]);
-    //printf("get_light %f/%f =>%f/%f r%f g%f b%f\n", request.pos.x, request.pos.y, posX, posY, pixels[0], pixels[1], pixels[2]);
-  }
-}
-
-#endif
diff --git a/src/video/gl_lightmap.hpp b/src/video/gl_lightmap.hpp
deleted file mode 100644 (file)
index cb70709..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-//  $Id: gl_lightmap.hpp 4986 2007-04-16 17:48:28Z matzeb $
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-#include <config.h>
-
-#ifdef HAVE_OPENGL
-
-#ifndef SUPERTUX_GL_LIGHTMAP_H
-#define SUPERTUX_GL_LIGHTMAP_H
-
-#include <SDL_video.h>
-
-#include "lightmap.hpp"
-
-struct DrawingRequest;
-
-namespace GL
-{
-  class Texture;
-  class Lightmap : public ::Lightmap
-  {
-  public:
-    Lightmap();
-    ~Lightmap();
-
-    void start_draw(const Color &ambient_color);
-    void end_draw();
-    void do_draw();
-    void draw_surface(const DrawingRequest& request);
-    void draw_surface_part(const DrawingRequest& request);
-    void draw_text(const DrawingRequest& request);
-    void draw_gradient(const DrawingRequest& request);
-    void draw_filled_rect(const DrawingRequest& request);
-    void get_light(const DrawingRequest& request) const;
-
-  private:
-    static const int LIGHTMAP_DIV = 5;
-
-    SDL_Surface* screen;
-    Texture* lightmap;
-    int lightmap_width, lightmap_height;
-    float lightmap_uv_right, lightmap_uv_bottom;
-  };
-}
-
-#endif
-
-#endif
diff --git a/src/video/gl_renderer.cpp b/src/video/gl_renderer.cpp
deleted file mode 100644 (file)
index 3eee8f1..0000000
+++ /dev/null
@@ -1,339 +0,0 @@
-//  $Id: gl_renderer.cpp 5063 2007-05-27 11:32:00Z matzeb $
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-#include <config.h>
-
-#ifdef HAVE_OPENGL
-
-#include <functional>
-#include <algorithm>
-#include <cassert>
-#include <math.h>
-#include <iostream>
-#include <SDL_image.h>
-#include <sstream>
-#include <iomanip>
-#include <physfs.h>
-
-#include "glutil.hpp"
-#include "gl_renderer.hpp"
-#include "gl_texture.hpp"
-#include "gl_surface_data.hpp"
-#include "drawing_context.hpp"
-#include "drawing_request.hpp"
-#include "surface.hpp"
-#include "font.hpp"
-#include "main.hpp"
-#include "gameconfig.hpp"
-#include "texture.hpp"
-#include "texture_manager.hpp"
-#include "obstack/obstackpp.hpp"
-#define LIGHTMAP_DIV 5
-
-namespace
-{
-  inline void intern_draw(float left, float top, float right, float bottom,
-                                  float uv_left, float uv_top,
-                                  float uv_right, float uv_bottom,
-                                  float angle, float alpha,
-                                  const Color& color,
-                                  const Blend& blend,
-                                  DrawingEffect effect)
-  {
-    if(effect & HORIZONTAL_FLIP)
-      std::swap(uv_left, uv_right);
-    if(effect & VERTICAL_FLIP) {
-      std::swap(uv_top, uv_bottom);
-    }
-
-    float center_x = (left + right) / 2;
-    float center_y = (top + bottom) / 2;
-
-    float sa = sinf(angle/180.0f*M_PI);
-    float ca = cosf(angle/180.0f*M_PI);
-
-    left  -= center_x;
-    right -= center_x;
-
-    top    -= center_y;
-    bottom -= center_y;
-
-    glBlendFunc(blend.sfactor, blend.dfactor);
-    glColor4f(color.red, color.green, color.blue, color.alpha * alpha);
-    glBegin(GL_QUADS);
-    glTexCoord2f(uv_left, uv_top);
-    glVertex2f(left*ca - top*sa + center_x,
-               left*sa + top*ca + center_y);
-
-    glTexCoord2f(uv_right, uv_top);
-    glVertex2f(right*ca - top*sa + center_x,
-               right*sa + top*ca + center_y);
-
-    glTexCoord2f(uv_right, uv_bottom);
-    glVertex2f(right*ca - bottom*sa + center_x,
-               right*sa + bottom*ca + center_y);
-
-    glTexCoord2f(uv_left, uv_bottom);
-    glVertex2f(left*ca - bottom*sa + center_x,
-               left*sa + bottom*ca + center_y);
-    glEnd();
-
-    // FIXME: find a better way to restore the blend mode
-    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
-    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-  }
-}
-
-namespace GL
-{
-  Renderer::Renderer()
-  {
-    if(texture_manager != 0)
-      texture_manager->save_textures();
-
-    if(config->try_vsync) {
-      /* we want vsync for smooth scrolling */
-    SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
-    }
-
-    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
-    SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
-    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
-    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
-
-    int flags = SDL_OPENGL;
-    if(config->use_fullscreen)
-      flags |= SDL_FULLSCREEN;
-    int width = config->screenwidth;
-    int height = config->screenheight;
-    int bpp = 0;
-
-    SDL_Surface *screen = SDL_SetVideoMode(width, height, bpp, flags);
-    if(screen == 0) {
-      std::stringstream msg;
-      msg << "Couldn't set video mode (" << width << "x" << height
-          << "-" << bpp << "bpp): " << SDL_GetError();
-      throw std::runtime_error(msg.str());
-    }
-
-    // setup opengl state and transform
-    glDisable(GL_DEPTH_TEST);
-    glDisable(GL_CULL_FACE);
-    glEnable(GL_TEXTURE_2D);
-    glEnable(GL_BLEND);
-    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
-    glViewport(0, 0, screen->w, screen->h);
-    glMatrixMode(GL_PROJECTION);
-    glLoadIdentity();
-    // logical resolution here not real monitor resolution
-    glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1.0, 1.0);
-    glMatrixMode(GL_MODELVIEW);
-    glLoadIdentity();
-    glTranslatef(0, 0, 0);
-
-    check_gl_error("Setting up view matrices");
-
-
-    if(texture_manager == 0)
-      texture_manager = new TextureManager();
-    else
-      texture_manager->reload_textures();
-  }
-
-  Renderer::~Renderer()
-  {
-  }
-
-  void
-  Renderer::draw_surface(const DrawingRequest& request)
-  {
-    const Surface* surface = (const Surface*) request.request_data;
-    GL::Texture *gltexture = dynamic_cast<GL::Texture *>(surface->get_texture());
-    GL::SurfaceData *surface_data = reinterpret_cast<GL::SurfaceData *>(surface->get_surface_data());
-
-    glBindTexture(GL_TEXTURE_2D, gltexture->get_handle());
-    intern_draw(request.pos.x, request.pos.y,
-                request.pos.x + surface->get_width(),
-                request.pos.y + surface->get_height(),
-                surface_data->get_uv_left(),
-                surface_data->get_uv_top(),
-                surface_data->get_uv_right(),
-                surface_data->get_uv_bottom(),
-                request.angle,
-                request.alpha,
-                request.color,
-                request.blend,
-                request.drawing_effect);
-  }
-
-  void
-  Renderer::draw_surface_part(const DrawingRequest& request)
-  {
-    const SurfacePartRequest* surfacepartrequest
-      = (SurfacePartRequest*) request.request_data;
-    const Surface *surface = surfacepartrequest->surface;
-    GL::Texture *gltexture = dynamic_cast<GL::Texture *>(surface->get_texture());
-    GL::SurfaceData *surface_data = reinterpret_cast<GL::SurfaceData *>(surface->get_surface_data());
-
-    float uv_width = surface_data->get_uv_right() - surface_data->get_uv_left();
-    float uv_height = surface_data->get_uv_bottom() - surface_data->get_uv_top();
-
-    float uv_left = surface_data->get_uv_left() + (uv_width * surfacepartrequest->source.x) / surface->get_width();
-    float uv_top = surface_data->get_uv_top() + (uv_height * surfacepartrequest->source.y) / surface->get_height();
-    float uv_right = surface_data->get_uv_left() + (uv_width * (surfacepartrequest->source.x + surfacepartrequest->size.x)) / surface->get_width();
-    float uv_bottom = surface_data->get_uv_top() + (uv_height * (surfacepartrequest->source.y + surfacepartrequest->size.y)) / surface->get_height();
-
-    glBindTexture(GL_TEXTURE_2D, gltexture->get_handle());
-    intern_draw(request.pos.x, request.pos.y,
-                request.pos.x + surfacepartrequest->size.x,
-                request.pos.y + surfacepartrequest->size.y,
-                uv_left,
-                uv_top,
-                uv_right,
-                uv_bottom,
-                0.0,
-                request.alpha,
-                Color(1.0, 1.0, 1.0),
-                Blend(),
-                request.drawing_effect);
-  }
-
-  void
-  Renderer::draw_gradient(const DrawingRequest& request)
-  {
-    const GradientRequest* gradientrequest 
-      = (GradientRequest*) request.request_data;
-    const Color& top = gradientrequest->top;
-    const Color& bottom = gradientrequest->bottom;
-
-    glDisable(GL_TEXTURE_2D);
-    glBegin(GL_QUADS);
-    glColor4f(top.red, top.green, top.blue, top.alpha);
-    glVertex2f(0, 0);
-    glVertex2f(SCREEN_WIDTH, 0);
-    glColor4f(bottom.red, bottom.green, bottom.blue, bottom.alpha);
-    glVertex2f(SCREEN_WIDTH, SCREEN_HEIGHT);
-    glVertex2f(0, SCREEN_HEIGHT);
-    glEnd();
-    glEnable(GL_TEXTURE_2D);
-    glColor4f(1, 1, 1, 1);
-  }
-
-  void
-  Renderer::draw_filled_rect(const DrawingRequest& request)
-  {
-    const FillRectRequest* fillrectrequest
-      = (FillRectRequest*) request.request_data;
-
-    float x = request.pos.x;
-    float y = request.pos.y;
-    float w = fillrectrequest->size.x;
-    float h = fillrectrequest->size.y;
-
-    glDisable(GL_TEXTURE_2D);
-    glColor4f(fillrectrequest->color.red, fillrectrequest->color.green,
-              fillrectrequest->color.blue, fillrectrequest->color.alpha);
-
-    glBegin(GL_QUADS);
-    glVertex2f(x, y);
-    glVertex2f(x+w, y);
-    glVertex2f(x+w, y+h);
-    glVertex2f(x, y+h);
-    glEnd();
-    glEnable(GL_TEXTURE_2D);
-    glColor4f(1, 1, 1, 1);
-  }
-
-  void 
-  Renderer::do_take_screenshot()
-  {
-    // [Christoph] TODO: Yes, this method also takes care of the actual disk I/O. Split it?
-
-    SDL_Surface *shot_surf;
-    // create surface to hold screenshot
-    #if SDL_BYTEORDER == SDL_BIG_ENDIAN
-    shot_surf = SDL_CreateRGBSurface(SDL_SWSURFACE, SCREEN_WIDTH, SCREEN_HEIGHT, 24, 0x00FF0000, 0x0000FF00, 0x000000FF, 0);
-    #else
-    shot_surf = SDL_CreateRGBSurface(SDL_SWSURFACE, SCREEN_WIDTH, SCREEN_HEIGHT, 24, 0x000000FF, 0x0000FF00, 0x00FF0000, 0);
-    #endif
-    if (!shot_surf) {
-      log_warning << "Could not create RGB Surface to contain screenshot" << std::endl;
-      return;
-    }
-
-    // read pixels into array
-    char* pixels = new char[3 * SCREEN_WIDTH * SCREEN_HEIGHT];
-    if (!pixels) {
-      log_warning << "Could not allocate memory to store screenshot" << std::endl;
-      SDL_FreeSurface(shot_surf);
-      return;
-    }
-    glReadPixels(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, pixels);
-
-    // copy array line-by-line
-    for (int i = 0; i < SCREEN_HEIGHT; i++) {
-      char* src = pixels + (3 * SCREEN_WIDTH * (SCREEN_HEIGHT - i - 1));
-      if(SDL_MUSTLOCK(shot_surf))
-      {
-        SDL_LockSurface(shot_surf);
-      }
-      char* dst = ((char*)shot_surf->pixels) + i * shot_surf->pitch;
-      memcpy(dst, src, 3 * SCREEN_WIDTH);
-      if(SDL_MUSTLOCK(shot_surf))
-      {
-        SDL_UnlockSurface(shot_surf);
-      }
-    }
-
-    // free array
-    delete[](pixels);
-
-    // save screenshot
-    static const std::string writeDir = PHYSFS_getWriteDir();
-    static const std::string dirSep = PHYSFS_getDirSeparator();
-    static const std::string baseName = "screenshot";
-    static const std::string fileExt = ".bmp";
-    std::string fullFilename;
-    for (int num = 0; num < 1000; num++) {
-      std::ostringstream oss;
-      oss << baseName;
-      oss << std::setw(3) << std::setfill('0') << num;
-      oss << fileExt;
-      std::string fileName = oss.str();
-      fullFilename = writeDir + dirSep + fileName;
-      if (!PHYSFS_exists(fileName.c_str())) {
-        SDL_SaveBMP(shot_surf, fullFilename.c_str());
-        log_debug << "Wrote screenshot to \"" << fullFilename << "\"" << std::endl;
-        SDL_FreeSurface(shot_surf);
-        return;
-      }
-    }
-    log_warning << "Did not save screenshot, because all files up to \"" << fullFilename << "\" already existed" << std::endl;
-    SDL_FreeSurface(shot_surf);
-  }
-
-  void
-  Renderer::flip()
-  {
-    assert_gl("drawing");
-    SDL_GL_SwapBuffers();
-  }
-}
-
-#endif
diff --git a/src/video/gl_renderer.hpp b/src/video/gl_renderer.hpp
deleted file mode 100644 (file)
index 1eef6b4..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-//  $Id: gl_renderer.hpp 4986 2007-04-16 17:48:28Z matzeb $
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-#include <config.h>
-
-#ifdef HAVE_OPENGL
-
-#ifndef SUPERTUX_GL_RENDERER_H
-#define SUPERTUX_GL_RENDERER_H
-
-#include "renderer.hpp"
-
-namespace GL
-{
-  class Renderer : public ::Renderer
-  {
-  public:
-    Renderer();
-    ~Renderer();
-
-    void draw_surface(const DrawingRequest& request);
-    void draw_surface_part(const DrawingRequest& request);
-    void draw_text(const DrawingRequest& request);
-    void draw_gradient(const DrawingRequest& request);
-    void draw_filled_rect(const DrawingRequest& request);
-    void do_take_screenshot();
-    void flip();
-  };
-}
-
-#endif
-
-#endif
diff --git a/src/video/gl_surface_data.hpp b/src/video/gl_surface_data.hpp
deleted file mode 100644 (file)
index a441f10..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-//  $Id: gl_surface_data.hpp 4063 2006-07-21 21:05:23Z anmaster $
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-#include <config.h>
-
-#ifdef HAVE_OPENGL
-
-#ifndef __GL_SURFACE_DATA_HPP__
-#define __GL_SURFACE_DATA_HPP__
-
-#include "surface.hpp"
-
-namespace GL
-{
-  class SurfaceData
-  {
-  private:
-    const Surface &surface;
-    float uv_left;
-    float uv_top;
-    float uv_right;
-    float uv_bottom;
-
-  public:
-    SurfaceData(const Surface &surface) :
-      surface(surface)
-    {
-      uv_left = (float) surface.get_x() / surface.get_texture()->get_texture_width();
-      uv_top = (float) surface.get_y() / surface.get_texture()->get_texture_height();
-      uv_right = (float) (surface.get_x() + surface.get_width()) / surface.get_texture()->get_texture_width();
-      uv_bottom = (float) (surface.get_y() + surface.get_height()) / surface.get_texture()->get_texture_height();
-    }
-
-    float get_uv_left() const
-    {
-      return surface.get_flipx() ? uv_right : uv_left;
-    }
-
-    float get_uv_top() const
-    {
-      return uv_top;
-    }
-
-    float get_uv_right() const
-    {
-      return surface.get_flipx() ? uv_left : uv_right;
-    }
-
-    float get_uv_bottom() const
-    {
-      return uv_bottom;
-    }
-  };
-}
-
-#endif
-
-#endif
diff --git a/src/video/gl_texture.cpp b/src/video/gl_texture.cpp
deleted file mode 100644 (file)
index 413d0ce..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-//  $Id: gl_texture.cpp 4063 2006-07-21 21:05:23Z anmaster $
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-#include <config.h>
-
-#ifdef HAVE_OPENGL
-
-#include "gl_texture.hpp"
-#include "gameconfig.hpp"
-#include "glutil.hpp"
-#include "log.hpp"
-
-#include <assert.h>
-#include <stdexcept>
-
-namespace
-{
-  inline bool is_power_of_2(int v)
-  {
-    return (v & (v-1)) == 0;
-  }
-
-  inline int next_power_of_two(int val)
-  {
-    int result = 1;
-    while(result < val)
-      result *= 2;
-    return result;
-  }
-}
-
-namespace GL
-{
-  Texture::Texture(unsigned int width, unsigned int height)
-  {
-    assert(is_power_of_2(width));
-    assert(is_power_of_2(height));
-    texture_width = width;
-    texture_height = height;
-    image_width = width;
-    image_height = height;
-
-    assert_gl("before creating texture");
-    glGenTextures(1, &handle);
-
-    try {
-      glBindTexture(GL_TEXTURE_2D, handle);
-
-      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_width,
-                   texture_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
-
-      set_texture_params();
-    } catch(...) {
-      glDeleteTextures(1, &handle);
-      throw;
-    }
-  }
-
-  Texture::Texture(SDL_Surface* image)
-  {
-    texture_width = next_power_of_two(image->w);
-    texture_height = next_power_of_two(image->h);
-    image_width = image->w;
-    image_height = image->h;
-
-#if SDL_BYTEORDER == SDL_BIG_ENDIAN
-    SDL_Surface* convert = SDL_CreateRGBSurface(SDL_SWSURFACE,
-        texture_width, texture_height, 32,
-        0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
-#else
-    SDL_Surface* convert = SDL_CreateRGBSurface(SDL_SWSURFACE,
-        texture_width, texture_height, 32,
-        0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
-#endif
-
-    if(convert == 0) {
-      throw std::runtime_error("Couldn't create texture: out of memory");
-    }
-
-    SDL_SetAlpha(image, 0, 0);
-    SDL_BlitSurface(image, 0, convert, 0);
-
-    assert_gl("before creating texture");
-    glGenTextures(1, &handle);
-
-    try {
-      GLenum sdl_format;
-      if(convert->format->BytesPerPixel == 3)
-        sdl_format = GL_RGB;
-      else if(convert->format->BytesPerPixel == 4)
-        sdl_format = GL_RGBA;
-      else
-        assert(false);
-
-      glBindTexture(GL_TEXTURE_2D, handle);
-      glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-      glPixelStorei(GL_UNPACK_ROW_LENGTH, convert->pitch/convert->format->BytesPerPixel);
-      if(SDL_MUSTLOCK(convert))
-      {
-        SDL_LockSurface(convert);
-      }
-      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_width,
-              texture_height, 0, sdl_format,
-              GL_UNSIGNED_BYTE, convert->pixels);
-      if(SDL_MUSTLOCK(convert))
-      {
-        SDL_UnlockSurface(convert);
-      }
-
-      assert_gl("creating texture");
-
-      set_texture_params();
-    } catch(...) {
-      glDeleteTextures(1, &handle);
-      SDL_FreeSurface(convert);
-      throw;
-    }
-    SDL_FreeSurface(convert);
-  }
-
-  Texture::~Texture()
-  {
-    glDeleteTextures(1, &handle);
-  }
-
-  void
-  Texture::set_texture_params()
-  {
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
-
-    assert_gl("set texture params");
-  }
-}
-
-#endif
diff --git a/src/video/gl_texture.hpp b/src/video/gl_texture.hpp
deleted file mode 100644 (file)
index 14532cc..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-//  $Id: gl_texture.hpp 4063 2006-07-21 21:05:23Z anmaster $
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-#include <config.h>
-
-#ifdef HAVE_OPENGL
-
-#ifndef __GL_TEXTURE_HPP__
-#define __GL_TEXTURE_HPP__
-
-#include <SDL.h>
-
-#include "texture.hpp"
-#include "glutil.hpp"
-
-/**
- * This class is a wrapper around a texture handle. It stores the texture width
- * and height and provides convenience functions for uploading SDL_Surfaces
- * into the texture
- */
-namespace GL
-{
-  class Texture : public ::Texture
-  {
-  protected:
-    GLuint handle;
-    unsigned int texture_width;
-    unsigned int texture_height;
-    unsigned int image_width;
-    unsigned int image_height;
-
-  public:
-    Texture(unsigned int width, unsigned int height);
-    Texture(SDL_Surface* image);
-    ~Texture();
-
-    const GLuint &get_handle() const {
-      return handle;
-    }
-
-    void set_handle(GLuint handle) {
-      this->handle = handle;
-    }
-
-    unsigned int get_texture_width() const
-    {
-      return texture_width;
-    }
-
-    unsigned int get_texture_height() const
-    {
-      return texture_height;
-    }
-
-    unsigned int get_image_width() const
-    {
-      return image_width;
-    }
-
-    unsigned int get_image_height() const
-    {
-      return image_height;
-    }
-
-    void set_image_width(unsigned int width)
-    {
-      image_width = width;
-    }
-
-    void set_image_height(unsigned int height)
-    {
-      image_height = height;
-    }
-
-  private:
-    void set_texture_params();
-  };
-}
-
-#endif
-
-#endif
index 85200bd..2c66dd6 100644 (file)
 #ifndef __GLUTIL_HPP__
 #define __GLUTIL_HPP__
 
-#include <config.h>
+typedef unsigned int GLenum;
+typedef int GLint;
 
+#define GL_ZERO 0x0
+#define GL_ONE 0x1
+#define GL_SRC_COLOR 0x0300
+#define GL_SRC_ALPHA 0x0302
+#define GL_ONE_MINUS_SRC_ALPHA 0x0303
+#define GL_DST_COLOR 0x0306
+
+//#include <config.h>
+
+#if 0
 #ifdef HAVE_OPENGL
 
 #include <sstream>
@@ -98,5 +109,6 @@ static inline void assert_gl(const char* message)
 #define GL_ONE 3
 
 #endif
+#endif
 
 #endif
diff --git a/src/video/lightmap.hpp b/src/video/lightmap.hpp
deleted file mode 100644 (file)
index 049b21e..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-//  $Id: lightmap.hpp 4986 2007-04-16 17:48:28Z matzeb $
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-#ifndef SUPERTUX_LIGHTMAP_H
-#define SUPERTUX_LIGHTMAP_H
-
-#include <vector>
-#include <string>
-#include <memory>
-
-#include <stdint.h>
-
-#include <SDL_video.h>
-
-#include "glutil.hpp"
-#include "obstack/obstack.h"
-#include "math/vector.hpp"
-#include "math/rect.hpp"
-#include "drawing_request.hpp"
-#include "surface.hpp"
-#include "font.hpp"
-#include "color.hpp"
-
-class Texture;
-struct DrawingRequest;
-
-class Lightmap
-{
-public:
-  virtual ~Lightmap() {}
-
-  virtual void start_draw(const Color &ambient_color) = 0;
-  virtual void end_draw() = 0;
-  virtual void do_draw() = 0;
-  virtual void draw_surface(const DrawingRequest& request) = 0;
-  virtual void draw_surface_part(const DrawingRequest& request) = 0;
-  virtual void draw_gradient(const DrawingRequest& request) = 0;
-  virtual void draw_filled_rect(const DrawingRequest& request) = 0;
-  virtual void get_light(const DrawingRequest& request) const = 0;
-};
-
-#endif
-
diff --git a/src/video/renderer.hpp b/src/video/renderer.hpp
deleted file mode 100644 (file)
index 2bd96d7..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-//  $Id: drawing_context.hpp 4986 2007-04-16 17:48:28Z matzeb $
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-#ifndef SUPERTUX_RENDERER_H
-#define SUPERTUX_RENDERER_H
-
-#include <vector>
-#include <string>
-#include <memory>
-
-#include <stdint.h>
-
-#include <SDL_video.h>
-
-#include "glutil.hpp"
-#include "obstack/obstack.h"
-#include "math/vector.hpp"
-#include "math/rect.hpp"
-#include "surface.hpp"
-#include "font.hpp"
-#include "color.hpp"
-
-class Surface;
-class Texture;
-struct DrawingRequest;
-
-class Renderer
-{
-public:
-  virtual ~Renderer() {}
-
-  virtual void draw_surface(const DrawingRequest& request) = 0;
-  virtual void draw_surface_part(const DrawingRequest& request) = 0;
-  virtual void draw_gradient(const DrawingRequest& request) = 0;
-  virtual void draw_filled_rect(const DrawingRequest& request)= 0;
-  virtual void do_take_screenshot() = 0;
-  virtual void flip() = 0;
-};
-
-#endif
-
diff --git a/src/video/sdl_lightmap.cpp b/src/video/sdl_lightmap.cpp
deleted file mode 100644 (file)
index 8e7c70f..0000000
+++ /dev/null
@@ -1,614 +0,0 @@
-//  $Id: sdl_lightmap.cpp 5063 2007-05-27 11:32:00Z matzeb $
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-#include <config.h>
-
-#include <functional>
-#include <algorithm>
-#include <cassert>
-#include <iostream>
-#include <SDL_image.h>
-#include <sstream>
-#include <iomanip>
-#include <physfs.h>
-
-#include "glutil.hpp"
-#include "sdl_lightmap.hpp"
-#include "sdl_texture.hpp"
-#include "sdl_surface_data.hpp"
-#include "drawing_context.hpp"
-#include "drawing_request.hpp"
-#include "renderer.hpp"
-#include "surface.hpp"
-#include "font.hpp"
-#include "main.hpp"
-#include "gameconfig.hpp"
-#include "texture.hpp"
-#include "texture_manager.hpp"
-#include "obstack/obstackpp.hpp"
-
-namespace SDL
-{
-  Lightmap::Lightmap()
-  {
-    screen = SDL_GetVideoSurface();
-
-    float xfactor = (float) config->screenwidth / SCREEN_WIDTH;
-    float yfactor = (float) config->screenheight / SCREEN_HEIGHT;
-    if(xfactor < yfactor)
-    {
-      numerator = config->screenwidth;
-      denominator = SCREEN_WIDTH;
-    }
-    else
-    {
-      numerator = config->screenheight;
-      denominator = SCREEN_HEIGHT;
-    }
-
-    LIGHTMAP_DIV = 8 * numerator / denominator;
-
-    width = screen->w / LIGHTMAP_DIV;
-    height = screen->h / LIGHTMAP_DIV;
-
-    red_channel = (Uint8 *)malloc(width * height * sizeof(Uint8));
-    green_channel = (Uint8 *)malloc(width * height * sizeof(Uint8));
-    blue_channel = (Uint8 *)malloc(width * height * sizeof(Uint8));
-  }
-
-  Lightmap::~Lightmap()
-  {
-    free(red_channel);
-    free(green_channel);
-    free(blue_channel);
-  }
-
-  void
-  Lightmap::start_draw(const Color &ambient_color)
-  {
-    memset(red_channel, (Uint8) (ambient_color.red * 255), width * height * sizeof(Uint8));
-    memset(green_channel, (Uint8) (ambient_color.green * 255), width * height * sizeof(Uint8));
-    memset(blue_channel, (Uint8) (ambient_color.blue * 255), width * height * sizeof(Uint8));
-  }
-
-  void
-  Lightmap::end_draw()
-  {
-  }
-
-//#define BILINEAR
-
-#ifdef BILINEAR
-  namespace
-  {
-    void merge(Uint8 color[3], Uint8 color0[3], Uint8 color1[3], int rem, int total)
-    {
-      color[0] = (color0[0] * (total - rem) + color1[0] * rem) / total;
-      color[1] = (color0[1] * (total - rem) + color1[1] * rem) / total;
-      color[2] = (color0[2] * (total - rem) + color1[2] * rem) / total;
-    }
-  }
-#endif
-
-  void
-  Lightmap::do_draw()
-  {
-    // FIXME: This is really slow
-    if(LIGHTMAP_DIV == 1)
-    {
-      int bpp = screen->format->BytesPerPixel;
-      if(SDL_MUSTLOCK(screen))
-      {
-        SDL_LockSurface(screen);
-      }
-      Uint8 *pixel = (Uint8 *) screen->pixels;
-      int loc = 0;
-      for(int y = 0;y < height;y++) {
-        for(int x = 0;x < width;x++, pixel += bpp, loc++) {
-          if(red_channel[loc] == 0xff && green_channel[loc] == 0xff && blue_channel[loc] == 0xff)
-          {
-            continue;
-          }
-          Uint32 mapped = 0;
-          switch(bpp) {
-            case 1:
-              mapped = *pixel;
-              break;
-            case 2:
-              mapped = *(Uint16 *)pixel;
-              break;
-            case 3:
-#if SDL_BYTEORDER == SDL_BIG_ENDIAN
-              mapped |= pixel[0] << 16;
-              mapped |= pixel[1] << 8;
-              mapped |= pixel[2] << 0;
-#else
-              mapped |= pixel[0] << 0;
-              mapped |= pixel[1] << 8;
-              mapped |= pixel[2] << 16;
-#endif
-              break;
-            case 4:
-              mapped = *(Uint32 *)pixel;
-              break;
-          }
-          Uint8 red, green, blue, alpha;
-          SDL_GetRGBA(mapped, screen->format, &red, &green, &blue, &alpha);
-          red = (red * red_channel[loc]) >> 8;
-          green = (green * green_channel[loc]) >> 8;
-          blue = (blue * blue_channel[loc]) >> 8;
-          mapped = SDL_MapRGBA(screen->format, red, green, blue, alpha);
-          switch(bpp) {
-            case 1:
-              *pixel = mapped;
-              break;
-            case 2:
-              *(Uint16 *)pixel = mapped;
-              break;
-            case 3:
-#if SDL_BYTEORDER == SDL_BIG_ENDIAN
-              pixel[0] = (mapped >> 16) & 0xff;
-              pixel[1] = (mapped >> 8) & 0xff;
-              pixel[2] = (mapped >> 0) & 0xff;
-#else
-              pixel[0] = (mapped >> 0) & 0xff;
-              pixel[1] = (mapped >> 8) & 0xff;
-              pixel[2] = (mapped >> 16) & 0xff;
-#endif
-              break;
-            case 4:
-              *(Uint32 *)pixel = mapped;
-              break;
-          }
-        }
-        pixel += screen->pitch - width * bpp;
-      }
-      if(SDL_MUSTLOCK(screen))
-      {
-        SDL_UnlockSurface(screen);
-      }
-    }
-    else
-    {
-      int bpp = screen->format->BytesPerPixel;
-      if(SDL_MUSTLOCK(screen))
-      {
-        SDL_LockSurface(screen);
-      }
-      Uint8 *div_pixel = (Uint8 *) screen->pixels;
-      int loc = 0;
-      for(int y = 0;y < height;y++) {
-        for(int x = 0;x < width;x++, div_pixel += bpp * LIGHTMAP_DIV, loc++) {
-          if(red_channel[loc] == 0xff && green_channel[loc] == 0xff && blue_channel[loc] == 0xff)
-          {
-            continue;
-          }
-          Uint8 *pixel = div_pixel;
-          for(int div_y = 0;div_y < LIGHTMAP_DIV;div_y++) {
-            for(int div_x = 0;div_x < LIGHTMAP_DIV;pixel += bpp, div_x++) {
-              Uint32 mapped = 0;
-              switch(bpp) {
-                case 1:
-                  mapped = *pixel;
-                  break;
-                case 2:
-                  mapped = *(Uint16 *)pixel;
-                  break;
-                case 3:
-#if SDL_BYTEORDER == SDL_BIG_ENDIAN
-                  mapped |= pixel[0] << 16;
-                  mapped |= pixel[1] << 8;
-                  mapped |= pixel[2] << 0;
-#else
-                  mapped |= pixel[0] << 0;
-                  mapped |= pixel[1] << 8;
-                  mapped |= pixel[2] << 16;
-#endif
-                  break;
-                case 4:
-                  mapped = *(Uint32 *)pixel;
-                  break;
-              }
-              Uint8 red, green, blue, alpha;
-              SDL_GetRGBA(mapped, screen->format, &red, &green, &blue, &alpha);
-
-#ifdef BILINEAR
-              int xinc = (x + 1 != width ? 1 : 0);
-              int yinc = (y + 1 != height ? width : 0);
-              Uint8 color00[3], color01[3], color10[3], color11[3];
-              {
-                color00[0] = red_channel[loc];
-                color00[1] = green_channel[loc];
-                color00[2] = blue_channel[loc];
-              }
-              {
-                color01[0] = red_channel[loc + xinc];
-                color01[1] = green_channel[loc + xinc];
-                color01[2] = blue_channel[loc + xinc];
-              }
-              {
-                color10[0] = red_channel[loc + yinc];
-                color10[1] = green_channel[loc + yinc];
-                color10[2] = blue_channel[loc + yinc];
-              }
-              {
-                color11[0] = red_channel[loc + yinc + xinc];
-                color11[1] = green_channel[loc + yinc + xinc];
-                color11[2] = blue_channel[loc + yinc + xinc];
-              }
-              Uint8 color0[3], color1[3], color[3];
-              merge(color0, color00, color01, div_x, LIGHTMAP_DIV);
-              merge(color1, color10, color11, div_x, LIGHTMAP_DIV);
-              merge(color, color0, color1, div_y, LIGHTMAP_DIV);
-              red = (red * color[0]) >> 8;
-              green = (green * color[1]) >> 8;
-              blue = (blue * color[2]) >> 8;
-#else
-              red = (red * red_channel[loc]) >> 8;
-              green = (green * green_channel[loc]) >> 8;
-              blue = (blue * blue_channel[loc]) >> 8;
-#endif
-
-              mapped = SDL_MapRGBA(screen->format, red, green, blue, alpha);
-              switch(bpp) {
-                case 1:
-                  *pixel = mapped;
-                  break;
-                case 2:
-                  *(Uint16 *)pixel = mapped;
-                  break;
-                case 3:
-#if SDL_BYTEORDER == SDL_BIG_ENDIAN
-                  pixel[0] = (mapped >> 16) & 0xff;
-                  pixel[1] = (mapped >> 8) & 0xff;
-                  pixel[2] = (mapped >> 0) & 0xff;
-#else
-                  pixel[0] = (mapped >> 0) & 0xff;
-                  pixel[1] = (mapped >> 8) & 0xff;
-                  pixel[2] = (mapped >> 16) & 0xff;
-#endif
-                  break;
-                case 4:
-                  *(Uint32 *)pixel = mapped;
-                  break;
-              }
-            }
-            pixel += screen->pitch - LIGHTMAP_DIV * bpp;
-          }
-        }
-        div_pixel += (screen->pitch - width * bpp) * LIGHTMAP_DIV;
-      }
-      if(SDL_MUSTLOCK(screen))
-      {
-        SDL_UnlockSurface(screen);
-      }
-    }
-  }
-
-  void Lightmap::light_blit(SDL_Surface *src, SDL_Rect *src_rect, int dstx, int dsty)
-  {
-    dstx /= LIGHTMAP_DIV;
-    dsty /= LIGHTMAP_DIV;
-    int srcx = src_rect->x / LIGHTMAP_DIV;
-    int srcy = src_rect->y / LIGHTMAP_DIV;
-    int blit_width = src_rect->w / LIGHTMAP_DIV;
-    int blit_height = src_rect->h / LIGHTMAP_DIV;
-    int bpp = src->format->BytesPerPixel;
-    if(SDL_MUSTLOCK(src))
-    {
-      SDL_LockSurface(src);
-    }
-    Uint8 *pixel = (Uint8 *) src->pixels + srcy * src->pitch + srcx * bpp;
-    int loc = dsty * width + dstx;
-    for(int y = 0;y < blit_height;y++) {
-      for(int x = 0;x < blit_width;x++, pixel += bpp * LIGHTMAP_DIV, loc++) {
-        if(x + dstx < 0 || y + dsty < 0 || x + dstx >= width || y + dsty >= height)
-        {
-          continue;
-        }
-        if(red_channel[loc] == 0xff && green_channel[loc] == 0xff && blue_channel[loc] == 0xff)
-        {
-          continue;
-        }
-
-        Uint32 mapped = 0;
-        switch(bpp) {
-          case 1:
-            mapped = *pixel;
-            break;
-          case 2:
-            mapped = *(Uint16 *)pixel;
-            break;
-          case 3:
-#if SDL_BYTEORDER == SDL_BIG_ENDIAN
-            mapped |= pixel[0] << 16;
-            mapped |= pixel[1] << 8;
-            mapped |= pixel[2] << 0;
-#else
-            mapped |= pixel[0] << 0;
-            mapped |= pixel[1] << 8;
-            mapped |= pixel[2] << 16;
-#endif
-            break;
-          case 4:
-            mapped = *(Uint32 *)pixel;
-            break;
-        }
-        Uint8 red, green, blue, alpha;
-        SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha);
-
-        if(red != 0)
-        {
-          int redsum = red_channel[loc] + (red * alpha >> 8);
-          red_channel[loc] = redsum & ~0xff ? 0xff : redsum;
-        }
-        if(green != 0)
-        {
-          int greensum = green_channel[loc] + (green * alpha >> 8);
-          green_channel[loc] = greensum & ~0xff ? 0xff : greensum;
-        }
-        if(blue != 0)
-        {
-          int bluesum = blue_channel[loc] + (blue * alpha >> 8);
-          blue_channel[loc] = bluesum & ~0xff ? 0xff : bluesum;
-        }
-      }
-      pixel += (src->pitch - blit_width * bpp) * LIGHTMAP_DIV;
-      loc += width - blit_width;
-    }
-    if(SDL_MUSTLOCK(src))
-    {
-      SDL_UnlockSurface(src);
-    }
-  }
-
-  /*void Lightmap::light_blit(SDL_Surface *src, SDL_Rect *src_rect, int dstx, int dsty)
-  {
-    int bpp = src->format->BytesPerPixel;
-    if(SDL_MUSTLOCK(src))
-    {
-      SDL_LockSurface(src);
-    }
-    Uint8 *pixel = (Uint8 *) src->pixels + src_rect->y * src->pitch + src_rect->x * bpp;
-    int loc = dsty * width + dstx;
-    for(int y = 0;y < src_rect->h;y++) {
-      for(int x = 0;x < src_rect->w;x++, pixel += bpp, loc++) {
-        if(x + dstx < 0 || y + dsty < 0 || x + dstx >= width || y + dsty >= height)
-        {
-          continue;
-        }
-        if(red_channel[loc] == 0xff && green_channel[loc] == 0xff && blue_channel[loc] == 0xff)
-        {
-          continue;
-        }
-
-        Uint32 mapped = 0;
-        switch(bpp) {
-          case 1:
-            mapped = *pixel;
-            break;
-          case 2:
-            mapped = *(Uint16 *)pixel;
-            break;
-          case 3:
-#if SDL_BYTEORDER == SDL_BIG_ENDIAN
-            mapped |= pixel[0] << 16;
-            mapped |= pixel[1] << 8;
-            mapped |= pixel[2] << 0;
-#else
-            mapped |= pixel[0] << 0;
-            mapped |= pixel[1] << 8;
-            mapped |= pixel[2] << 16;
-#endif
-            break;
-          case 4:
-            mapped = *(Uint32 *)pixel;
-            break;
-        }
-        Uint8 red, green, blue, alpha;
-        SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha);
-
-        if(red != 0)
-        {
-          int redsum = red_channel[loc] + (red * alpha >> 8);
-          red_channel[loc] = redsum & ~0xff ? 0xff : redsum;
-        }
-        if(green != 0)
-        {
-          int greensum = green_channel[loc] + (green * alpha >> 8);
-          green_channel[loc] = greensum & ~0xff ? 0xff : greensum;
-        }
-        if(blue != 0)
-        {
-          int bluesum = blue_channel[loc] + (blue * alpha >> 8);
-          blue_channel[loc] = bluesum & ~0xff ? 0xff : bluesum;
-        }
-      }
-      pixel += src->pitch - src_rect->w * bpp;
-      loc += width - src_rect->w;
-    }
-    if(SDL_MUSTLOCK(src))
-    {
-      SDL_UnlockSurface(src);
-    }
-  }*/
-
-  void
-  Lightmap::draw_surface(const DrawingRequest& request)
-  {
-    if((request.color.red == 0.0 && request.color.green == 0.0 && request.color.blue == 0.0) || request.color.alpha == 0.0 || request.alpha == 0.0)
-    {
-      return;
-    }
-    //FIXME: support parameters request.alpha, request.angle, request.blend
-    const Surface* surface = (const Surface*) request.request_data;
-    SDL::Texture *sdltexture = dynamic_cast<SDL::Texture *>(surface->get_texture());
-    SDL::SurfaceData *surface_data = reinterpret_cast<SDL::SurfaceData *>(surface->get_surface_data());
-
-    DrawingEffect effect = request.drawing_effect;
-    if (surface->get_flipx()) effect = HORIZONTAL_FLIP;
-
-    SDL_Surface *transform = sdltexture->get_transform(request.color, effect);
-
-    // get and check SDL_Surface
-    if (transform == 0) {
-      std::cerr << "Warning: Tried to draw NULL surface, skipped draw" << std::endl;
-      return;
-    }  
-
-    SDL_Rect *src_rect = surface_data->get_src_rect(effect);
-    int dstx = (int) request.pos.x * numerator / denominator;
-    int dsty = (int) request.pos.y * numerator / denominator;
-    light_blit(transform, src_rect, dstx, dsty);
-  }
-
-  void
-  Lightmap::draw_surface_part(const DrawingRequest& request)
-  {
-    const SurfacePartRequest* surfacepartrequest
-      = (SurfacePartRequest*) request.request_data;
-
-    const Surface* surface = surfacepartrequest->surface;
-    SDL::Texture *sdltexture = dynamic_cast<SDL::Texture *>(surface->get_texture());
-
-    DrawingEffect effect = request.drawing_effect;
-    if (surface->get_flipx()) effect = HORIZONTAL_FLIP;
-
-    SDL_Surface *transform = sdltexture->get_transform(Color(1.0, 1.0, 1.0), effect);
-
-    // get and check SDL_Surface
-    if (transform == 0) {
-      std::cerr << "Warning: Tried to draw NULL surface, skipped draw" << std::endl;
-      return;
-    }  
-
-    int ox, oy;
-    if (effect == HORIZONTAL_FLIP)
-    {
-      ox = sdltexture->get_texture_width() - surface->get_x() - (int) surfacepartrequest->size.x;
-    }
-    else
-    {
-      ox = surface->get_x();
-    }
-    if (effect == VERTICAL_FLIP)
-    {
-      oy = sdltexture->get_texture_height() - surface->get_y() - (int) surfacepartrequest->size.y;
-    }
-    else
-    {
-      oy = surface->get_y();
-    }
-
-    SDL_Rect src_rect;
-    src_rect.x = (ox + (int) surfacepartrequest->source.x) * numerator / denominator;
-    src_rect.y = (oy + (int) surfacepartrequest->source.y) * numerator / denominator;
-    src_rect.w = (int) surfacepartrequest->size.x * numerator / denominator;
-    src_rect.h = (int) surfacepartrequest->size.y * numerator / denominator;
-    int dstx = (int) request.pos.x * numerator / denominator;
-    int dsty = (int) request.pos.y * numerator / denominator;
-    light_blit(transform, &src_rect, dstx, dsty);
-  }
-
-  void
-  Lightmap::draw_gradient(const DrawingRequest& request)
-  {
-    const GradientRequest* gradientrequest 
-      = (GradientRequest*) request.request_data;
-    const Color& top = gradientrequest->top;
-    const Color& bottom = gradientrequest->bottom;
-
-    int loc = 0;
-    for(int y = 0;y < height;++y)
-    {
-      Uint8 red = (Uint8)((((float)(top.red-bottom.red)/(0-height)) * y + top.red) * 255);
-      Uint8 green = (Uint8)((((float)(top.green-bottom.green)/(0-height)) * y + top.green) * 255);
-      Uint8 blue = (Uint8)((((float)(top.blue-bottom.blue)/(0-height)) * y + top.blue) * 255);
-      Uint8 alpha = (Uint8)((((float)(top.alpha-bottom.alpha)/(0-height)) * y + top.alpha) * 255);
-      for(int x = 0;x < width;x++, loc++) {
-        if(red != 0)
-        {
-          int redsum = red_channel[loc] + (red * alpha >> 8);
-          red_channel[loc] = redsum & ~0xff ? 0xff : redsum;
-        }
-        if(green != 0)
-        {
-          int greensum = green_channel[loc] + (green * alpha >> 8);
-          green_channel[loc] = greensum & ~0xff ? 0xff : greensum;
-        }
-        if(blue != 0)
-        {
-          int bluesum = blue_channel[loc] + (blue * alpha >> 8);
-          blue_channel[loc] = bluesum & ~0xff ? 0xff : bluesum;
-        }
-      }
-    }
-  }
-
-  void
-  Lightmap::draw_filled_rect(const DrawingRequest& request)
-  {
-    const FillRectRequest* fillrectrequest
-      = (FillRectRequest*) request.request_data;
-
-    int rect_x = (int) (request.pos.x * width / SCREEN_WIDTH);
-    int rect_y = (int) (request.pos.y * height / SCREEN_HEIGHT);
-    int rect_w = (int) (fillrectrequest->size.x * width / SCREEN_WIDTH);
-    int rect_h = (int) (fillrectrequest->size.y * height / SCREEN_HEIGHT);
-    Uint8 red = (Uint8) (fillrectrequest->color.red * fillrectrequest->color.alpha * 255);
-    Uint8 green = (Uint8) (fillrectrequest->color.green * fillrectrequest->color.alpha * 255);
-    Uint8 blue = (Uint8) (fillrectrequest->color.blue * fillrectrequest->color.alpha * 255);
-    if(red == 0 && green == 0 && blue == 0)
-    {
-      return;
-    }
-    for(int y = rect_y;y < rect_y + rect_h;y++) {
-      for(int x = rect_x;x < rect_x + rect_w;x++) {
-        int loc = y * width + x;
-        if(red != 0)
-        {
-          int redsum = red_channel[loc] + red;
-          red_channel[loc] = redsum & ~0xff ? 0xff : redsum;
-        }
-        if(green != 0)
-        {
-          int greensum = green_channel[loc] + green;
-          green_channel[loc] = greensum & ~0xff ? 0xff : greensum;
-        }
-        if(blue != 0)
-        {
-          int bluesum = blue_channel[loc] + blue;
-          blue_channel[loc] = bluesum & ~0xff ? 0xff : bluesum;
-        }
-      }
-    }
-  }
-
-  void
-  Lightmap::get_light(const DrawingRequest& request) const
-  {
-    const GetLightRequest* getlightrequest 
-      = (GetLightRequest*) request.request_data;
-
-    int x = (int) (request.pos.x * width / SCREEN_WIDTH);
-    int y = (int) (request.pos.y * height / SCREEN_HEIGHT);
-    int loc = y * width + x;
-    *(getlightrequest->color_ptr) = Color(((float)red_channel[loc])/255, ((float)green_channel[loc])/255, ((float)blue_channel[loc])/255);
-  }
-}
diff --git a/src/video/sdl_lightmap.hpp b/src/video/sdl_lightmap.hpp
deleted file mode 100644 (file)
index fbde750..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-//  $Id: sdl_lightmap.hpp 4986 2007-04-16 17:48:28Z matzeb $
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-#ifndef SUPERTUX_SDL_LIGHTMAP_H
-#define SUPERTUX_SDL_LIGHTMAP_H
-
-#include <SDL_video.h>
-
-#include "lightmap.hpp"
-
-class Color;
-struct DrawingRequest;
-
-namespace SDL
-{
-  class Lightmap : public ::Lightmap
-  {
-  public:
-    Lightmap();
-    ~Lightmap();
-
-    void start_draw(const Color &ambient_color);
-    void end_draw();
-    void do_draw();
-    void draw_surface(const DrawingRequest& request);
-    void draw_surface_part(const DrawingRequest& request);
-    void draw_text(const DrawingRequest& request);
-    void draw_gradient(const DrawingRequest& request);
-    void draw_filled_rect(const DrawingRequest& request);
-    void get_light(const DrawingRequest& request) const;
-
-  private:
-    SDL_Surface* screen;
-    Uint8 *red_channel;
-    Uint8 *blue_channel;
-    Uint8 *green_channel;
-    int width, height;
-    int numerator, denominator;
-    int LIGHTMAP_DIV;
-
-    void light_blit(SDL_Surface *src, SDL_Rect *src_rect, int dstx, int dsty);
-  };
-}
-
-#endif
-
diff --git a/src/video/sdl_renderer.cpp b/src/video/sdl_renderer.cpp
deleted file mode 100644 (file)
index dede6c8..0000000
+++ /dev/null
@@ -1,433 +0,0 @@
-//  $Id: sdl_renderer.cpp 5063 2007-05-27 11:32:00Z matzeb $
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-#include <config.h>
-
-#include <functional>
-#include <algorithm>
-#include <stdexcept>
-#include <cassert>
-#include <iostream>
-#include <SDL_image.h>
-#include <sstream>
-#include <iomanip>
-#include <physfs.h>
-
-#include "glutil.hpp"
-#include "sdl_renderer.hpp"
-#include "sdl_texture.hpp"
-#include "sdl_surface_data.hpp"
-#include "drawing_context.hpp"
-#include "drawing_request.hpp"
-#include "surface.hpp"
-#include "font.hpp"
-#include "main.hpp"
-#include "gameconfig.hpp"
-#include "log.hpp"
-#include "texture.hpp"
-#include "texture_manager.hpp"
-#include "obstack/obstackpp.hpp"
-
-namespace
-{
-  SDL_Surface *apply_alpha(SDL_Surface *src, float alpha_factor)
-  {
-    // FIXME: This is really slow
-    assert(src->format->Amask);
-    int alpha = (int) (alpha_factor * 256);
-    SDL_Surface *dst = SDL_CreateRGBSurface(src->flags, src->w, src->h, src->format->BitsPerPixel, src->format->Rmask,  src->format->Gmask, src->format->Bmask, src->format->Amask);
-    int bpp = dst->format->BytesPerPixel;
-    if(SDL_MUSTLOCK(src))
-    {
-      SDL_LockSurface(src);
-    }
-    if(SDL_MUSTLOCK(dst))
-    {
-      SDL_LockSurface(dst);
-    }
-    for(int y = 0;y < dst->h;y++) {
-      for(int x = 0;x < dst->w;x++) {
-        Uint8 *srcpixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
-        Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
-        Uint32 mapped = 0;
-        switch(bpp) {
-          case 1:
-            mapped = *srcpixel;
-            break;
-          case 2:
-            mapped = *(Uint16 *)srcpixel;
-            break;
-          case 3:
-#if SDL_BYTEORDER == SDL_BIG_ENDIAN
-            mapped |= srcpixel[0] << 16;
-            mapped |= srcpixel[1] << 8;
-            mapped |= srcpixel[2] << 0;
-#else
-            mapped |= srcpixel[0] << 0;
-            mapped |= srcpixel[1] << 8;
-            mapped |= srcpixel[2] << 16;
-#endif
-            break;
-          case 4:
-            mapped = *(Uint32 *)srcpixel;
-            break;
-        }
-        Uint8 r, g, b, a;
-        SDL_GetRGBA(mapped, src->format, &r, &g, &b, &a);
-        mapped = SDL_MapRGBA(dst->format, r, g, b, (a * alpha) >> 8);
-        switch(bpp) {
-          case 1:
-            *dstpixel = mapped;
-            break;
-          case 2:
-            *(Uint16 *)dstpixel = mapped;
-            break;
-          case 3:
-#if SDL_BYTEORDER == SDL_BIG_ENDIAN
-            dstpixel[0] = (mapped >> 16) & 0xff;
-            dstpixel[1] = (mapped >> 8) & 0xff;
-            dstpixel[2] = (mapped >> 0) & 0xff;
-#else
-            dstpixel[0] = (mapped >> 0) & 0xff;
-            dstpixel[1] = (mapped >> 8) & 0xff;
-            dstpixel[2] = (mapped >> 16) & 0xff;
-#endif
-            break;
-          case 4:
-            *(Uint32 *)dstpixel = mapped;
-            break;
-        }
-      }
-    }
-    if(SDL_MUSTLOCK(dst))
-    {
-      SDL_UnlockSurface(dst);
-    }
-    if(SDL_MUSTLOCK(src))
-    {
-      SDL_UnlockSurface(src);
-    }
-    return dst;
-  }
-}
-
-namespace SDL
-{
-  Renderer::Renderer()
-  {
-    const SDL_VideoInfo *info = SDL_GetVideoInfo();
-    log_info << "Hardware surfaces are " << (info->hw_available ? "" : "not ") << "available." << std::endl;
-    log_info << "Hardware to hardware blits are " << (info->blit_hw ? "" : "not ") << "accelerated." << std::endl;
-    log_info << "Hardware to hardware blits with colorkey are " << (info->blit_hw_CC ? "" : "not ") << "accelerated." << std::endl;
-    log_info << "Hardware to hardware blits with alpha are " << (info->blit_hw_A ? "" : "not ") << "accelerated." << std::endl;
-    log_info << "Software to hardware blits are " << (info->blit_sw ? "" : "not ") << "accelerated." << std::endl;
-    log_info << "Software to hardware blits with colorkey are " << (info->blit_sw_CC ? "" : "not ") << "accelerated." << std::endl;
-    log_info << "Software to hardware blits with alpha are " << (info->blit_sw_A ? "" : "not ") << "accelerated." << std::endl;
-    log_info << "Color fills are " << (info->blit_fill ? "" : "not ") << "accelerated." << std::endl;
-
-    int flags = SDL_SWSURFACE | SDL_ANYFORMAT;
-    if(config->use_fullscreen)
-      flags |= SDL_FULLSCREEN;
-    int width = config->screenwidth;
-    int height = config->screenheight;
-
-    screen = SDL_SetVideoMode(width, height, 0, flags);
-    if(screen == 0) {
-      std::stringstream msg;
-      msg << "Couldn't set video mode (" << width << "x" << height
-          << "): " << SDL_GetError();
-      throw std::runtime_error(msg.str());
-    }
-
-    float xfactor = (float) config->screenwidth / SCREEN_WIDTH;
-    float yfactor = (float) config->screenheight / SCREEN_HEIGHT;
-    if(xfactor < yfactor)
-    {
-      numerator = config->screenwidth;
-      denominator = SCREEN_WIDTH;
-    }
-    else
-    {
-      numerator = config->screenheight;
-      denominator = SCREEN_HEIGHT;
-    }
-
-    if(texture_manager == 0)
-      texture_manager = new TextureManager();
-  }
-
-  Renderer::~Renderer()
-  {
-  }
-
-  void
-  Renderer::draw_surface(const DrawingRequest& request)
-  {
-    //FIXME: support parameters request.alpha, request.angle, request.blend
-    const Surface* surface = (const Surface*) request.request_data;
-    SDL::Texture *sdltexture = dynamic_cast<SDL::Texture *>(surface->get_texture());
-    SDL::SurfaceData *surface_data = reinterpret_cast<SDL::SurfaceData *>(surface->get_surface_data());
-
-    DrawingEffect effect = request.drawing_effect;
-    if (surface->get_flipx()) effect = HORIZONTAL_FLIP;
-
-    SDL_Surface *transform = sdltexture->get_transform(request.color, effect);
-
-    // get and check SDL_Surface
-    if (transform == 0) {
-      std::cerr << "Warning: Tried to draw NULL surface, skipped draw" << std::endl;
-      return;
-    }  
-
-    SDL_Rect *src_rect = surface_data->get_src_rect(effect);
-    SDL_Rect dst_rect;
-    dst_rect.x = (int) request.pos.x * numerator / denominator;
-    dst_rect.y = (int) request.pos.y * numerator / denominator;
-
-    Uint8 alpha = 0;
-    if(request.alpha != 1.0)
-    {
-      if(!transform->format->Amask)
-      {
-        if(transform->flags & SDL_SRCALPHA)
-        {
-          alpha = transform->format->alpha;
-        }
-        else
-        {
-          alpha = 255;
-        }
-        SDL_SetAlpha(transform, SDL_SRCALPHA, (Uint8) (request.alpha * alpha));
-      }
-      /*else
-      {
-        transform = apply_alpha(transform, request.alpha);
-      }*/
-    }
-
-    SDL_BlitSurface(transform, src_rect, screen, &dst_rect);
-
-    if(request.alpha != 1.0)
-    {
-      if(!transform->format->Amask)
-      {
-        if(alpha == 255)
-        {
-          SDL_SetAlpha(transform, SDL_RLEACCEL, 0);
-        }
-        else
-        {
-          SDL_SetAlpha(transform, SDL_SRCALPHA | SDL_RLEACCEL, alpha);
-        }
-      }
-      /*else
-      {
-        SDL_FreeSurface(transform);
-      }*/
-    }
-  }
-
-  void
-  Renderer::draw_surface_part(const DrawingRequest& request)
-  {
-    const SurfacePartRequest* surfacepartrequest
-      = (SurfacePartRequest*) request.request_data;
-
-    const Surface* surface = surfacepartrequest->surface;
-    SDL::Texture *sdltexture = dynamic_cast<SDL::Texture *>(surface->get_texture());
-
-    DrawingEffect effect = request.drawing_effect;
-    if (surface->get_flipx()) effect = HORIZONTAL_FLIP;
-
-    SDL_Surface *transform = sdltexture->get_transform(Color(1.0, 1.0, 1.0), effect);
-
-    // get and check SDL_Surface
-    if (transform == 0) {
-      std::cerr << "Warning: Tried to draw NULL surface, skipped draw" << std::endl;
-      return;
-    }  
-
-    int ox, oy;
-    if (effect == HORIZONTAL_FLIP)
-    {
-      ox = sdltexture->get_texture_width() - surface->get_x() - (int) surfacepartrequest->size.x;
-    }
-    else
-    {
-      ox = surface->get_x();
-    }
-    if (effect == VERTICAL_FLIP)
-    {
-      oy = sdltexture->get_texture_height() - surface->get_y() - (int) surfacepartrequest->size.y;
-    }
-    else
-    {
-      oy = surface->get_y();
-    }
-
-    SDL_Rect src_rect;
-    src_rect.x = (ox + (int) surfacepartrequest->source.x) * numerator / denominator;
-    src_rect.y = (oy + (int) surfacepartrequest->source.y) * numerator / denominator;
-    src_rect.w = (int) surfacepartrequest->size.x * numerator / denominator;
-    src_rect.h = (int) surfacepartrequest->size.y * numerator / denominator;
-
-    SDL_Rect dst_rect;
-    dst_rect.x = (int) request.pos.x * numerator / denominator;
-    dst_rect.y = (int) request.pos.y * numerator / denominator;
-
-    Uint8 alpha = 0;
-    if(request.alpha != 1.0)
-    {
-      if(!transform->format->Amask)
-      {
-        if(transform->flags & SDL_SRCALPHA)
-        {
-          alpha = transform->format->alpha;
-        }
-        else
-        {
-          alpha = 255;
-        }
-        SDL_SetAlpha(transform, SDL_SRCALPHA, (Uint8) (request.alpha * alpha));
-      }
-      /*else
-      {
-        transform = apply_alpha(transform, request.alpha);
-      }*/
-    }
-
-    SDL_BlitSurface(transform, &src_rect, screen, &dst_rect);
-
-    if(request.alpha != 1.0)
-    {
-      if(!transform->format->Amask)
-      {
-        if(alpha == 255)
-        {
-          SDL_SetAlpha(transform, SDL_RLEACCEL, 0);
-        }
-        else
-        {
-          SDL_SetAlpha(transform, SDL_SRCALPHA | SDL_RLEACCEL, alpha);
-        }
-      }
-      /*else
-      {
-        SDL_FreeSurface(transform);
-      }*/
-    }
-  }
-
-  void
-  Renderer::draw_gradient(const DrawingRequest& request)
-  {
-    const GradientRequest* gradientrequest 
-      = (GradientRequest*) request.request_data;
-    const Color& top = gradientrequest->top;
-    const Color& bottom = gradientrequest->bottom;
-
-    for(int y = 0;y < screen->h;++y)
-    {
-      Uint8 r = (Uint8)((((float)(top.red-bottom.red)/(0-screen->h)) * y + top.red) * 255);
-      Uint8 g = (Uint8)((((float)(top.green-bottom.green)/(0-screen->h)) * y + top.green) * 255);
-      Uint8 b = (Uint8)((((float)(top.blue-bottom.blue)/(0-screen->h)) * y + top.blue) * 255);
-      Uint8 a = (Uint8)((((float)(top.alpha-bottom.alpha)/(0-screen->h)) * y + top.alpha) * 255);
-      Uint32 color = SDL_MapRGB(screen->format, r, g, b);
-
-      SDL_Rect rect;
-      rect.x = 0;
-      rect.y = y;
-      rect.w = screen->w;
-      rect.h = 1;
-
-      if(a == SDL_ALPHA_OPAQUE) {
-        SDL_FillRect(screen, &rect, color);
-      } else if(a != SDL_ALPHA_TRANSPARENT) {
-        SDL_Surface *temp = SDL_CreateRGBSurface(screen->flags, rect.w, rect.h, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
-
-        SDL_FillRect(temp, 0, color);
-        SDL_SetAlpha(temp, SDL_SRCALPHA | SDL_RLEACCEL, a);
-        SDL_BlitSurface(temp, 0, screen, &rect);
-        SDL_FreeSurface(temp);
-      }
-    }
-  }
-
-  void
-  Renderer::draw_filled_rect(const DrawingRequest& request)
-  {
-    const FillRectRequest* fillrectrequest
-      = (FillRectRequest*) request.request_data;
-
-    SDL_Rect rect;
-    rect.x = (Sint16)request.pos.x * screen->w / SCREEN_WIDTH;
-    rect.y = (Sint16)request.pos.y * screen->h / SCREEN_HEIGHT;
-    rect.w = (Uint16)fillrectrequest->size.x * screen->w / SCREEN_WIDTH;
-    rect.h = (Uint16)fillrectrequest->size.y * screen->h / SCREEN_HEIGHT;
-    Uint8 r = static_cast<Uint8>(fillrectrequest->color.red * 255);
-    Uint8 g = static_cast<Uint8>(fillrectrequest->color.green * 255);
-    Uint8 b = static_cast<Uint8>(fillrectrequest->color.blue * 255);
-    Uint8 a = static_cast<Uint8>(fillrectrequest->color.alpha * 255);
-    Uint32 color = SDL_MapRGB(screen->format, r, g, b);
-    if(a == SDL_ALPHA_OPAQUE) {
-      SDL_FillRect(screen, &rect, color);
-    } else if(a != SDL_ALPHA_TRANSPARENT) {
-      SDL_Surface *temp = SDL_CreateRGBSurface(screen->flags, rect.w, rect.h, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
-
-      SDL_FillRect(temp, 0, color);
-      SDL_SetAlpha(temp, SDL_SRCALPHA | SDL_RLEACCEL, a);
-      SDL_BlitSurface(temp, 0, screen, &rect);
-      SDL_FreeSurface(temp);
-    }
-  }
-
-  void 
-  Renderer::do_take_screenshot()
-  {
-    // [Christoph] TODO: Yes, this method also takes care of the actual disk I/O. Split it?
-
-    SDL_Surface *screen = SDL_GetVideoSurface();
-
-    // save screenshot
-    static const std::string writeDir = PHYSFS_getWriteDir();
-    static const std::string dirSep = PHYSFS_getDirSeparator();
-    static const std::string baseName = "screenshot";
-    static const std::string fileExt = ".bmp";
-    std::string fullFilename;
-    for (int num = 0; num < 1000; num++) {
-      std::ostringstream oss;
-      oss << baseName;
-      oss << std::setw(3) << std::setfill('0') << num;
-      oss << fileExt;
-      std::string fileName = oss.str();
-      fullFilename = writeDir + dirSep + fileName;
-      if (!PHYSFS_exists(fileName.c_str())) {
-        SDL_SaveBMP(screen, fullFilename.c_str());
-        log_debug << "Wrote screenshot to \"" << fullFilename << "\"" << std::endl;
-        return;
-      }
-    }
-    log_warning << "Did not save screenshot, because all files up to \"" << fullFilename << "\" already existed" << std::endl;
-  }
-
-  void
-  Renderer::flip()
-  {
-    SDL_Flip(screen);
-  }
-}
diff --git a/src/video/sdl_renderer.hpp b/src/video/sdl_renderer.hpp
deleted file mode 100644 (file)
index 24dcb84..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-//  $Id: sdl_renderer.hpp 4986 2007-04-16 17:48:28Z matzeb $
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-#ifndef SUPERTUX_SDL_RENDERER_H
-#define SUPERTUX_SDL_RENDERER_H
-
-#include <SDL_video.h>
-
-#include "renderer.hpp"
-
-namespace SDL
-{
-  class Renderer : public ::Renderer
-  {
-  public:
-    Renderer();
-    ~Renderer();
-
-    void draw_surface(const DrawingRequest& request);
-    void draw_surface_part(const DrawingRequest& request);
-    void draw_text(const DrawingRequest& request);
-    void draw_gradient(const DrawingRequest& request);
-    void draw_filled_rect(const DrawingRequest& request);
-    void do_take_screenshot();
-    void flip();
-  private:
-    SDL_Surface *screen;
-    int numerator, denominator;
-  };
-}
-
-#endif
-
diff --git a/src/video/sdl_surface_data.hpp b/src/video/sdl_surface_data.hpp
deleted file mode 100644 (file)
index 1e46e68..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-//  $Id: gl_surface_data.hpp 4063 2006-07-21 21:05:23Z anmaster $
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-#ifndef __SDL_SURFACE_DATA_HPP__
-#define __SDL_SURFACE_DATA_HPP__
-
-#include <config.h>
-
-#include "surface.hpp"
-#include "texture.hpp"
-#include "main.hpp"
-#include "gameconfig.hpp"
-
-namespace SDL
-{
-  class SurfaceData
-  {
-  private:
-    const Surface &surface;
-    SDL_Rect src_rects[NUM_EFFECTS];
-
-  public:
-    SurfaceData(const Surface &surface) :
-      surface(surface)
-    {
-      int numerator, denominator;
-      float xfactor = (float) config->screenwidth / SCREEN_WIDTH;
-      float yfactor = (float) config->screenheight / SCREEN_HEIGHT;
-      if(xfactor < yfactor)
-      {
-        numerator = config->screenwidth;
-        denominator = SCREEN_WIDTH;
-      }
-      else
-      {
-        numerator = config->screenheight;
-        denominator = SCREEN_HEIGHT;
-      }
-
-      src_rects[NO_EFFECT].x = surface.get_x() * numerator / denominator;
-      src_rects[NO_EFFECT].y = surface.get_y() * numerator / denominator;
-      src_rects[NO_EFFECT].w = surface.get_width() * numerator / denominator;
-      src_rects[NO_EFFECT].h = surface.get_height() * numerator / denominator;
-
-      int flipped_x = surface.get_texture()->get_texture_width() - surface.get_x() - surface.get_width();
-      src_rects[HORIZONTAL_FLIP].x = flipped_x * numerator / denominator;
-      src_rects[HORIZONTAL_FLIP].y = surface.get_y() * numerator / denominator;
-      src_rects[HORIZONTAL_FLIP].w = surface.get_width() * numerator / denominator;
-      src_rects[HORIZONTAL_FLIP].h = surface.get_height() * numerator / denominator;
-
-      int flipped_y = surface.get_texture()->get_texture_height() - surface.get_y() - surface.get_height();
-      src_rects[VERTICAL_FLIP].x = flipped_y * numerator / denominator;
-      src_rects[VERTICAL_FLIP].y = surface.get_y() * numerator / denominator;
-      src_rects[VERTICAL_FLIP].w = surface.get_width() * numerator / denominator;
-      src_rects[VERTICAL_FLIP].h = surface.get_height() * numerator / denominator;
-    }
-
-    SDL_Rect *get_src_rect(DrawingEffect effect)
-    {
-      return src_rects + effect;
-    }
-  };
-}
-
-#endif
diff --git a/src/video/sdl_texture.cpp b/src/video/sdl_texture.cpp
deleted file mode 100644 (file)
index 2164550..0000000
+++ /dev/null
@@ -1,658 +0,0 @@
-//  $Id: sdl_texture.cpp 4063 2006-07-21 21:05:23Z anmaster $
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-#include <config.h>
-
-#include "sdl_texture.hpp"
-#include "color.hpp"
-#include "gameconfig.hpp"
-#include "main.hpp"
-
-#include <assert.h>
-
-#include <SDL.h>
-
-namespace
-{
-#define BILINEAR
-
-#ifdef NAIVE
-  SDL_Surface *scale(SDL_Surface *src, int numerator, int denominator)
-  {
-    if(numerator == denominator)
-    {
-      src->refcount++;
-      return src;
-    }
-    else
-    {
-      SDL_Surface *dst = SDL_CreateRGBSurface(src->flags, src->w * numerator / denominator, src->h * numerator / denominator, src->format->BitsPerPixel, src->format->Rmask,  src->format->Gmask, src->format->Bmask, src->format->Amask);
-      int bpp = dst->format->BytesPerPixel;
-      if(SDL_MUSTLOCK(src))
-      {
-        SDL_LockSurface(src);
-      }
-      if(SDL_MUSTLOCK(dst))
-      {
-        SDL_LockSurface(dst);
-      }
-      for(int y = 0;y < dst->h;y++) {
-        for(int x = 0;x < dst->w;x++) {
-          Uint8 *srcpixel = (Uint8 *) src->pixels + (y * denominator / numerator) * src->pitch + (x * denominator / numerator) * bpp;
-          Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
-          switch(bpp) {
-            case 4:
-              dstpixel[3] = srcpixel[3];
-            case 3:
-              dstpixel[2] = srcpixel[2];
-            case 2:
-              dstpixel[1] = srcpixel[1];
-            case 1:
-              dstpixel[0] = srcpixel[0];
-          }
-        }
-      }
-      if(SDL_MUSTLOCK(dst))
-      {
-        SDL_UnlockSurface(dst);
-      }
-      if(SDL_MUSTLOCK(src))
-      {
-        SDL_UnlockSurface(src);
-      }
-      if(!src->format->Amask)
-      {
-        if(src->flags & SDL_SRCALPHA)
-        {
-          SDL_SetAlpha(dst, SDL_SRCALPHA | SDL_RLEACCEL, src->format->alpha);
-        }
-        if(src->flags & SDL_SRCCOLORKEY)
-        {
-          SDL_SetColorKey(dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, src->format->colorkey);
-        }
-      }
-      return dst;
-    }
-  }
-#endif
-
-#ifdef BILINEAR
-  void getpixel(SDL_Surface *src, int srcx, int srcy, Uint8 color[4])
-  {
-    int bpp = src->format->BytesPerPixel;
-    if(srcx == src->w)
-    {
-      srcx--;
-    }
-    if(srcy == src->h)
-    {
-      srcy--;
-    }
-    Uint8 *srcpixel = (Uint8 *) src->pixels + srcy * src->pitch + srcx * bpp;
-    Uint32 mapped = 0;
-    switch(bpp) {
-      case 1:
-        mapped = *srcpixel;
-        break;
-      case 2:
-        mapped = *(Uint16 *)srcpixel;
-        break;
-      case 3:
-#if SDL_BYTEORDER == SDL_BIG_ENDIAN
-        mapped |= srcpixel[0] << 16;
-        mapped |= srcpixel[1] << 8;
-        mapped |= srcpixel[2] << 0;
-#else
-        mapped |= srcpixel[0] << 0;
-        mapped |= srcpixel[1] << 8;
-        mapped |= srcpixel[2] << 16;
-#endif
-        break;
-      case 4:
-        mapped = *(Uint32 *)srcpixel;
-        break;
-    }
-    SDL_GetRGBA(mapped, src->format, &color[0], &color[1], &color[2], &color[3]);
-  }
-
-  void merge(Uint8 color[4], Uint8 color0[4], Uint8 color1[4], int rem, int total)
-  {
-    color[0] = (color0[0] * (total - rem) + color1[0] * rem) / total;
-    color[1] = (color0[1] * (total - rem) + color1[1] * rem) / total;
-    color[2] = (color0[2] * (total - rem) + color1[2] * rem) / total;
-    color[3] = (color0[3] * (total - rem) + color1[3] * rem) / total;
-  }
-
-  SDL_Surface *scale(SDL_Surface *src, int numerator, int denominator)
-  {
-    if(numerator == denominator)
-    {
-      src->refcount++;
-      return src;
-    }
-    else
-    {
-      SDL_Surface *dst = SDL_CreateRGBSurface(src->flags, src->w * numerator / denominator, src->h * numerator / denominator, src->format->BitsPerPixel, src->format->Rmask,  src->format->Gmask, src->format->Bmask, src->format->Amask);
-      int bpp = dst->format->BytesPerPixel;
-      if(SDL_MUSTLOCK(src))
-      {
-        SDL_LockSurface(src);
-      }
-      if(SDL_MUSTLOCK(dst))
-      {
-        SDL_LockSurface(dst);
-      }
-      for(int y = 0;y < dst->h;y++) {
-        for(int x = 0;x < dst->w;x++) {
-          int srcx = x * denominator / numerator;
-          int srcy = y * denominator / numerator;
-          Uint8 color00[4], color01[4], color10[4], color11[4];
-          getpixel(src, srcx, srcy, color00);
-          getpixel(src, srcx + 1, srcy, color01);
-          getpixel(src, srcx, srcy + 1, color10);
-          getpixel(src, srcx + 1, srcy + 1, color11);
-          Uint8 color0[4], color1[4], color[4];
-          int remx = x * denominator % numerator;
-          merge(color0, color00, color01, remx, numerator);
-          merge(color1, color10, color11, remx, numerator);
-          int remy = y * denominator % numerator;
-          merge(color, color0, color1, remy, numerator);
-          Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
-          Uint32 mapped = SDL_MapRGBA(dst->format, color[0], color[1], color[2], color[3]);
-          switch(bpp) {
-            case 1:
-              *dstpixel = mapped;
-              break;
-            case 2:
-              *(Uint16 *)dstpixel = mapped;
-              break;
-            case 3:
-#if SDL_BYTEORDER == SDL_BIG_ENDIAN
-              dstpixel[0] = (mapped >> 16) & 0xff;
-              dstpixel[1] = (mapped >> 8) & 0xff;
-              dstpixel[2] = (mapped >> 0) & 0xff;
-#else
-              dstpixel[0] = (mapped >> 0) & 0xff;
-              dstpixel[1] = (mapped >> 8) & 0xff;
-              dstpixel[2] = (mapped >> 16) & 0xff;
-#endif
-              break;
-            case 4:
-              *(Uint32 *)dstpixel = mapped;
-              break;
-          }
-        }
-      }
-      if(SDL_MUSTLOCK(dst))
-      {
-        SDL_UnlockSurface(dst);
-      }
-      if(SDL_MUSTLOCK(src))
-      {
-        SDL_UnlockSurface(src);
-      }
-      if(!src->format->Amask)
-      {
-        if(src->flags & SDL_SRCALPHA)
-        {
-          SDL_SetAlpha(dst, SDL_SRCALPHA | SDL_RLEACCEL, src->format->alpha);
-        }
-        if(src->flags & SDL_SRCCOLORKEY)
-        {
-          SDL_SetColorKey(dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, src->format->colorkey);
-        }
-      }
-      return dst;
-    }
-  }
-#endif
-
-  SDL_Surface *horz_flip(SDL_Surface *src)
-  {
-    SDL_Surface *dst = SDL_CreateRGBSurface(src->flags, src->w, src->h, src->format->BitsPerPixel, src->format->Rmask,  src->format->Gmask, src->format->Bmask, src->format->Amask);
-    int bpp = dst->format->BytesPerPixel;
-    if(SDL_MUSTLOCK(src))
-    {
-      SDL_LockSurface(src);
-    }
-    if(SDL_MUSTLOCK(dst))
-    {
-      SDL_LockSurface(dst);
-    }
-    for(int y = 0;y < dst->h;y++) {
-      for(int x = 0;x < dst->w;x++) {
-        Uint8 *srcpixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
-        Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + (dst->w - x - 1) * bpp;
-        switch(bpp) {
-          case 4:
-            dstpixel[3] = srcpixel[3];
-          case 3:
-            dstpixel[2] = srcpixel[2];
-          case 2:
-            dstpixel[1] = srcpixel[1];
-          case 1:
-            dstpixel[0] = srcpixel[0];
-        }
-      }
-    }
-    if(SDL_MUSTLOCK(dst))
-    {
-      SDL_UnlockSurface(dst);
-    }
-    if(SDL_MUSTLOCK(src))
-    {
-      SDL_UnlockSurface(src);
-    }
-    if(!src->format->Amask)
-    {
-      if(src->flags & SDL_SRCALPHA)
-      {
-        SDL_SetAlpha(dst, SDL_SRCALPHA | SDL_RLEACCEL, src->format->alpha);
-      }
-      if(src->flags & SDL_SRCCOLORKEY)
-      {
-        SDL_SetColorKey(dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, src->format->colorkey);
-      }
-    }
-    return dst;
-  }
-
-  SDL_Surface *vert_flip(SDL_Surface *src)
-  {
-    SDL_Surface *dst = SDL_CreateRGBSurface(src->flags, src->w, src->h, src->format->BitsPerPixel, src->format->Rmask,  src->format->Gmask, src->format->Bmask, src->format->Amask);
-    int bpp = dst->format->BytesPerPixel;
-    if(SDL_MUSTLOCK(src))
-    {
-      SDL_LockSurface(src);
-    }
-    if(SDL_MUSTLOCK(dst))
-    {
-      SDL_LockSurface(dst);
-    }
-    for(int y = 0;y < dst->h;y++) {
-      for(int x = 0;x < dst->w;x++) {
-        Uint8 *srcpixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
-        Uint8 *dstpixel = (Uint8 *) dst->pixels + (dst->h - y - 1) * dst->pitch + x * bpp;
-        switch(bpp) {
-          case 4:
-            dstpixel[3] = srcpixel[3];
-          case 3:
-            dstpixel[2] = srcpixel[2];
-          case 2:
-            dstpixel[1] = srcpixel[1];
-          case 1:
-            dstpixel[0] = srcpixel[0];
-        }
-      }
-    }
-    if(SDL_MUSTLOCK(dst))
-    {
-      SDL_UnlockSurface(dst);
-    }
-    if(SDL_MUSTLOCK(src))
-    {
-      SDL_UnlockSurface(src);
-    }
-    if(!src->format->Amask)
-    {
-      if(src->flags & SDL_SRCALPHA)
-      {
-        SDL_SetAlpha(dst, SDL_SRCALPHA | SDL_RLEACCEL, src->format->alpha);
-      }
-      if(src->flags & SDL_SRCCOLORKEY)
-      {
-        SDL_SetColorKey(dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, src->format->colorkey);
-      }
-    }
-    return dst;
-  }
-
-  SDL_Surface *colorize(SDL_Surface *src, const Color &color)
-  {
-    // FIXME: This is really slow
-    assert(color.red != 1.0 || color.green != 1.0 || color.blue != 1.0);
-    int red = (int) (color.red * 256);
-    int green = (int) (color.green * 256);
-    int blue = (int) (color.blue * 256);
-    SDL_Surface *dst = SDL_CreateRGBSurface(src->flags, src->w, src->h, src->format->BitsPerPixel, src->format->Rmask,  src->format->Gmask, src->format->Bmask, src->format->Amask);
-    int bpp = dst->format->BytesPerPixel;
-    if(SDL_MUSTLOCK(src))
-    {
-      SDL_LockSurface(src);
-    }
-    if(SDL_MUSTLOCK(dst))
-    {
-      SDL_LockSurface(dst);
-    }
-    for(int y = 0;y < dst->h;y++) {
-      for(int x = 0;x < dst->w;x++) {
-        Uint8 *srcpixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
-        Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
-        Uint32 mapped = 0;
-        switch(bpp) {
-          case 1:
-            mapped = *srcpixel;
-            break;
-          case 2:
-            mapped = *(Uint16 *)srcpixel;
-            break;
-          case 3:
-#if SDL_BYTEORDER == SDL_BIG_ENDIAN
-            mapped |= srcpixel[0] << 16;
-            mapped |= srcpixel[1] << 8;
-            mapped |= srcpixel[2] << 0;
-#else
-            mapped |= srcpixel[0] << 0;
-            mapped |= srcpixel[1] << 8;
-            mapped |= srcpixel[2] << 16;
-#endif
-            break;
-          case 4:
-            mapped = *(Uint32 *)srcpixel;
-            break;
-        }
-        if(src->format->Amask || !(src->flags & SDL_SRCCOLORKEY) || mapped != src->format->colorkey)
-        {
-          Uint8 r, g, b, a;
-          SDL_GetRGBA(mapped, src->format, &r, &g, &b, &a);
-          mapped = SDL_MapRGBA(dst->format, (r * red) >> 8, (g * green) >> 8, (b * blue) >> 8, a);
-        }
-        switch(bpp) {
-          case 1:
-            *dstpixel = mapped;
-            break;
-          case 2:
-            *(Uint16 *)dstpixel = mapped;
-            break;
-          case 3:
-#if SDL_BYTEORDER == SDL_BIG_ENDIAN
-            dstpixel[0] = (mapped >> 16) & 0xff;
-            dstpixel[1] = (mapped >> 8) & 0xff;
-            dstpixel[2] = (mapped >> 0) & 0xff;
-#else
-            dstpixel[0] = (mapped >> 0) & 0xff;
-            dstpixel[1] = (mapped >> 8) & 0xff;
-            dstpixel[2] = (mapped >> 16) & 0xff;
-#endif
-            break;
-          case 4:
-            *(Uint32 *)dstpixel = mapped;
-            break;
-        }
-      }
-    }
-    if(SDL_MUSTLOCK(dst))
-    {
-      SDL_UnlockSurface(dst);
-    }
-    if(SDL_MUSTLOCK(src))
-    {
-      SDL_UnlockSurface(src);
-    }
-    if(!src->format->Amask)
-    {
-      if(src->flags & SDL_SRCALPHA)
-      {
-        SDL_SetAlpha(dst, SDL_SRCALPHA | SDL_RLEACCEL, src->format->alpha);
-      }
-      if(src->flags & SDL_SRCCOLORKEY)
-      {
-        SDL_SetColorKey(dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, src->format->colorkey);
-      }
-    }
-    return dst;
-  }
-
-  SDL_Surface *optimize(SDL_Surface *src)
-  {
-    if(!src->format->Amask)
-    {
-      return SDL_DisplayFormat(src);
-    }
-    else
-    {
-      int transparent = 0;
-      int opaque = 0;
-      int semitransparent = 0;
-      int alphasum = 0;
-      int squaredalphasum = 0;
-      bool colors[(1 << 12)];
-      memset(colors, 0, (1 << 12) * sizeof(bool));
-
-      int bpp = src->format->BytesPerPixel;
-      if(SDL_MUSTLOCK(src))
-      {
-        SDL_LockSurface(src);
-      }
-      for(int y = 0;y < src->h;y++) {
-        for(int x = 0;x < src->w;x++) {
-          Uint8 *pixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
-          Uint32 mapped = 0;
-          switch(bpp) {
-            case 1:
-              mapped = *pixel;
-              break;
-            case 2:
-              mapped = *(Uint16 *)pixel;
-              break;
-            case 3:
-#if SDL_BYTEORDER == SDL_BIG_ENDIAN
-              mapped |= pixel[0] << 16;
-              mapped |= pixel[1] << 8;
-              mapped |= pixel[2] << 0;
-#else
-              mapped |= pixel[0] << 0;
-              mapped |= pixel[1] << 8;
-              mapped |= pixel[2] << 16;
-#endif
-              break;
-            case 4:
-              mapped = *(Uint32 *)pixel;
-              break;
-          }
-          Uint8 red, green, blue, alpha;
-          SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha);
-          if(alpha < 16)
-          {
-            transparent++;
-          }
-          else if (alpha > 240)
-          {
-            opaque++;
-            alphasum += alpha;
-            squaredalphasum += alpha * alpha;
-          }
-          else
-          {
-            semitransparent++;
-            squaredalphasum += alpha * alpha;
-          }
-          if(alpha != 0)
-          {
-            colors[((red & 0xf0) << 4) | (green & 0xf0) | ((blue & 0xf0) >> 4)] = true;
-          }
-        }
-      }
-      if(SDL_MUSTLOCK(src))
-      {
-        SDL_UnlockSurface(src);
-      }
-      int avgalpha = (opaque + semitransparent) ? alphasum / (opaque + semitransparent) : 0;
-      int avgsquaredalpha = (opaque + semitransparent) ? squaredalphasum / (opaque + semitransparent) : 0;
-      int alphavariance = avgsquaredalpha - avgalpha * avgalpha;
-      if(semitransparent > ((transparent + opaque + semitransparent) / 8) && alphavariance > 16)
-      {
-        return SDL_DisplayFormatAlpha(src);
-      }
-      int keycolor = -1;
-      for(int i = 0;i < (1 << 12);i++)
-      {
-        if(!colors[i])
-        {
-          keycolor = i;
-        }
-      }
-      if(keycolor == -1)
-      {
-        return SDL_DisplayFormatAlpha(src);
-      }
-      SDL_Surface *dst = SDL_CreateRGBSurface(src->flags & ~(SDL_SRCALPHA), src->w, src->h, src->format->BitsPerPixel, src->format->Rmask,  src->format->Gmask, src->format->Bmask, 0);
-      bpp = dst->format->BytesPerPixel;
-      Uint32 key = SDL_MapRGB(dst->format, (((keycolor & 0xf00) >> 4) | 0xf), ((keycolor & 0xf0) | 0xf), (((keycolor & 0xf) << 4) | 0xf));
-      if(SDL_MUSTLOCK(src))
-      {
-        SDL_LockSurface(src);
-      }
-      if(SDL_MUSTLOCK(dst))
-      {
-        SDL_LockSurface(dst);
-      }
-      for(int y = 0;y < dst->h;y++) {
-        for(int x = 0;x < dst->w;x++) {
-          Uint8 *srcpixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
-          Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
-          Uint32 mapped = 0;
-          switch(bpp) {
-            case 1:
-              mapped = *srcpixel;
-              break;
-            case 2:
-              mapped = *(Uint16 *)srcpixel;
-              break;
-            case 3:
-#if SDL_BYTEORDER == SDL_BIG_ENDIAN
-              mapped |= srcpixel[0] << 16;
-              mapped |= srcpixel[1] << 8;
-              mapped |= srcpixel[2] << 0;
-#else
-              mapped |= srcpixel[0] << 0;
-              mapped |= srcpixel[1] << 8;
-              mapped |= srcpixel[2] << 16;
-#endif
-              break;
-            case 4:
-              mapped = *(Uint32 *)srcpixel;
-              break;
-          }
-          Uint8 red, green, blue, alpha;
-          SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha);
-          if(alpha < (avgalpha / 4))
-          {
-            mapped = key;
-          }
-          else
-          {
-            mapped = SDL_MapRGB(dst->format, red, green, blue);
-          }
-          switch(bpp) {
-            case 1:
-              *dstpixel = mapped;
-              break;
-            case 2:
-              *(Uint16 *)dstpixel = mapped;
-              break;
-            case 3:
-#if SDL_BYTEORDER == SDL_BIG_ENDIAN
-              dstpixel[0] = (mapped >> 16) & 0xff;
-              dstpixel[1] = (mapped >> 8) & 0xff;
-              dstpixel[2] = (mapped >> 0) & 0xff;
-#else
-              dstpixel[0] = (mapped >> 0) & 0xff;
-              dstpixel[1] = (mapped >> 8) & 0xff;
-              dstpixel[2] = (mapped >> 16) & 0xff;
-#endif
-              break;
-            case 4:
-              *(Uint32 *)dstpixel = mapped;
-              break;
-          }
-        }
-      }
-      if(SDL_MUSTLOCK(dst))
-      {
-        SDL_UnlockSurface(dst);
-      }
-      if(SDL_MUSTLOCK(src))
-      {
-        SDL_UnlockSurface(src);
-      }
-      if(avgalpha < 240)
-      {
-        SDL_SetAlpha(dst, SDL_SRCALPHA | SDL_RLEACCEL, avgalpha);
-      }
-      SDL_SetColorKey(dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, key);
-      SDL_Surface *convert = SDL_DisplayFormat(dst);
-      SDL_FreeSurface(dst);
-      return convert;
-    }
-  }
-}
-
-namespace SDL
-{
-  Texture::Texture(SDL_Surface* image)
-  {
-    texture = optimize(image);
-    //width = texture->w;
-    //height = texture->h;
-    int numerator, denominator;
-    float xfactor = (float) config->screenwidth / SCREEN_WIDTH;
-    float yfactor = (float) config->screenheight / SCREEN_HEIGHT;
-    if(xfactor < yfactor)
-    {
-      numerator = config->screenwidth;
-      denominator = SCREEN_WIDTH;
-    }
-    else
-    {
-      numerator = config->screenheight;
-      denominator = SCREEN_HEIGHT;
-    }
-    cache[NO_EFFECT][Color::WHITE] = scale(texture, numerator, denominator);
-  }
-
-  Texture::~Texture()
-  {
-    SDL_FreeSurface(texture);
-  }
-
-  SDL_Surface *Texture::get_transform(const Color &color, DrawingEffect effect)
-  {
-    if(cache[NO_EFFECT][color] == 0) {
-      assert(cache[NO_EFFECT][Color::WHITE]);
-      cache[NO_EFFECT][color] = colorize(cache[NO_EFFECT][Color::WHITE], color);
-    }
-    if(cache[effect][color] == 0) {
-      assert(cache[NO_EFFECT][color]);
-      switch(effect) {
-        case NO_EFFECT:
-          break;
-        case HORIZONTAL_FLIP:
-          cache[HORIZONTAL_FLIP][color] = horz_flip(cache[NO_EFFECT][color]);
-          break;
-        case VERTICAL_FLIP:
-          cache[VERTICAL_FLIP][color] = vert_flip(cache[NO_EFFECT][color]);
-          break;
-        default:
-          return 0;
-      }
-    }
-    return cache[effect][color];
-  }
-}
diff --git a/src/video/sdl_texture.hpp b/src/video/sdl_texture.hpp
deleted file mode 100644 (file)
index 34479db..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-//  $Id: sdl_texture.hpp 4063 2006-07-21 21:05:23Z anmaster $
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-#ifndef __SDL_TEXTURE_HPP__
-#define __SDL_TEXTURE_HPP__
-
-#include <config.h>
-
-#include <SDL.h>
-
-#include "texture.hpp"
-#include "color.hpp"
-
-namespace SDL
-{
-  class Texture : public ::Texture
-  {
-  protected:
-    SDL_Surface *texture;
-    //unsigned int width;
-    //unsigned int height;
-
-    struct ColorCache
-    {
-      static const int HASHED_BITS = 3;
-      static const int CACHE_SIZE = 1 << (HASHED_BITS * 3);
-
-      static void ref(SDL_Surface *surface)
-      {
-        if(surface)
-        {
-          surface->refcount++;
-        }
-      }
-
-      static int hash(const Color &color)
-      {
-        return
-      ((int) (color.red * ((1 << HASHED_BITS) - 1)) << (HASHED_BITS - 1) * 2) |
-      ((int) (color.green * ((1 << HASHED_BITS) - 1)) << (HASHED_BITS - 1)) |
-      ((int) (color.blue * ((1 << HASHED_BITS) - 1)) << 0);
-      }
-
-      SDL_Surface *data[CACHE_SIZE];
-
-      ColorCache()
-      {
-        memset(data, 0, CACHE_SIZE * sizeof(SDL_Surface *));
-      }
-
-      ~ColorCache()
-      {
-        std::for_each(data, data + CACHE_SIZE, SDL_FreeSurface);
-      }
-
-      void operator = (const ColorCache &other)
-      {
-        std::for_each(other.data, other.data + CACHE_SIZE, ref);
-        std::for_each(data, data + CACHE_SIZE, SDL_FreeSurface);
-        memcpy(data, other.data, CACHE_SIZE * sizeof(SDL_Surface *));
-      }
-
-      SDL_Surface *&operator [] (const Color &color)
-      {
-        return data[hash(color)];
-      }
-    };
-    //typedef std::map<Color, SDL_Surface *> ColorCache;
-    ColorCache cache[NUM_EFFECTS];
-
-  public:
-    Texture(SDL_Surface* sdlsurface);
-    virtual ~Texture();
-
-    SDL_Surface *get_transform(const Color &color, DrawingEffect effect);
-
-    SDL_Surface *get_texture() const
-    {
-      return texture;
-    }
-
-    unsigned int get_texture_width() const
-    {
-      return texture->w;
-    }
-
-    unsigned int get_texture_height() const
-    {
-      return texture->h;
-    }
-
-    unsigned int get_image_width() const
-    {
-      return texture->w;
-    }
-
-    unsigned int get_image_height() const
-    {
-      return texture->h;
-    }
-
-    /*unsigned int get_texture_width() const
-    {
-      return width;
-    }
-
-    unsigned int get_texture_height() const
-    {
-      return height;
-    }
-
-    unsigned int get_image_width() const
-    {
-      return width;
-    }
-
-    unsigned int get_image_height() const
-    {
-      return height;
-    }*/
-  };
-}
-
-#endif
index d90494b..a9358fb 100644 (file)
 #include <string>
 #include <SDL.h>
 #include "math/vector.hpp"
-#include "texture.hpp"
-#include "video_systems.hpp"
+#include "file_system.hpp"
+#include <unison/video/Texture.hpp>
+
+/// bitset for drawing effects
+enum DrawingEffect {
+  /** Don't apply anything */
+  NO_EFFECT,
+  /** Draw the Surface upside down */
+  VERTICAL_FLIP,
+  /** Draw the Surface from left to down */
+  HORIZONTAL_FLIP,
+  NUM_EFFECTS
+};
 
 /**
  * A rectangular image.
 class Surface
 {
 private:
-  Texture* texture;
-  void *surface_data;
-  int x;
-  int y;
-  int w;
-  int h;
+  Unison::Video::TextureSection texture;
   bool flipx;
 
 public:
   Surface(const std::string& file) :
-    texture(texture_manager->get(file)),
-    x(0), y(0), w(0), h(0),
+    texture(FileSystem::normalize(file)),
     flipx(false)
   {
-    texture->ref();
-    w = texture->get_image_width();
-    h = texture->get_image_height();
-    surface_data = new_surface_data(*this);
   }
 
   Surface(const std::string& file, int x, int y, int w, int h) :
-    texture(texture_manager->get(file)),
-    x(x), y(y), w(w), h(h),
+    texture(FileSystem::normalize(file), Unison::Video::Rect(x, y, w, h)),
     flipx(false)
   {
-    texture->ref();
-    surface_data = new_surface_data(*this);
   }
 
   Surface(const Surface& other) :
     texture(other.texture),
-    x(other.x), y(other.y),
-    w(other.w), h(other.h),
     flipx(false)
   {
-    texture->ref();
-    surface_data = new_surface_data(*this);
   }
 
   ~Surface()
   {
-    free_surface_data(surface_data);
-    texture->unref();
   }
 
   /** flip the surface horizontally */
@@ -94,44 +86,33 @@ public:
 
   const Surface& operator= (const Surface& other)
   {
-    other.texture->ref();
-    texture->unref();
     texture = other.texture;
-    x = other.x;
-    y = other.y;
-    w = other.w;
-    h = other.h;
     return *this;
   }
 
-  Texture *get_texture() const
+  Unison::Video::TextureSection get_texture() const
   {
     return texture;
   }
 
-  void *get_surface_data() const
-  {
-    return surface_data;
-  }
-
   int get_x() const
   {
-    return x;
+    return texture.clip_rect.pos.x;
   }
 
   int get_y() const
   {
-    return y;
+    return texture.clip_rect.pos.y;
   }
 
   int get_width() const
   {
-    return w;
+    return texture.clip_rect.size.x ? texture.clip_rect.size.x : texture.image.get_size().x;
   }
 
   int get_height() const
   {
-    return h;
+    return texture.clip_rect.size.y ? texture.clip_rect.size.y : texture.image.get_size().y;
   }
 
   Vector get_position() const
diff --git a/src/video/texture.hpp b/src/video/texture.hpp
deleted file mode 100644 (file)
index 6e4c462..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-//  $Id$
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-#ifndef __TEXTURE_HPP__
-#define __TEXTURE_HPP__
-
-#include <config.h>
-
-#include <assert.h>
-#include <string>
-
-#include "texture_manager.hpp"
-
-/// bitset for drawing effects
-enum DrawingEffect {
-  /** Don't apply anything */
-  NO_EFFECT,
-  /** Draw the Surface upside down */
-  VERTICAL_FLIP,
-  /** Draw the Surface from left to down */
-  HORIZONTAL_FLIP,
-  NUM_EFFECTS
-};
-
-/**
- * This class is a wrapper around a texture handle. It stores the texture width
- * and height and provides convenience functions for uploading SDL_Surfaces
- * into the texture
- */
-class Texture
-{
-protected:
-  int refcount;
-  std::string filename;
-
-public:
-  Texture() : refcount(0), filename() {}
-  virtual ~Texture() {}
-
-  virtual unsigned int get_texture_width() const = 0;
-  virtual unsigned int get_texture_height() const = 0;
-  virtual unsigned int get_image_width() const = 0;
-  virtual unsigned int get_image_height() const = 0;
-
-  std::string get_filename() const
-  {
-    return filename;
-  }
-
-  void set_filename(std::string filename)
-  {
-    this->filename = filename;
-  }
-
-  void ref()
-  {
-    refcount++;
-  }
-
-  void unref()
-  {
-    assert(refcount > 0);
-    refcount--;
-    if(refcount == 0)
-      release();
-  }
-
-private:
-  void release()
-  {
-    texture_manager->release(this);
-  }
-};
-
-#endif
diff --git a/src/video/texture_manager.cpp b/src/video/texture_manager.cpp
deleted file mode 100644 (file)
index d9ff2a7..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-//  $Id$
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-#include <config.h>
-
-#include "texture_manager.hpp"
-
-#include <assert.h>
-#include <SDL.h>
-#include <SDL_image.h>
-#include <iostream>
-#include <sstream>
-#include <stdexcept>
-#include "physfs/physfs_sdl.hpp"
-#include "video_systems.hpp"
-#include "gl_texture.hpp"
-#include "glutil.hpp"
-#include "gameconfig.hpp"
-#include "file_system.hpp"
-#include "log.hpp"
-#include "texture.hpp"
-
-TextureManager* texture_manager = NULL;
-
-TextureManager::TextureManager()
-{
-}
-
-TextureManager::~TextureManager()
-{
-  for(ImageTextures::iterator i = image_textures.begin();
-      i != image_textures.end(); ++i) {
-    if(i->second == NULL)
-      continue;
-    log_warning << "Texture '" << i->first << "' not freed" << std::endl;
-    delete i->second;
-  }
-}
-
-Texture*
-TextureManager::get(const std::string& _filename)
-{
-  std::string filename = FileSystem::normalize(_filename);
-  ImageTextures::iterator i = image_textures.find(filename);
-
-  Texture* texture = NULL;
-  if(i != image_textures.end())
-    texture = i->second;
-
-  if(texture == NULL) {
-    texture = create_image_texture(filename);
-    image_textures[filename] = texture;
-  }
-
-  return texture;
-}
-
-void
-TextureManager::release(Texture* texture)
-{
-  image_textures.erase(texture->get_filename());
-  delete texture;
-}
-
-#ifdef HAVE_OPENGL
-void
-TextureManager::register_texture(GL::Texture* texture)
-{
-  textures.insert(texture);
-}
-
-void
-TextureManager::remove_texture(GL::Texture* texture)
-{
-  textures.erase(texture);
-}
-#endif
-
-Texture*
-TextureManager::create_image_texture(const std::string& filename)
-{
-  SDL_Surface* image = IMG_Load_RW(get_physfs_SDLRWops(filename), 1);
-  if(image == 0) {
-    std::ostringstream msg;
-    msg << "Couldn't load image '" << filename << "' :" << SDL_GetError();
-    throw std::runtime_error(msg.str());
-  }
-
-  Texture* result = 0;
-  try {
-    result = new_texture(image);
-    result->set_filename(filename);
-  } catch(...) {
-    delete result;
-    SDL_FreeSurface(image);
-    throw;
-  }
-
-  SDL_FreeSurface(image);
-  return result;
-}
-
-#ifdef HAVE_OPENGL
-void
-TextureManager::save_textures()
-{
-  glPixelStorei(GL_PACK_ROW_LENGTH, 0);
-  glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0);
-  glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
-  glPixelStorei(GL_PACK_SKIP_ROWS, 0);
-  glPixelStorei(GL_PACK_SKIP_IMAGES, 0);
-  glPixelStorei(GL_PACK_ALIGNMENT, 1);
-  for(Textures::iterator i = textures.begin(); i != textures.end(); ++i) {
-    save_texture(*i);
-  }
-  for(ImageTextures::iterator i = image_textures.begin();
-      i != image_textures.end(); ++i) {
-    save_texture(dynamic_cast<GL::Texture *>(i->second));
-  }
-}
-
-void
-TextureManager::save_texture(GL::Texture* texture)
-{
-  SavedTexture saved_texture;
-  saved_texture.texture = texture;
-  glBindTexture(GL_TEXTURE_2D, texture->get_handle());
-  glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH,
-                           &saved_texture.width);
-  glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT,
-                           &saved_texture.height);
-  glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BORDER,
-                           &saved_texture.border);
-  glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
-                      &saved_texture.min_filter);
-  glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
-                      &saved_texture.mag_filter);
-  glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
-                      &saved_texture.wrap_s);
-  glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
-                      &saved_texture.wrap_t);
-
-  size_t pixelssize = saved_texture.width * saved_texture.height * 4;
-  saved_texture.pixels = new char[pixelssize];
-
-  glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE,
-                saved_texture.pixels);
-
-  saved_textures.push_back(saved_texture);
-
-  glDeleteTextures(1, &(texture->get_handle()));
-  texture->set_handle(0);
-
-  assert_gl("retrieving texture for save");
-}
-
-void
-TextureManager::reload_textures()
-{
-  glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
-  glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
-  glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
-  glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
-  glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0);
-  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-
-  for(std::vector<SavedTexture>::iterator i = saved_textures.begin();
-      i != saved_textures.end(); ++i) {
-    SavedTexture& saved_texture = *i;
-
-    GLuint handle;
-    glGenTextures(1, &handle);
-    assert_gl("creating texture handle");
-
-    glBindTexture(GL_TEXTURE_2D, handle);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
-                 saved_texture.width, saved_texture.height,
-                 saved_texture.border, GL_RGBA,
-                 GL_UNSIGNED_BYTE, saved_texture.pixels);
-    delete[] saved_texture.pixels;
-    assert_gl("uploading texture pixel data");
-
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
-                    saved_texture.min_filter);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
-                    saved_texture.mag_filter);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
-                    saved_texture.wrap_s);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
-                    saved_texture.wrap_t);
-
-    assert_gl("setting texture_params");
-    saved_texture.texture->set_handle(handle);
-  }
-
-  saved_textures.clear();
-}
-#endif
diff --git a/src/video/texture_manager.hpp b/src/video/texture_manager.hpp
deleted file mode 100644 (file)
index 1431c68..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-//  $Id$
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-#ifndef __IMAGE_TEXTURE_MANAGER_HPP__
-#define __IMAGE_TEXTURE_MANAGER_HPP__
-
-#include <config.h>
-
-#include "glutil.hpp"
-#include <string>
-#include <vector>
-#include <map>
-#include <set>
-
-class Texture;
-namespace GL { class Texture; }
-
-class TextureManager
-{
-public:
-  TextureManager();
-  ~TextureManager();
-
-  Texture* get(const std::string& filename);
-
-#ifdef HAVE_OPENGL
-  void register_texture(GL::Texture* texture);
-  void remove_texture(GL::Texture* texture);
-
-  void save_textures();
-  void reload_textures();
-#endif
-
-private:
-  friend class Texture;
-  void release(Texture* texture);
-
-  typedef std::map<std::string, Texture*> ImageTextures;
-  ImageTextures image_textures;
-
-  Texture* create_image_texture(const std::string& filename);
-
-#ifdef HAVE_OPENGL
-  typedef std::set<GL::Texture*> Textures;
-  Textures textures;
-
-  struct SavedTexture
-  {
-    GL::Texture* texture;
-    GLint width;
-    GLint height;
-    char* pixels;
-    GLint border;
-
-    GLint min_filter;
-    GLint mag_filter;
-    GLint wrap_s;
-    GLint wrap_t;
-  };
-  std::vector<SavedTexture> saved_textures;
-
-  void save_texture(GL::Texture* texture);
-#endif
-};
-
-extern TextureManager* texture_manager;
-
-#endif
diff --git a/src/video/video_systems.cpp b/src/video/video_systems.cpp
deleted file mode 100644 (file)
index 1fd3627..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-//  $Id: video_systems.cpp 5063 2007-05-27 11:32:00Z matzeb $
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-#include <config.h>
-
-#include "video_systems.hpp"
-#include "gameconfig.hpp"
-#include "renderer.hpp"
-#include "gl_renderer.hpp"
-#include "sdl_renderer.hpp"
-#include "lightmap.hpp"
-#include "gl_lightmap.hpp"
-#include "sdl_lightmap.hpp"
-#include "texture.hpp"
-#include "gl_texture.hpp"
-#include "sdl_texture.hpp"
-#include "gl_surface_data.hpp"
-#include "sdl_surface_data.hpp"
-
-Renderer *new_renderer()
-{
-  switch(config->video)
-  {
-    case AUTO_VIDEO:
-#ifdef HAVE_OPENGL
-      return new GL::Renderer();
-#else
-      return new SDL::Renderer();
-#endif
-#ifdef HAVE_OPENGL
-    case OPENGL:
-      return new GL::Renderer();
-#endif
-    case PURE_SDL:
-      return new SDL::Renderer();
-    default:
-      assert(0 && "invalid video system in config");
-#ifdef HAVE_OPENGL
-      return new GL::Renderer();
-#else
-      return new SDL::Renderer();
-#endif
-  }
-}
-
-Lightmap *new_lightmap()
-{
-  switch(config->video)
-  {
-    case AUTO_VIDEO:
-#ifdef HAVE_OPENGL
-      return new GL::Lightmap();
-#else
-      return new SDL::Lightmap();
-#endif
-#ifdef HAVE_OPENGL
-    case OPENGL:
-      return new GL::Lightmap();
-#endif
-    case PURE_SDL:
-      return new SDL::Lightmap();
-    default:
-      assert(0 && "invalid video system in config");
-#ifdef HAVE_OPENGL
-      return new GL::Lightmap();
-#else
-      return new SDL::Lightmap();
-#endif
-  }
-}
-
-Texture *new_texture(SDL_Surface *image)
-{
-  switch(config->video)
-  {
-    case AUTO_VIDEO:
-#ifdef HAVE_OPENGL
-      return new GL::Texture(image);
-#else
-      return new SDL::Texture(image);
-#endif
-#ifdef HAVE_OPENGL
-    case OPENGL:
-      return new GL::Texture(image);
-#endif
-    case PURE_SDL:
-      return new SDL::Texture(image);
-    default:
-      assert(0 && "invalid video system in config");
-#ifdef HAVE_OPENGL
-      return new GL::Texture(image);
-#else
-      return new SDL::Texture(image);
-#endif
-  }
-}
-
-void *new_surface_data(const Surface &surface)
-{
-  switch(config->video)
-  {
-    case AUTO_VIDEO:
-#ifdef HAVE_OPENGL
-      return new GL::SurfaceData(surface);
-#else
-      return new SDL::SurfaceData(surface);
-#endif
-#ifdef HAVE_OPENGL
-    case OPENGL:
-      return new GL::SurfaceData(surface);
-#endif
-    case PURE_SDL:
-      return new SDL::SurfaceData(surface);
-    default:
-      assert(0 && "invalid video system in config");
-#ifdef HAVE_OPENGL
-      return new GL::SurfaceData(surface);
-#else
-      return new SDL::SurfaceData(surface);
-#endif
-  }
-}
-
-void free_surface_data(void *surface_data)
-{
-  delete reinterpret_cast<char *>(surface_data);
-}
-
-VideoSystem get_video_system(const std::string &video)
-{
-  if(video == "auto")
-  {
-    return AUTO_VIDEO;
-  }
-#ifdef HAVE_OPENGL
-  else if(video == "opengl")
-  {
-    return OPENGL;
-  }
-#endif
-  else if(video == "sdl")
-  {
-    return PURE_SDL;
-  }
-  else
-  {
-    return AUTO_VIDEO;
-  }
-}
-
-std::string get_video_string(VideoSystem video)
-{
-  switch(video)
-  {
-    case AUTO_VIDEO:
-      return "auto";
-    case OPENGL:
-      return "opengl";
-    case PURE_SDL:
-      return "sdl";
-    default:
-      assert(0 && "invalid video system in config");
-      return "auto";
-  }
-}
diff --git a/src/video/video_systems.hpp b/src/video/video_systems.hpp
deleted file mode 100644 (file)
index 1347f54..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-//  $Id: video_systems.hpp 5138 2007-08-15 01:02:22Z tuxdev $
-//
-//  SuperTux
-//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-//  02111-1307, USA.
-#ifndef __RENDER_SYTSTEMS_HPP__
-#define __RENDER_SYTSTEMS_HPP__
-
-#include <config.h>
-
-#include <string>
-#include <SDL.h>
-
-class Renderer;
-class Lightmap;
-class Texture;
-class Surface;
-
-enum VideoSystem {
-  AUTO_VIDEO,
-  OPENGL,
-  PURE_SDL,
-  NUM_SYSTEMS
-};
-
-Renderer *new_renderer();
-Lightmap *new_lightmap();
-Texture *new_texture(SDL_Surface *image);
-void *new_surface_data(const Surface &surface);
-void free_surface_data(void *surface_data);
-VideoSystem get_video_system(const std::string &video);
-std::string get_video_string(VideoSystem video);
-
-#endif
index 8fd4599..d8beb4a 100644 (file)
@@ -20,7 +20,8 @@
 #include <config.h>
 
 #include <stddef.h>
-#include <physfs.h>
+//#include <physfs.h>
+#include <unison/vfs/FileSystem.hpp>
 #include <stdexcept>
 
 #include "world.hpp"
@@ -61,19 +62,21 @@ World::~World()
 void
 World::set_savegame_filename(const std::string& filename)
 {
+  Unison::VFS::FileSystem &fs = Unison::VFS::FileSystem::get();
   this->savegame_filename = filename;
   // make sure the savegame directory exists
   std::string dirname = FileSystem::dirname(filename);
-  if(!PHYSFS_exists(dirname.c_str())) {
-      if(PHYSFS_mkdir(dirname.c_str())) {
+  if(!fs.exists(dirname)) {
+      fs.mkdir(dirname);
+      /*if(PHYSFS_mkdir(dirname.c_str())) {
           std::ostringstream msg;
           msg << "Couldn't create directory for savegames '"
               << dirname << "': " <<PHYSFS_getLastError();
           throw std::runtime_error(msg.str());
-      }
+      }*/
   }
 
-  if(!PHYSFS_isDirectory(dirname.c_str())) {
+  if(!fs.is_dir(dirname)) {
       std::ostringstream msg;
       msg << "Savegame path '" << dirname << "' is not a directory";
       throw std::runtime_error(msg.str());
@@ -107,7 +110,14 @@ World::load(const std::string& filename)
   // directory to see what we can find
 
   std::string path = basedir;
-  char** files = PHYSFS_enumerateFiles(path.c_str());
+  std::vector<std::string> files = Unison::VFS::FileSystem::get().ls(path);
+  for(std::vector<std::string>::iterator iter = files.begin();iter != files.end();++iter)
+  {
+    if(has_suffix(iter->c_str(), ".stl")) {
+      levels.push_back(path + *iter);
+    }
+  }
+  /*char** files = PHYSFS_enumerateFiles(path.c_str());
   if(!files) {
     log_warning << "Couldn't read subset dir '" << path << "'" << std::endl;
     return;
@@ -118,7 +128,7 @@ World::load(const std::string& filename)
       levels.push_back(path + *filename);
     }
   }
-  PHYSFS_freeList(files);
+  PHYSFS_freeList(files);*/
 }
 
 void
index 2b61124..c3ec7e5 100644 (file)
 #include <config.h>
 
 #include <stddef.h>
-#include <physfs.h>
+//#include <physfs.h>
 #include "worldmap/level.hpp"
 #include "sprite/sprite_manager.hpp"
 #include "sprite/sprite.hpp"
 #include "video/drawing_context.hpp"
 #include "log.hpp"
 #include "file_system.hpp"
+#include <unison/vfs/FileSystem.hpp>
 
 namespace WorldMapNS
 {
@@ -46,7 +47,7 @@ LevelTile::LevelTile(const std::string& basedir, const lisp::Lisp* lisp)
 
   lisp->get("extro-script", extro_script);
 
-  if (!PHYSFS_exists((basedir + name).c_str()))
+  if (!Unison::VFS::FileSystem::get().exists(basedir + name))
   {
     log_warning << "level file '" << name
       << "' does not exist and will not be added to the worldmap" << std::endl;
@@ -76,7 +77,7 @@ LevelTile::get_picture()
   if (picture_cached) return picture;
   picture_cached = true;
   std::string fname = FileSystem::strip_extension(basedir + name)+".jpg";
-  if (!PHYSFS_exists(fname.c_str())) {
+  if (!Unison::VFS::FileSystem::get().exists(fname)) {
        return 0;
   }
   picture = new Surface(fname);
index 2f5d3aa..473811e 100644 (file)
@@ -26,7 +26,7 @@
 #include <stdexcept>
 #include <sstream>
 #include <unistd.h>
-#include <physfs.h>
+//#include <physfs.h>
 
 #include "worldmap.hpp"