From 99cf62c2d44b4555e9761f1c8f1b10cf880c33fb Mon Sep 17 00:00:00 2001 From: Tim Goya Date: Sun, 16 Dec 2007 22:17:36 +0000 Subject: [PATCH] Initial integration, lots of broken stuff SVN-Revision: 5199 --- src/addon_manager.cpp | 64 +- src/gameconfig.cpp | 13 +- src/gameconfig.hpp | 4 +- src/lisp/parser.cpp | 5 +- src/main.cpp | 137 +- src/physfs/physfs_sdl.cpp | 17 + src/physfs/physfs_stream.cpp | 2 + src/physfs/physfs_stream.hpp | 7 + src/sector.cpp | 5 +- src/tinygettext/tinygettext.cpp | 147 +- src/title.cpp | 23 +- src/unison/CMakeLists.txt | 55 + src/unison/Doxyfile | 1257 ++++++++++ src/unison/LICENSE_1_0.txt | 23 + src/unison/include/unison/vfs/FileSystem.hpp | 53 + src/unison/include/unison/vfs/sdl/Utils.hpp | 27 + src/unison/include/unison/vfs/stream.hpp | 31 + src/unison/include/unison/video/Blittable.hpp | 107 + src/unison/include/unison/video/Blitters.hpp | 83 + src/unison/include/unison/video/Color.hpp | 111 + src/unison/include/unison/video/Coord.hpp | 275 +++ src/unison/include/unison/video/DisplayList.hpp | 240 ++ src/unison/include/unison/video/Rect.hpp | 186 ++ src/unison/include/unison/video/RenderOptions.hpp | 79 + src/unison/include/unison/video/Renderers.hpp | 57 + src/unison/include/unison/video/Surface.hpp | 245 ++ src/unison/include/unison/video/Texture.hpp | 124 + src/unison/include/unison/video/Window.hpp | 148 ++ .../include/unison/video/backend/Renderer.hpp | 102 + .../include/unison/video/backend/Texture.hpp | 115 + src/unison/include/unison/video/backend/Window.hpp | 62 + src/unison/include/unison/video/sdl/Blitters.hpp | 108 + src/unison/physfs-1.1.1/CHANGELOG.txt | 602 +++++ src/unison/physfs-1.1.1/CMakeLists.txt | 383 ++++ src/unison/physfs-1.1.1/CREDITS.txt | 95 + src/unison/physfs-1.1.1/Doxyfile | 1079 +++++++++ src/unison/physfs-1.1.1/INSTALL.txt | 149 ++ src/unison/physfs-1.1.1/LICENSE.txt | 29 + src/unison/physfs-1.1.1/TODO.txt | 45 + src/unison/physfs-1.1.1/archivers/dir.c | 283 +++ src/unison/physfs-1.1.1/archivers/grp.c | 467 ++++ src/unison/physfs-1.1.1/archivers/hog.c | 506 +++++ src/unison/physfs-1.1.1/archivers/lzma.c | 693 ++++++ src/unison/physfs-1.1.1/archivers/mvl.c | 463 ++++ src/unison/physfs-1.1.1/archivers/qpak.c | 622 +++++ src/unison/physfs-1.1.1/archivers/wad.c | 526 +++++ src/unison/physfs-1.1.1/archivers/zip.c | 1441 ++++++++++++ .../physfs-1.1.1/extras/PhysFS.NET/AssemblyInfo.cs | 58 + .../extras/PhysFS.NET/PhysFS.NET.csproj | 113 + .../physfs-1.1.1/extras/PhysFS.NET/PhysFS.NET.sln | 21 + .../physfs-1.1.1/extras/PhysFS.NET/PhysFS.cs | 189 ++ .../extras/PhysFS.NET/PhysFSFileStream.cs | 194 ++ .../physfs-1.1.1/extras/PhysFS.NET/PhysFS_DLL.cs | 113 + .../physfs-1.1.1/extras/PhysFS.NET/README.txt | 10 + .../physfs-1.1.1/extras/PhysFS.NET/TestApp/App.ico | Bin 0 -> 1078 bytes .../extras/PhysFS.NET/TestApp/AssemblyInfo.cs | 58 + .../extras/PhysFS.NET/TestApp/TestApp.csproj | 116 + .../extras/PhysFS.NET/TestApp/TestApp.sln | 27 + .../extras/PhysFS.NET/TestApp/TestAppForm.cs | 274 +++ .../extras/PhysFS.NET/TestApp/TestAppForm.resx | 102 + src/unison/physfs-1.1.1/extras/abs-file.h | 165 ++ src/unison/physfs-1.1.1/extras/casefolding.txt | 1064 +++++++++ src/unison/physfs-1.1.1/extras/globbing.c | 159 ++ src/unison/physfs-1.1.1/extras/globbing.h | 77 + src/unison/physfs-1.1.1/extras/ignorecase.c | 219 ++ src/unison/physfs-1.1.1/extras/ignorecase.h | 75 + .../physfs-1.1.1/extras/makecasefoldhashtable.pl | 85 + src/unison/physfs-1.1.1/extras/makedist.sh | 54 + .../physfs-1.1.1/extras/physfs_rb/installer.rb | 103 + .../extras/physfs_rb/physfs/extconf.rb | 9 + .../extras/physfs_rb/physfs/install.rb | 7 + .../extras/physfs_rb/physfs/make_install_test.sh | 9 + .../physfs-1.1.1/extras/physfs_rb/physfs/physfs.rb | 121 + .../extras/physfs_rb/physfs/physfsrwops.c | 192 ++ .../extras/physfs_rb/physfs/physfsrwops.h | 87 + .../extras/physfs_rb/physfs/rb_physfs.c | 462 ++++ .../extras/physfs_rb/physfs/rb_physfs.h | 13 + .../extras/physfs_rb/physfs/rb_physfs_file.c | 226 ++ .../extras/physfs_rb/physfs/rb_physfs_file.h | 24 + .../extras/physfs_rb/physfs/rb_sdl_rwops.c | 162 ++ .../extras/physfs_rb/physfs/rb_sdl_rwops.h | 16 + .../extras/physfs_rb/physfs/test/test_physfs.rb | 358 +++ src/unison/physfs-1.1.1/extras/physfshttpd.c | 291 +++ src/unison/physfs-1.1.1/extras/physfsrwops.c | 193 ++ src/unison/physfs-1.1.1/extras/physfsrwops.h | 88 + src/unison/physfs-1.1.1/extras/physfsunpack.c | 181 ++ src/unison/physfs-1.1.1/extras/selfextract.c | 66 + src/unison/physfs-1.1.1/lzma/7zAlloc.h | 20 + src/unison/physfs-1.1.1/lzma/7zBuffer.c | 29 + src/unison/physfs-1.1.1/lzma/7zBuffer.h | 19 + src/unison/physfs-1.1.1/lzma/7zCrc.c | 76 + src/unison/physfs-1.1.1/lzma/7zCrc.h | 24 + src/unison/physfs-1.1.1/lzma/7zDecode.c | 150 ++ src/unison/physfs-1.1.1/lzma/7zDecode.h | 21 + src/unison/physfs-1.1.1/lzma/7zExtract.c | 116 + src/unison/physfs-1.1.1/lzma/7zExtract.h | 40 + src/unison/physfs-1.1.1/lzma/7zHeader.c | 5 + src/unison/physfs-1.1.1/lzma/7zHeader.h | 55 + src/unison/physfs-1.1.1/lzma/7zIn.c | 1282 +++++++++++ src/unison/physfs-1.1.1/lzma/7zIn.h | 55 + src/unison/physfs-1.1.1/lzma/7zItem.c | 133 ++ src/unison/physfs-1.1.1/lzma/7zItem.h | 90 + src/unison/physfs-1.1.1/lzma/7zMethodID.c | 14 + src/unison/physfs-1.1.1/lzma/7zMethodID.h | 18 + src/unison/physfs-1.1.1/lzma/7zTypes.h | 67 + src/unison/physfs-1.1.1/lzma/LZMA-LICENSE.txt | 94 + src/unison/physfs-1.1.1/lzma/LzmaDecode.c | 584 +++++ src/unison/physfs-1.1.1/lzma/LzmaDecode.h | 113 + src/unison/physfs-1.1.1/lzma/LzmaStateDecode.c | 0 src/unison/physfs-1.1.1/lzma/LzmaStateDecode.h | 0 src/unison/physfs-1.1.1/lzma/LzmaTypes.h | 45 + src/unison/physfs-1.1.1/makeos2.cmd | 181 ++ .../physfs-1.1.1/CMakeFiles/CMakeError.log | 31 + .../physfs-1.1.1/CMakeFiles/CMakeTmp/src.c | 7 + src/unison/physfs-1.1.1/physfs.c | 2220 ++++++++++++++++++ src/unison/physfs-1.1.1/physfs.h | 2390 ++++++++++++++++++++ src/unison/physfs-1.1.1/physfs.spec.in | 99 + src/unison/physfs-1.1.1/physfs_byteorder.c | 324 +++ src/unison/physfs-1.1.1/physfs_casefolding.h | 2013 +++++++++++++++++ src/unison/physfs-1.1.1/physfs_internal.h | 1779 +++++++++++++++ src/unison/physfs-1.1.1/physfs_platforms.h | 37 + src/unison/physfs-1.1.1/physfs_unicode.c | 459 ++++ src/unison/physfs-1.1.1/platform/beos.cpp | 240 ++ src/unison/physfs-1.1.1/platform/macosx.c | 396 ++++ src/unison/physfs-1.1.1/platform/os2.c | 702 ++++++ src/unison/physfs-1.1.1/platform/pocketpc.c | 608 +++++ src/unison/physfs-1.1.1/platform/posix.c | 398 ++++ src/unison/physfs-1.1.1/platform/unix.c | 395 ++++ src/unison/physfs-1.1.1/platform/windows.c | 1395 ++++++++++++ src/unison/physfs-1.1.1/test/test_physfs.c | 1222 ++++++++++ src/unison/physfs-1.1.1/test/wxtest_physfs.cpp | 486 ++++ src/unison/physfs-1.1.1/zlib123/adler32.c | 149 ++ src/unison/physfs-1.1.1/zlib123/compress.c | 79 + src/unison/physfs-1.1.1/zlib123/crc32.c | 423 ++++ src/unison/physfs-1.1.1/zlib123/crc32.h | 441 ++++ src/unison/physfs-1.1.1/zlib123/deflate.c | 1736 ++++++++++++++ src/unison/physfs-1.1.1/zlib123/deflate.h | 331 +++ src/unison/physfs-1.1.1/zlib123/gzio.c | 1026 +++++++++ src/unison/physfs-1.1.1/zlib123/infback.c | 623 +++++ src/unison/physfs-1.1.1/zlib123/inffast.c | 318 +++ src/unison/physfs-1.1.1/zlib123/inffast.h | 11 + src/unison/physfs-1.1.1/zlib123/inffixed.h | 94 + src/unison/physfs-1.1.1/zlib123/inflate.c | 1368 +++++++++++ src/unison/physfs-1.1.1/zlib123/inflate.h | 115 + src/unison/physfs-1.1.1/zlib123/inftrees.c | 329 +++ src/unison/physfs-1.1.1/zlib123/inftrees.h | 55 + src/unison/physfs-1.1.1/zlib123/trees.c | 1219 ++++++++++ src/unison/physfs-1.1.1/zlib123/trees.h | 128 ++ src/unison/physfs-1.1.1/zlib123/uncompr.c | 61 + src/unison/physfs-1.1.1/zlib123/zconf.h | 332 +++ src/unison/physfs-1.1.1/zlib123/zlib.h | 1357 +++++++++++ src/unison/physfs-1.1.1/zlib123/zutil.c | 318 +++ src/unison/physfs-1.1.1/zlib123/zutil.h | 269 +++ src/unison/src/vfs/FileSystem.cpp | 127 ++ src/unison/src/vfs/sdl/Utils.cpp | 79 + src/unison/src/vfs/stream.cpp | 158 ++ src/unison/src/video/Blittable.cpp | 78 + src/unison/src/video/Blitters.cpp | 191 ++ src/unison/src/video/Color.cpp | 21 + src/unison/src/video/Renderers.cpp | 98 + src/unison/src/video/Surface.cpp | 242 ++ src/unison/src/video/Texture.cpp | 172 ++ src/unison/src/video/Window.cpp | 129 ++ src/unison/src/video/auto/Renderer.cpp | 113 + src/unison/src/video/auto/Renderer.hpp | 57 + src/unison/src/video/backend/Texture.cpp | 209 ++ src/unison/src/video/opengl/Renderer.cpp | 194 ++ src/unison/src/video/opengl/Renderer.hpp | 98 + src/unison/src/video/opengl/SDL_gl.c | 24 + src/unison/src/video/opengl/SDL_gl.h | 67 + src/unison/src/video/opengl/SDL_glfuncs.h | 38 + src/unison/src/video/opengl/Texture.cpp | 252 +++ src/unison/src/video/opengl/Texture.hpp | 55 + src/unison/src/video/opengl/Window.cpp | 191 ++ src/unison/src/video/opengl/Window.hpp | 53 + src/unison/src/video/sdl/Blitters.cpp | 607 +++++ src/unison/src/video/sdl/Renderer.cpp | 183 ++ src/unison/src/video/sdl/Renderer.hpp | 97 + src/unison/src/video/sdl/Texture.cpp | 118 + src/unison/src/video/sdl/Texture.hpp | 85 + src/unison/src/video/sdl/Window.cpp | 229 ++ src/unison/src/video/sdl/Window.hpp | 55 + src/video/color.hpp | 15 +- src/video/drawing_context.cpp | 206 +- src/video/drawing_context.hpp | 39 +- src/video/drawing_request.hpp | 41 +- src/video/font.cpp | 38 +- src/video/font.hpp | 8 +- src/video/gl_lightmap.cpp | 311 --- src/video/gl_lightmap.hpp | 63 - src/video/gl_renderer.cpp | 339 --- src/video/gl_renderer.hpp | 48 - src/video/gl_surface_data.hpp | 73 - src/video/gl_texture.cpp | 154 -- src/video/gl_texture.hpp | 97 - src/video/glutil.hpp | 14 +- src/video/lightmap.hpp | 58 - src/video/renderer.hpp | 56 - src/video/sdl_lightmap.cpp | 614 ----- src/video/sdl_lightmap.hpp | 61 - src/video/sdl_renderer.cpp | 433 ---- src/video/sdl_renderer.hpp | 48 - src/video/sdl_surface_data.hpp | 80 - src/video/sdl_texture.cpp | 658 ------ src/video/sdl_texture.hpp | 140 -- src/video/surface.hpp | 61 +- src/video/texture.hpp | 91 - src/video/texture_manager.cpp | 214 -- src/video/texture_manager.hpp | 84 - src/video/video_systems.cpp | 180 -- src/video/video_systems.hpp | 48 - src/world.cpp | 24 +- src/worldmap/level.cpp | 7 +- src/worldmap/worldmap.cpp | 2 +- 214 files changed, 50530 insertions(+), 4085 deletions(-) create mode 100644 src/unison/CMakeLists.txt create mode 100644 src/unison/Doxyfile create mode 100644 src/unison/LICENSE_1_0.txt create mode 100644 src/unison/include/unison/vfs/FileSystem.hpp create mode 100644 src/unison/include/unison/vfs/sdl/Utils.hpp create mode 100644 src/unison/include/unison/vfs/stream.hpp create mode 100644 src/unison/include/unison/video/Blittable.hpp create mode 100644 src/unison/include/unison/video/Blitters.hpp create mode 100644 src/unison/include/unison/video/Color.hpp create mode 100644 src/unison/include/unison/video/Coord.hpp create mode 100644 src/unison/include/unison/video/DisplayList.hpp create mode 100644 src/unison/include/unison/video/Rect.hpp create mode 100644 src/unison/include/unison/video/RenderOptions.hpp create mode 100644 src/unison/include/unison/video/Renderers.hpp create mode 100644 src/unison/include/unison/video/Surface.hpp create mode 100644 src/unison/include/unison/video/Texture.hpp create mode 100644 src/unison/include/unison/video/Window.hpp create mode 100644 src/unison/include/unison/video/backend/Renderer.hpp create mode 100644 src/unison/include/unison/video/backend/Texture.hpp create mode 100644 src/unison/include/unison/video/backend/Window.hpp create mode 100644 src/unison/include/unison/video/sdl/Blitters.hpp create mode 100644 src/unison/physfs-1.1.1/CHANGELOG.txt create mode 100644 src/unison/physfs-1.1.1/CMakeLists.txt create mode 100644 src/unison/physfs-1.1.1/CREDITS.txt create mode 100644 src/unison/physfs-1.1.1/Doxyfile create mode 100644 src/unison/physfs-1.1.1/INSTALL.txt create mode 100644 src/unison/physfs-1.1.1/LICENSE.txt create mode 100644 src/unison/physfs-1.1.1/TODO.txt create mode 100644 src/unison/physfs-1.1.1/archivers/dir.c create mode 100644 src/unison/physfs-1.1.1/archivers/grp.c create mode 100644 src/unison/physfs-1.1.1/archivers/hog.c create mode 100644 src/unison/physfs-1.1.1/archivers/lzma.c create mode 100644 src/unison/physfs-1.1.1/archivers/mvl.c create mode 100644 src/unison/physfs-1.1.1/archivers/qpak.c create mode 100644 src/unison/physfs-1.1.1/archivers/wad.c create mode 100644 src/unison/physfs-1.1.1/archivers/zip.c create mode 100755 src/unison/physfs-1.1.1/extras/PhysFS.NET/AssemblyInfo.cs create mode 100755 src/unison/physfs-1.1.1/extras/PhysFS.NET/PhysFS.NET.csproj create mode 100755 src/unison/physfs-1.1.1/extras/PhysFS.NET/PhysFS.NET.sln create mode 100755 src/unison/physfs-1.1.1/extras/PhysFS.NET/PhysFS.cs create mode 100755 src/unison/physfs-1.1.1/extras/PhysFS.NET/PhysFSFileStream.cs create mode 100755 src/unison/physfs-1.1.1/extras/PhysFS.NET/PhysFS_DLL.cs create mode 100755 src/unison/physfs-1.1.1/extras/PhysFS.NET/README.txt create mode 100755 src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/App.ico create mode 100755 src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/AssemblyInfo.cs create mode 100755 src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/TestApp.csproj create mode 100755 src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/TestApp.sln create mode 100755 src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/TestAppForm.cs create mode 100755 src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/TestAppForm.resx create mode 100644 src/unison/physfs-1.1.1/extras/abs-file.h create mode 100644 src/unison/physfs-1.1.1/extras/casefolding.txt create mode 100644 src/unison/physfs-1.1.1/extras/globbing.c create mode 100644 src/unison/physfs-1.1.1/extras/globbing.h create mode 100644 src/unison/physfs-1.1.1/extras/ignorecase.c create mode 100644 src/unison/physfs-1.1.1/extras/ignorecase.h create mode 100755 src/unison/physfs-1.1.1/extras/makecasefoldhashtable.pl create mode 100755 src/unison/physfs-1.1.1/extras/makedist.sh create mode 100644 src/unison/physfs-1.1.1/extras/physfs_rb/installer.rb create mode 100644 src/unison/physfs-1.1.1/extras/physfs_rb/physfs/extconf.rb create mode 100644 src/unison/physfs-1.1.1/extras/physfs_rb/physfs/install.rb create mode 100755 src/unison/physfs-1.1.1/extras/physfs_rb/physfs/make_install_test.sh create mode 100644 src/unison/physfs-1.1.1/extras/physfs_rb/physfs/physfs.rb create mode 100644 src/unison/physfs-1.1.1/extras/physfs_rb/physfs/physfsrwops.c create mode 100644 src/unison/physfs-1.1.1/extras/physfs_rb/physfs/physfsrwops.h create mode 100644 src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_physfs.c create mode 100644 src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_physfs.h create mode 100644 src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_physfs_file.c create mode 100644 src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_physfs_file.h create mode 100644 src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_sdl_rwops.c create mode 100644 src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_sdl_rwops.h create mode 100644 src/unison/physfs-1.1.1/extras/physfs_rb/physfs/test/test_physfs.rb create mode 100644 src/unison/physfs-1.1.1/extras/physfshttpd.c create mode 100644 src/unison/physfs-1.1.1/extras/physfsrwops.c create mode 100644 src/unison/physfs-1.1.1/extras/physfsrwops.h create mode 100644 src/unison/physfs-1.1.1/extras/physfsunpack.c create mode 100644 src/unison/physfs-1.1.1/extras/selfextract.c create mode 100644 src/unison/physfs-1.1.1/lzma/7zAlloc.h create mode 100644 src/unison/physfs-1.1.1/lzma/7zBuffer.c create mode 100644 src/unison/physfs-1.1.1/lzma/7zBuffer.h create mode 100644 src/unison/physfs-1.1.1/lzma/7zCrc.c create mode 100644 src/unison/physfs-1.1.1/lzma/7zCrc.h create mode 100644 src/unison/physfs-1.1.1/lzma/7zDecode.c create mode 100644 src/unison/physfs-1.1.1/lzma/7zDecode.h create mode 100644 src/unison/physfs-1.1.1/lzma/7zExtract.c create mode 100644 src/unison/physfs-1.1.1/lzma/7zExtract.h create mode 100644 src/unison/physfs-1.1.1/lzma/7zHeader.c create mode 100644 src/unison/physfs-1.1.1/lzma/7zHeader.h create mode 100644 src/unison/physfs-1.1.1/lzma/7zIn.c create mode 100644 src/unison/physfs-1.1.1/lzma/7zIn.h create mode 100644 src/unison/physfs-1.1.1/lzma/7zItem.c create mode 100644 src/unison/physfs-1.1.1/lzma/7zItem.h create mode 100644 src/unison/physfs-1.1.1/lzma/7zMethodID.c create mode 100644 src/unison/physfs-1.1.1/lzma/7zMethodID.h create mode 100644 src/unison/physfs-1.1.1/lzma/7zTypes.h create mode 100644 src/unison/physfs-1.1.1/lzma/LZMA-LICENSE.txt create mode 100644 src/unison/physfs-1.1.1/lzma/LzmaDecode.c create mode 100644 src/unison/physfs-1.1.1/lzma/LzmaDecode.h create mode 100644 src/unison/physfs-1.1.1/lzma/LzmaStateDecode.c create mode 100644 src/unison/physfs-1.1.1/lzma/LzmaStateDecode.h create mode 100644 src/unison/physfs-1.1.1/lzma/LzmaTypes.h create mode 100644 src/unison/physfs-1.1.1/makeos2.cmd create mode 100644 src/unison/physfs-1.1.1/physfs-1.1.1/CMakeFiles/CMakeError.log create mode 100644 src/unison/physfs-1.1.1/physfs-1.1.1/CMakeFiles/CMakeTmp/src.c create mode 100644 src/unison/physfs-1.1.1/physfs.c create mode 100644 src/unison/physfs-1.1.1/physfs.h create mode 100644 src/unison/physfs-1.1.1/physfs.spec.in create mode 100644 src/unison/physfs-1.1.1/physfs_byteorder.c create mode 100644 src/unison/physfs-1.1.1/physfs_casefolding.h create mode 100644 src/unison/physfs-1.1.1/physfs_internal.h create mode 100644 src/unison/physfs-1.1.1/physfs_platforms.h create mode 100644 src/unison/physfs-1.1.1/physfs_unicode.c create mode 100644 src/unison/physfs-1.1.1/platform/beos.cpp create mode 100644 src/unison/physfs-1.1.1/platform/macosx.c create mode 100644 src/unison/physfs-1.1.1/platform/os2.c create mode 100644 src/unison/physfs-1.1.1/platform/pocketpc.c create mode 100644 src/unison/physfs-1.1.1/platform/posix.c create mode 100644 src/unison/physfs-1.1.1/platform/unix.c create mode 100644 src/unison/physfs-1.1.1/platform/windows.c create mode 100644 src/unison/physfs-1.1.1/test/test_physfs.c create mode 100644 src/unison/physfs-1.1.1/test/wxtest_physfs.cpp create mode 100644 src/unison/physfs-1.1.1/zlib123/adler32.c create mode 100644 src/unison/physfs-1.1.1/zlib123/compress.c create mode 100644 src/unison/physfs-1.1.1/zlib123/crc32.c create mode 100644 src/unison/physfs-1.1.1/zlib123/crc32.h create mode 100644 src/unison/physfs-1.1.1/zlib123/deflate.c create mode 100644 src/unison/physfs-1.1.1/zlib123/deflate.h create mode 100644 src/unison/physfs-1.1.1/zlib123/gzio.c create mode 100644 src/unison/physfs-1.1.1/zlib123/infback.c create mode 100644 src/unison/physfs-1.1.1/zlib123/inffast.c create mode 100644 src/unison/physfs-1.1.1/zlib123/inffast.h create mode 100644 src/unison/physfs-1.1.1/zlib123/inffixed.h create mode 100644 src/unison/physfs-1.1.1/zlib123/inflate.c create mode 100644 src/unison/physfs-1.1.1/zlib123/inflate.h create mode 100644 src/unison/physfs-1.1.1/zlib123/inftrees.c create mode 100644 src/unison/physfs-1.1.1/zlib123/inftrees.h create mode 100644 src/unison/physfs-1.1.1/zlib123/trees.c create mode 100644 src/unison/physfs-1.1.1/zlib123/trees.h create mode 100644 src/unison/physfs-1.1.1/zlib123/uncompr.c create mode 100644 src/unison/physfs-1.1.1/zlib123/zconf.h create mode 100644 src/unison/physfs-1.1.1/zlib123/zlib.h create mode 100644 src/unison/physfs-1.1.1/zlib123/zutil.c create mode 100644 src/unison/physfs-1.1.1/zlib123/zutil.h create mode 100644 src/unison/src/vfs/FileSystem.cpp create mode 100644 src/unison/src/vfs/sdl/Utils.cpp create mode 100644 src/unison/src/vfs/stream.cpp create mode 100644 src/unison/src/video/Blittable.cpp create mode 100644 src/unison/src/video/Blitters.cpp create mode 100644 src/unison/src/video/Color.cpp create mode 100644 src/unison/src/video/Renderers.cpp create mode 100644 src/unison/src/video/Surface.cpp create mode 100644 src/unison/src/video/Texture.cpp create mode 100644 src/unison/src/video/Window.cpp create mode 100644 src/unison/src/video/auto/Renderer.cpp create mode 100644 src/unison/src/video/auto/Renderer.hpp create mode 100644 src/unison/src/video/backend/Texture.cpp create mode 100644 src/unison/src/video/opengl/Renderer.cpp create mode 100644 src/unison/src/video/opengl/Renderer.hpp create mode 100644 src/unison/src/video/opengl/SDL_gl.c create mode 100644 src/unison/src/video/opengl/SDL_gl.h create mode 100644 src/unison/src/video/opengl/SDL_glfuncs.h create mode 100644 src/unison/src/video/opengl/Texture.cpp create mode 100644 src/unison/src/video/opengl/Texture.hpp create mode 100644 src/unison/src/video/opengl/Window.cpp create mode 100644 src/unison/src/video/opengl/Window.hpp create mode 100644 src/unison/src/video/sdl/Blitters.cpp create mode 100644 src/unison/src/video/sdl/Renderer.cpp create mode 100644 src/unison/src/video/sdl/Renderer.hpp create mode 100644 src/unison/src/video/sdl/Texture.cpp create mode 100644 src/unison/src/video/sdl/Texture.hpp create mode 100644 src/unison/src/video/sdl/Window.cpp create mode 100644 src/unison/src/video/sdl/Window.hpp delete mode 100644 src/video/gl_lightmap.cpp delete mode 100644 src/video/gl_lightmap.hpp delete mode 100644 src/video/gl_renderer.cpp delete mode 100644 src/video/gl_renderer.hpp delete mode 100644 src/video/gl_surface_data.hpp delete mode 100644 src/video/gl_texture.cpp delete mode 100644 src/video/gl_texture.hpp delete mode 100644 src/video/lightmap.hpp delete mode 100644 src/video/renderer.hpp delete mode 100644 src/video/sdl_lightmap.cpp delete mode 100644 src/video/sdl_lightmap.hpp delete mode 100644 src/video/sdl_renderer.cpp delete mode 100644 src/video/sdl_renderer.hpp delete mode 100644 src/video/sdl_surface_data.hpp delete mode 100644 src/video/sdl_texture.cpp delete mode 100644 src/video/sdl_texture.hpp delete mode 100644 src/video/texture.hpp delete mode 100644 src/video/texture_manager.cpp delete mode 100644 src/video/texture_manager.hpp delete mode 100644 src/video/video_systems.cpp delete mode 100644 src/video/video_systems.hpp diff --git a/src/addon_manager.cpp b/src/addon_manager.cpp index 79e353741..c60a395a1 100644 --- a/src/addon_manager.cpp +++ b/src/addon_manager.cpp @@ -22,9 +22,12 @@ #include #include #include -#include +//#include +#include +#include #include #include +#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(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(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 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 search_path = fs.get_search_path(); + for(std::vector::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); } } diff --git a/src/gameconfig.cpp b/src/gameconfig.cpp index 060eed074..49728045f 100644 --- a/src/gameconfig.cpp +++ b/src/gameconfig.cpp @@ -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); diff --git a/src/gameconfig.hpp b/src/gameconfig.hpp index ac45730c7..2c39f939d 100644 --- a/src/gameconfig.hpp +++ b/src/gameconfig.hpp @@ -23,7 +23,7 @@ #include -#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; diff --git a/src/lisp/parser.cpp b/src/lisp/parser.cpp index a558adc1a..c59535f9d 100644 --- a/src/lisp/parser.cpp +++ b/src/lisp/parser.cpp @@ -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; diff --git a/src/main.cpp b/src/main.cpp index cca8615e3..1e102031f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -30,9 +30,9 @@ #include #include #include -#include +//#include #include -#include +//#include #ifdef MACOSX namespace supertux_apple { @@ -40,12 +40,15 @@ namespace supertux_apple { } #endif +#include +#include + #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 rc = fs.ls("/"); + for(std::vector::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 searchpath = fs.get_search_path(); + for(std::vector::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; } diff --git a/src/physfs/physfs_sdl.cpp b/src/physfs/physfs_sdl.cpp index 4ad2b6e34..76c3be98b 100644 --- a/src/physfs/physfs_sdl.cpp +++ b/src/physfs/physfs_sdl.cpp @@ -17,6 +17,22 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +#include +#include + +#include + +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 #include "physfs_sdl.hpp" @@ -100,3 +116,4 @@ SDL_RWops* get_physfs_SDLRWops(const std::string& filename) ops->close = funcClose; return ops; } +#endif diff --git a/src/physfs/physfs_stream.cpp b/src/physfs/physfs_stream.cpp index c4347b244..beb58480c 100644 --- a/src/physfs/physfs_stream.cpp +++ b/src/physfs/physfs_stream.cpp @@ -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 #include "physfs_stream.hpp" @@ -177,3 +178,4 @@ OFileStream::~OFileStream() { delete rdbuf(); } +#endif diff --git a/src/physfs/physfs_stream.hpp b/src/physfs/physfs_stream.hpp index 077a8760b..d861236d8 100644 --- a/src/physfs/physfs_stream.hpp +++ b/src/physfs/physfs_stream.hpp @@ -20,6 +20,12 @@ #ifndef __PHYSFSSTREAM_HPP__ #define __PHYSFSSTREAM_HPP__ +#include + +typedef Unison::VFS::istream IFileStream; +typedef Unison::VFS::ostream OFileStream; + +#if 0 #include #include #include @@ -74,5 +80,6 @@ public: OFileStream(const std::string& filename); ~OFileStream(); }; +#endif #endif diff --git a/src/sector.cpp b/src/sector.cpp index 57418fd83..cd4276ba7 100644 --- a/src/sector.cpp +++ b/src/sector.cpp @@ -28,7 +28,8 @@ #include #include #include -#include +//#include +#include #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 = ""; } diff --git a/src/tinygettext/tinygettext.cpp b/src/tinygettext/tinygettext.cpp index d22ae2a6f..d2df1e545 100644 --- a/src/tinygettext/tinygettext.cpp +++ b/src/tinygettext/tinygettext.cpp @@ -31,6 +31,7 @@ #include "tinygettext.hpp" #include "log.hpp" #include "physfs/physfs_stream.hpp" +#include #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 files = Unison::VFS::FileSystem::get().ls(*p); + for(std::vector::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 @@ -332,6 +367,15 @@ DictionaryManager::get_languages() for (SearchPath::iterator p = search_path.begin(); p != search_path.end(); ++p) { + std::vector files = Unison::VFS::FileSystem::get().ls(*p); + for(std::vector::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; } diff --git a/src/title.cpp b/src/title.cpp index a53f8aba5..3778b17a9 100644 --- a/src/title.cpp +++ b/src/title.cpp @@ -30,8 +30,9 @@ #include #include #include -#include -#include +//#include +//#include +#include #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 level_worlds; - char** files = PHYSFS_enumerateFiles("levels/"); + std::vector files = Unison::VFS::FileSystem::get().ls("levels/"); + for(std::vector::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 index 000000000..f3a758dbb --- /dev/null +++ b/src/unison/CMakeLists.txt @@ -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 index 000000000..efcf103f7 --- /dev/null +++ b/src/unison/Doxyfile @@ -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 , where is the value of +# the FILE_VERSION_FILTER tag, and 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 , where +# is the value of the INPUT_FILTER tag, and 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 index 000000000..36b7cd93c --- /dev/null +++ b/src/unison/LICENSE_1_0.txt @@ -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 index 000000000..40286a2e4 --- /dev/null +++ b/src/unison/include/unison/vfs/FileSystem.hpp @@ -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 +#include + +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 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 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 index 000000000..be5b3c8f2 --- /dev/null +++ b/src/unison/include/unison/vfs/sdl/Utils.hpp @@ -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 + +#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 index 000000000..42125636d --- /dev/null +++ b/src/unison/include/unison/vfs/stream.hpp @@ -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 + +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 index 000000000..d8febe3e0 --- /dev/null +++ b/src/unison/include/unison/video/Blittable.hpp @@ -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 +#include +#include + +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 §ion, 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 §ion, 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 ℑ + + /// 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 index 000000000..d201cb914 --- /dev/null +++ b/src/unison/include/unison/video/Blitters.hpp @@ -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 +#include + +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 index 000000000..6f9ee0074 --- /dev/null +++ b/src/unison/include/unison/video/Color.hpp @@ -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 index 000000000..576502a95 --- /dev/null +++ b/src/unison/include/unison/video/Coord.hpp @@ -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 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 Coord(const Coord &rhs) + : x(rhs.x), + y(rhs.y) + { + } + + /// Assignment operator + /// \param[in] rhs The source color + template Coord &operator =(const Coord &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 bool operator ==(const Coord &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 bool operator !=(const Coord &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 Coord &operator +=(const Coord &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 Coord &operator -=(const Coord &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 Coord &operator *=(const Coord &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 Coord &operator /=(const Coord &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 Coord &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 Coord &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 Coord &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 Coord &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 const Coord operator +(const Coord &lhs, const Coord &rhs) + { + return Coord(lhs) += rhs; + } + + /// Subtract two coordinates + /// \param[in] lhs The left operand + /// \param[in] rhs The right operand + /// \return The resultant coordinate + template const Coord operator -(const Coord &lhs, const Coord &rhs) + { + return Coord(lhs) -= rhs; + } + + /// Multiply two coordinates + /// \param[in] lhs The left operand + /// \param[in] rhs The right operand + /// \return The resultant coordinate + template const Coord operator *(const Coord &lhs, const Coord &rhs) + { + return Coord(lhs) *= rhs; + } + + /// Divide two coordinates + /// \param[in] lhs The left operand + /// \param[in] rhs The right operand + /// \return The resultant coordinate + template const Coord operator /(const Coord &lhs, const Coord &rhs) + { + return Coord(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 const Coord operator +(const Coord &lhs, const V &rhs) + { + return Coord(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 const Coord operator -(const Coord &lhs, const V &rhs) + { + return Coord(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 const Coord operator *(const Coord &lhs, const V &rhs) + { + return Coord(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 const Coord operator /(const Coord &lhs, const V &rhs) + { + return Coord(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 const Coord operator +(const V &lhs, const Coord &rhs) + { + return Coord(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 const Coord operator -(const V &lhs, const Coord &rhs) + { + return Coord(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 const Coord operator *(const V &lhs, const Coord &rhs) + { + return Coord(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 const Coord operator /(const V &lhs, const Coord &rhs) + { + return Coord(rhs) /= lhs; + } + + /// A point in 2-dimensional space + typedef Coord Point; + + /// A 2-dimensional area + typedef Coord Area; + } +} + +#endif diff --git a/src/unison/include/unison/video/DisplayList.hpp b/src/unison/include/unison/video/DisplayList.hpp new file mode 100644 index 000000000..1da6a039f --- /dev/null +++ b/src/unison/include/unison/video/DisplayList.hpp @@ -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 +#include +#include +#include + +#include +#include +#include + +namespace Unison +{ + namespace Video + { + class DisplayList : public Blittable + { + public: + DisplayList() : + requests() + { + } + + DisplayList(const std::map &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 pair) + { + requests.insert(requests.end(), pair.second.requests.begin(), pair.second.requests.end()); + } + std::vector 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 requests; + }; + } +} + +#endif diff --git a/src/unison/include/unison/video/Rect.hpp b/src/unison/include/unison/video/Rect.hpp new file mode 100644 index 000000000..7fee65fab --- /dev/null +++ b/src/unison/include/unison/video/Rect.hpp @@ -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 + +#include + +#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 ▭ + } + } + 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 index 000000000..ca496d1bd --- /dev/null +++ b/src/unison/include/unison/video/RenderOptions.hpp @@ -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 + +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 index 000000000..adb082198 --- /dev/null +++ b/src/unison/include/unison/video/Renderers.hpp @@ -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 +#include + +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 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 index 000000000..074140aac --- /dev/null +++ b/src/unison/include/unison/video/Surface.hpp @@ -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 +#include + +#include +#include +#include + +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 index 000000000..720980173 --- /dev/null +++ b/src/unison/include/unison/video/Texture.hpp @@ -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 +#include +#include + +#include +#include +#include + +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 save_textures(); + static void load_textures(const std::vector &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 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 index 000000000..5178af537 --- /dev/null +++ b/src/unison/include/unison/video/Window.hpp @@ -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 +#include +#include +#include +#include + +#include +#include +#include + +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 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 index 000000000..0f04b4ec3 --- /dev/null +++ b/src/unison/include/unison/video/backend/Renderer.hpp @@ -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 + +#include +#include + +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 index 000000000..0d82371bd --- /dev/null +++ b/src/unison/include/unison/video/backend/Texture.hpp @@ -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 +#include +#include + +#include +#include +#include + +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 save_textures(); + + /// Load the textures + static void load_textures(const std::vector &surfaces); + + /// Recover previously used but now unused texture IDs + /// \return A map of what IDs changed during recovery + static std::map 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 textures; + + /// The subset of all textures that have names + static std::map 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 index 000000000..136420c3b --- /dev/null +++ b/src/unison/include/unison/video/backend/Window.hpp @@ -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 +#include +#include +#include + +#include +#include + +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 index 000000000..c71854415 --- /dev/null +++ b/src/unison/include/unison/video/sdl/Blitters.hpp @@ -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 +#include +#include + +#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(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(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 index 000000000..805b7be52 --- /dev/null +++ b/src/unison/physfs-1.1.1/CHANGELOG.txt @@ -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 index 000000000..418a3375d --- /dev/null +++ b/src/unison/physfs-1.1.1/CMakeLists.txt @@ -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 index 000000000..105631c70 --- /dev/null +++ b/src/unison/physfs-1.1.1/CREDITS.txt @@ -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 index 000000000..0954d7aba --- /dev/null +++ b/src/unison/physfs-1.1.1/Doxyfile @@ -0,0 +1,1079 @@ +# Doxyfile 1.3.4 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = physfs + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +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 , where +# is the value of the INPUT_FILTER tag, and 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 index 000000000..7e89ac99f --- /dev/null +++ b/src/unison/physfs-1.1.1/INSTALL.txt @@ -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 index 000000000..3f0223b8d --- /dev/null +++ b/src/unison/physfs-1.1.1/LICENSE.txt @@ -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 + + +(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 index 000000000..9425051b2 --- /dev/null +++ b/src/unison/physfs-1.1.1/TODO.txt @@ -0,0 +1,45 @@ +Stuff that needs to be done and wishlist: + +These are in no particular order. +Some might be dupes, some might be done already. + +UNICODE: +- OS/2: Codepages. No full Unicode in the filesystem, but we can probably make + a conversion effort. + + +Stuff: +- Other archivers: perhaps tar(.gz|.bz2), RPM, ARJ, etc. These are less + important, since streaming archives aren't of much value to games (which + is why zipfiles are king: random access), but it could have uses for, say, + an installer/updater. +- Reduce malloc() pressure all over the place. We fragment memory like mad. +- profile string list interpolation. +- We have two different ways to find dir entries in zip.c. +- Do symlinks in zip archiver work when they point to dirs? +- Enable more warnings? +- Use __cdecl in physfs.h? +- Look for FIXMEs (many marked with "!!!" in comments). +- Find some way to relax or remove the security model for external tools. +- OSX shouldn't use ~/.app for userdir. +- fscanf and fprintf support in extras dir. +- Why do we call it openArchive and dirClose? +- Sanity check byte order at runtime. +- Memory locking? +- Find a better name than dvoid and fvoid. +- Can windows.c and pocketpc.c get merged? +- There's so much cut-and-paste between archivers...can this be reduced? +- General code audit. +- Multiple write dirs with mount points? +- Deprecate PHYSFS_setSaneConfig and move it to extras? +- Why is physfsrwops.c cut-and-pasted into the ruby bindings? +- Replace code from SDL... +- Should file enumeration return an error or set error state? +- Need "getmountpoint" command in test_physfs.c ... +- Look for calloc() calls that aren't going through the allocation hooks. +- Write up a simple HOWTO on embedding physicsfs in another project. +- Archivers need abstracted i/o to read from memory or files (archives in archives?) +- Probably other stuff. Requests and recommendations are welcome. + +// end of TODO.txt ... + 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 index 000000000..a5807434b --- /dev/null +++ b/src/unison/physfs-1.1.1/archivers/dir.c @@ -0,0 +1,283 @@ +/* + * Standard directory I/O support routines for PhysicsFS. + * + * Please see the file LICENSE.txt in the source's root directory. + * + * This file written by Ryan C. Gordon. + */ + +#include +#include +#include +#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 ", + "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 index 000000000..820a881eb --- /dev/null +++ b/src/unison/physfs-1.1.1/archivers/grp.c @@ -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 +#include +#include +#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 ", + "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 index 000000000..136b7cb60 --- /dev/null +++ b/src/unison/physfs-1.1.1/archivers/hog.c @@ -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 +#include +#include +#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 ", + "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 index 000000000..1f5262058 --- /dev/null +++ b/src/unison/physfs-1.1.1/archivers/lzma.c @@ -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 +#include + +#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 ", + "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 index 000000000..650b49bf0 --- /dev/null +++ b/src/unison/physfs-1.1.1/archivers/mvl.c @@ -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 +#include +#include +#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 ", + "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 index 000000000..f4aa7e7be --- /dev/null +++ b/src/unison/physfs-1.1.1/archivers/qpak.c @@ -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 +#include +#include +#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 ", + "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 index 000000000..fddc22a55 --- /dev/null +++ b/src/unison/physfs-1.1.1/archivers/wad.c @@ -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 +#include +#include +#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 ", + "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 index 000000000..33de47580 --- /dev/null +++ b/src/unison/physfs-1.1.1/archivers/zip.c @@ -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 +#include +#include +#ifndef _WIN32_WCE +#include +#include +#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, ¢_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 ", + "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 index 000000000..2ba488773 --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/PhysFS.NET/AssemblyInfo.cs @@ -0,0 +1,58 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("PhysFS.NET")] +[assembly: AssemblyDescription("PhysFS Bindings for .NET")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PhysFS.NET")] +[assembly: AssemblyCopyright("(c)2003 Gregory S. Read")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.0.*")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the project output directory which is +// %Project Directory%\obj\. 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 index 000000000..d27194688 --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/PhysFS.NET/PhysFS.NET.csproj @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + 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 index 000000000..93b44806d --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/PhysFS.NET/PhysFS.NET.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhysFS.NET", "PhysFS.NET.csproj", "{C6205A43-3D4D-41E6-872C-96CD7BE55230}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {C6205A43-3D4D-41E6-872C-96CD7BE55230}.Debug.ActiveCfg = Debug|.NET + {C6205A43-3D4D-41E6-872C-96CD7BE55230}.Debug.Build.0 = Debug|.NET + {C6205A43-3D4D-41E6-872C-96CD7BE55230}.Release.ActiveCfg = Release|.NET + {C6205A43-3D4D-41E6-872C-96CD7BE55230}.Release.Build.0 = Release|.NET + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal 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 index 000000000..bad6172dc --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/PhysFS.NET/PhysFS.cs @@ -0,0 +1,189 @@ +/* PhysFS.cs - (c)2003 Gregory S. Read + * Provides access to PhysFS API calls not specific to file handle access. + */ +using System; + +namespace PhysFS_NET +{ + public class PhysFS + { + /* Initialize + * Inits the PhysFS API. This normally does not need to be called unless + * the API has been manually deinitialized since the PhysFS_DLL class + * initializes just before the first call is made into the DLL. + * Parameters + * none + * Returns + * none + * Exceptions + * PhysFSException - An error occured in the PhysFS API + */ + public static void Initialize() + { + // Initialize the physfs library, raise an exception if error + if(PhysFS_DLL.PHYSFS_init("") == 0) + throw new PhysFSException(); + } + + /* Deinitialize + * Deinits the PhysFS API. It is recommended that this method be called + * by the application before exiting in order to gracefully deallocate + * resources and close all filehandles, etc. + * Parameters + * none + * Returns + * none + * Exceptions + * PhysFSException - An error occured in the PhysFS API + */ + public static void Deinitialize() + { + // Deinit, raise an exception if an error occured + if(PhysFS_DLL.PHYSFS_deinit() == 0) + throw new PhysFSException(); + } + + /* BaseDir + * Gets the base directory configured for PhysFS. See the PhysFS API + * documentation for more information. + * Parameters + * none + * Returns + * A string value representing the Base Directory + * Exceptions + * none + */ + public static string BaseDir + { + get + { + // Return the current base directory + return PhysFS_DLL.PHYSFS_getBaseDir(); + } + } + + /* WriteDir + * Gets or sets the write directory configured for PhysFS. See the PhysFS API + * documentation for more information. + * Parameters + * set - Path to set the WriteDir property to + * Returns + * A string value representing the Write Directory + * Exceptions + * PhysFSException - An error occured in the PhysFS API when + * settings the write directory. + */ + public static string WriteDir + { + get + { + // Return the current write directory + return PhysFS_DLL.PHYSFS_getWriteDir(); + } + set + { + // Set the write directory and raise an exception if an error occured + if(PhysFS_DLL.PHYSFS_setWriteDir(value) == 0) + throw new PhysFSException(); + } + } + + /* UserDir + * Gets or sets the write directory configured for PhysFS. See the PhysFS API + * documentation for more information. + * Parameters + * set - Path to set the WriteDir property to + * Returns + * A string value representing the Write Directory + * Exceptions + * PhysFSException - An error occured in the PhysFS API when + * settings the write directory. + */ + public static string UserDir + { + get + { + // Return the current user directory + return PhysFS_DLL.PHYSFS_getUserDir(); + } + } + public static void AddToSearchPath(string NewDir, bool Append) + { + if(PhysFS_DLL.PHYSFS_addToSearchPath(NewDir, Append?1:0) == 0) + throw new PhysFSException(); + } + public static void RemoveFromSearchPath(string OldDir) + { + if(PhysFS_DLL.PHYSFS_removeFromSearchPath(OldDir) == 0) + throw new PhysFSException(); + } + public unsafe static string[] GetSearchPath() + { + byte** p; // Searchpath list from PhysFS dll + string[] pathlist; // List converted to an array + + // Get the CDROM drive listing + p = PhysFS_DLL.PHYSFS_getSearchPath(); + // Convert the C-style array to a .NET style array + pathlist = PhysFS_DLL.BytePPToArray(p); + // Free the original list since we're done with it + PhysFS_DLL.PHYSFS_freeList(p); + + return pathlist; + } + public unsafe static string[] GetCDROMDrives() + { + byte** p; // CDROM list from PhysFS dll + string[] cdromlist; // List converted to an array + + // Get the CDROM drive listing + p = PhysFS_DLL.PHYSFS_getCdRomDirs(); + // Convert the C-style array to a .NET style array + cdromlist = PhysFS_DLL.BytePPToArray(p); + // Free the original list since we're done with it + PhysFS_DLL.PHYSFS_freeList(p); + + return cdromlist; + } + public static void MkDir(string Dirname) + { + if(PhysFS_DLL.PHYSFS_mkdir(Dirname) == 0) + throw new PhysFSException(); + } + public static void Delete(string Filename) + { + if(PhysFS_DLL.PHYSFS_delete(Filename) == 0) + throw new PhysFSException(); + } + public static string GetRealDir(string Filename) + { + string RetValue; + + RetValue = PhysFS_DLL.PHYSFS_getRealDir(Filename); + if(RetValue == null) + throw new PhysFSException("File not found in search path."); + + // Return the real file path of the specified filename + return RetValue; + } + public unsafe static string[] EnumerateFiles(string Dirname) + { + byte** p; // File list from PhysFS dll + string[] filelist; // List converted to an array + + // Get the CDROM drive listing + p = PhysFS_DLL.PHYSFS_enumerateFiles(Dirname); + // Convert the C-style array to a .NET style array + filelist = PhysFS_DLL.BytePPToArray(p); + // Free the original list since we're done with it + PhysFS_DLL.PHYSFS_freeList(p); + + return filelist; + } + public static bool IsDirectory(string Filename) + { + // Return true if non-zero, otherwise return false + return (PhysFS_DLL.PHYSFS_isDirectory(Filename) == 0)?false:true; + } + } +} 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 index 000000000..725b2c453 --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/PhysFS.NET/PhysFSFileStream.cs @@ -0,0 +1,194 @@ +/* PhysFSFileStream.cs - (c)2003 Gregory S. Read */ +using System; +using System.Collections; +using System.IO; + +namespace PhysFS_NET +{ + public enum PhysFSFileMode {Read, Write, Append}; + + // Our exception class we'll use for throwing all PhysFS API related exception + public class PhysFSException : IOException + { + public PhysFSException(string Message) : base(Message) {} + public PhysFSException() : base(PhysFS_DLL.PHYSFS_getLastError()) {} + } + + public unsafe class PhysFSFileStream : Stream + { + // ***Public properties*** + public override bool CanRead + { + get + { + // Reading is supported + return true; + } + } + + public override bool CanSeek + { + get + { + // Seek is supported + return true; + } + } + + public override bool CanWrite + { + get + { + // Writing is supported + return true; + } + } + + public override long Length + { + get + { + long TempLength; + TempLength = PhysFS_DLL.PHYSFS_fileLength(pHandle); + + // If call returned an error, throw an exception + if(TempLength == -1) + throw new PhysFSException(); + + return TempLength; + } + } + + public override long Position + { + get + { + long TempPosition; + TempPosition = PhysFS_DLL.PHYSFS_tell(pHandle); + + // If call returned an error, throw an exception + if(TempPosition == -1) + throw new PhysFSException(); + + return TempPosition; + } + set + { + // Seek from beginning of file using the position value + Seek(value, SeekOrigin.Begin); + } + } + + // ***Public methods*** + public PhysFSFileStream(string FileName, PhysFSFileMode FileMode, ulong BufferSize) + { + // Open the specified file with the appropriate file access + switch(FileMode) + { + case PhysFSFileMode.Read: + pHandle = PhysFS_DLL.PHYSFS_openRead(FileName); + break; + case PhysFSFileMode.Write: + pHandle = PhysFS_DLL.PHYSFS_openWrite(FileName); + break; + case PhysFSFileMode.Append: + pHandle = PhysFS_DLL.PHYSFS_openAppend(FileName); + break; + default: + throw new PhysFSException("Invalid FileMode specified"); + } + + // If handle is null, an error occured, so raise an exception + //!!! Does object get created if exception is thrown? + if(pHandle == null) + throw new PhysFSException(); + + // Set buffer size, raise an exception if an error occured + if(PhysFS_DLL.PHYSFS_setBuffer(pHandle, BufferSize) == 0) + throw new PhysFSException(); + } + + // This constructor sets the buffer size to 0 if not specified + public PhysFSFileStream(string FileName, PhysFSFileMode FileMode) : this(FileName, FileMode, 0) {} + + ~PhysFSFileStream() + { + // Don't close the handle if they've specifically closed it already + if(!Closed) + Close(); + } + + public override void Flush() + { + if(PhysFS_DLL.PHYSFS_flush(pHandle) == 0) + throw new PhysFSException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + long RetValue; + + fixed(byte *pbytes = &buffer[offset]) + { + // Read into our allocated pointer + RetValue = PhysFS_DLL.PHYSFS_read(pHandle, pbytes, sizeof(byte), (uint)count); + } + + if(RetValue == -1) + throw new PhysFSException(); + + // Return number of bytes read + // Note: This cast should be safe since we are only reading 'count' items, which + // is of type 'int'. + return (int)RetValue; + } + + public override void Write(byte[] buffer, int offset, int count) + { + long RetValue; + + fixed(byte* pbytes = &buffer[offset]) + { + // Write buffer + RetValue = PhysFS_DLL.PHYSFS_write(pHandle, pbytes, sizeof(byte), (uint)count); + } + + if(RetValue == -1) + throw new PhysFSException(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + // Only seeking from beginning is supported by PhysFS API + if(origin != SeekOrigin.Begin) + throw new PhysFSException("Only seek origin of \"Begin\" is supported"); + + // Seek to specified offset, raise an exception if error occured + if(PhysFS_DLL.PHYSFS_seek(pHandle, (ulong)offset) == 0) + throw new PhysFSException(); + + // Since we always seek from beginning, the offset is always + // the absolute position. + return offset; + } + + public override void SetLength(long value) + { + throw new NotSupportedException("SetLength method not supported in PhysFSFileStream objects."); + } + + public override void Close() + { + // Close the handle + if(PhysFS_DLL.PHYSFS_close(pHandle) == 0) + throw new PhysFSException(); + + // File has been closed. Rock. + Closed = true; + } + + // ***Private variables*** + private void *pHandle; + private bool Closed = false; + } +} \ 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 index 000000000..6d7d9dcbf --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/PhysFS.NET/PhysFS_DLL.cs @@ -0,0 +1,113 @@ +/* PhysFS_DLL - (c)2003 Gregory S. Read + * Internal class that provides direct access to the PhysFS DLL. It is + * not accessible outside of the PhysFS.NET assembly. + */ +using System.Collections; +using System.Runtime.InteropServices; + +namespace PhysFS_NET +{ + internal class PhysFS_DLL + { + /* Static constructor + * Initializes the PhysFS API before any method is called in this class. This + * relieves the user from having to explicitly initialize the API. + * Parameters + * none + * Returns + * none + * Exceptions + * PhysFSException - An error occured in the PhysFS API + */ + static PhysFS_DLL() + { + if(PHYSFS_init("") == 0) + throw new PhysFSException(); + } + + /* BytePPToArray + * Converts a C-style string array into a .NET managed string array + * Parameters + * C-style string array pointer returned from PhysFS + * Returns + * .NET managed string array + * Exceptions + * none + */ + public unsafe static string[] BytePPToArray(byte **bytearray) + { + byte** ptr; + byte* c; + string tempstr; + ArrayList MyArrayList = new ArrayList(); + string[] RetArray; + + for(ptr = bytearray; *ptr != null; ptr++) + { + tempstr = ""; + for(c = *ptr; *c != 0; c++) + { + tempstr += (char)*c; + } + + // Add string to our list + MyArrayList.Add(tempstr); + } + + // Return a normal array of the list + RetArray = new string[MyArrayList.Count]; + MyArrayList.CopyTo(RetArray, 0); + return RetArray; + } + + // Name of DLL to import + private const string PHYSFS_DLLNAME = "physfs.dll"; + + // DLL import declarations + [DllImport(PHYSFS_DLLNAME)] public static extern int PHYSFS_init(string argv0); + [DllImport(PHYSFS_DLLNAME)] public static extern int PHYSFS_deinit(); + [DllImport(PHYSFS_DLLNAME)] public static extern unsafe void PHYSFS_freeList(void *listVar); + [DllImport(PHYSFS_DLLNAME)] public static extern string PHYSFS_getLastError(); + [DllImport(PHYSFS_DLLNAME)] public static extern string PHYSFS_getDirSeparator(); + [DllImport(PHYSFS_DLLNAME)] public static extern void PHYSFS_permitSymbolicLinks(int allow); + [DllImport(PHYSFS_DLLNAME)] public static extern unsafe byte** PHYSFS_getCdRomDirs(); + [DllImport(PHYSFS_DLLNAME)] public static extern string PHYSFS_getBaseDir(); + [DllImport(PHYSFS_DLLNAME)] public static extern string PHYSFS_getUserDir(); + [DllImport(PHYSFS_DLLNAME)] public static extern string PHYSFS_getWriteDir(); + [DllImport(PHYSFS_DLLNAME)] public static extern int PHYSFS_setWriteDir(string newDir); + [DllImport(PHYSFS_DLLNAME)] public static extern int PHYSFS_addToSearchPath(string newDir, int appendToPath); + [DllImport(PHYSFS_DLLNAME)] public static extern int PHYSFS_removeFromSearchPath(string oldDir); + [DllImport(PHYSFS_DLLNAME)] public static extern unsafe byte** PHYSFS_getSearchPath(); + [DllImport(PHYSFS_DLLNAME)] public static extern int PHYSFS_setSaneConfig(string organization, + string appName, + string archiveExt, + int includeCdRoms, + int archivesFirst); + [DllImport(PHYSFS_DLLNAME)] public static extern int PHYSFS_mkdir(string dirName); + [DllImport(PHYSFS_DLLNAME)] public static extern int PHYSFS_delete(string filename); + [DllImport(PHYSFS_DLLNAME)] public static extern string PHYSFS_getRealDir(string filename); + [DllImport(PHYSFS_DLLNAME)] public static extern unsafe byte** PHYSFS_enumerateFiles(string dir); + [DllImport(PHYSFS_DLLNAME)] public static extern int PHYSFS_exists(string fname); + [DllImport(PHYSFS_DLLNAME)] public static extern int PHYSFS_isDirectory(string fname); + [DllImport(PHYSFS_DLLNAME)] public static extern int PHYSFS_isSymbolicLink(string fname); + [DllImport(PHYSFS_DLLNAME)] public static extern unsafe void* PHYSFS_openWrite(string filename); + [DllImport(PHYSFS_DLLNAME)] public static extern unsafe void* PHYSFS_openAppend(string filename); + [DllImport(PHYSFS_DLLNAME)] public static extern unsafe void* PHYSFS_openRead(string filename); + [DllImport(PHYSFS_DLLNAME)] public static extern unsafe int PHYSFS_close(void* handle); + [DllImport(PHYSFS_DLLNAME)] public static extern unsafe long PHYSFS_getLastModTime(string filename); + [DllImport(PHYSFS_DLLNAME)] public static extern unsafe long PHYSFS_read(void* handle, + void *buffer, + uint objSize, + uint objCount); + [DllImport(PHYSFS_DLLNAME)] public static extern unsafe long PHYSFS_write(void* handle, + void *buffer, + uint objSize, + uint objCount); + [DllImport(PHYSFS_DLLNAME)] public static extern unsafe int PHYSFS_eof(void* handle); + [DllImport(PHYSFS_DLLNAME)] public static extern unsafe long PHYSFS_tell(void* handle); + [DllImport(PHYSFS_DLLNAME)] public static extern unsafe int PHYSFS_seek(void* handle, ulong pos); + [DllImport(PHYSFS_DLLNAME)] public static extern unsafe long PHYSFS_fileLength(void* handle); + [DllImport(PHYSFS_DLLNAME)] public static extern unsafe int PHYSFS_setBuffer(void* handle, ulong bufsize); + [DllImport(PHYSFS_DLLNAME)] public static extern unsafe int PHYSFS_flush(void* handle); + } +} 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 index 000000000..aa1874c9b --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/PhysFS.NET/README.txt @@ -0,0 +1,10 @@ +PhysFS.NET is a library that encapsulates the PhysFS API into a .NET assembly. + +There are two class objects that are exposed in the assembly: + PhysFS.cs + This class exposes any non-filehandle specific functionality contained in + the PhysFS library. + PhysFSFileStream.cs + A System.IO.Stream derived class which provides file access via the + PhysFS API. Usage of this object is identical to a standard stream + object. \ 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 index 0000000000000000000000000000000000000000..3a5525fd794f7a7c5c8e6187f470ea3af38cd2b6 GIT binary patch literal 1078 zcmeHHJr05}7=1t!Hp3A*8IHkVf+j?-!eHY14Gtcw1Eb*_9>Bq^zETJ@GKj{_2j4$w zo9}xCh!8{T3=X##Skq>ikMjsvB|y%crWBM2iW(4pI}c%z6%lW!=~4v77#3{z!dmB1 z__&l)-{KUYR+|8|;wB^R|9ET$J@(@=#rd^=)qs85?vAy(PSF5CyNkus435LVkZ$rj zNw|JG-P7^hF<(;#o*Vk}5R#e|^13tBbQkeF?djULtvqyxd3<{9 literal 0 HcmV?d00001 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 index 000000000..9f89a3282 --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/AssemblyInfo.cs @@ -0,0 +1,58 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.0.*")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the project output directory which is +// %Project Directory%\obj\. 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 index 000000000..45af063ef --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/TestApp.csproj @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 index 000000000..5c3463dac --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/TestApp.sln @@ -0,0 +1,27 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApp", "TestApp.csproj", "{9C1ECC6B-16C7-42B3-BF7C-8BA8D81BA980}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhysFS.NET", "..\PhysFS.NET.csproj", "{C6205A43-3D4D-41E6-872C-96CD7BE55230}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {9C1ECC6B-16C7-42B3-BF7C-8BA8D81BA980}.Debug.ActiveCfg = Debug|.NET + {9C1ECC6B-16C7-42B3-BF7C-8BA8D81BA980}.Debug.Build.0 = Debug|.NET + {9C1ECC6B-16C7-42B3-BF7C-8BA8D81BA980}.Release.ActiveCfg = Release|.NET + {9C1ECC6B-16C7-42B3-BF7C-8BA8D81BA980}.Release.Build.0 = Release|.NET + {C6205A43-3D4D-41E6-872C-96CD7BE55230}.Debug.ActiveCfg = Debug|.NET + {C6205A43-3D4D-41E6-872C-96CD7BE55230}.Debug.Build.0 = Debug|.NET + {C6205A43-3D4D-41E6-872C-96CD7BE55230}.Release.ActiveCfg = Release|.NET + {C6205A43-3D4D-41E6-872C-96CD7BE55230}.Release.Build.0 = Release|.NET + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal 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 index 000000000..8688bffb5 --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/TestAppForm.cs @@ -0,0 +1,274 @@ +using System; +using System.Drawing; +using System.Collections; +using System.ComponentModel; +using System.Windows.Forms; +using System.Data; +using System.IO; +using PhysFS_NET; + +namespace TestApp +{ + /// + /// Summary description for Form1. + /// + 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; + /// + /// Required designer variable. + /// + private System.ComponentModel.Container components = null; + + public TestAppForm() + { + // + // Required for Windows Form Designer support + // + InitializeComponent(); + + // + // TODO: Add any constructor code after InitializeComponent call + // + } + + /// + /// Clean up any resources being used. + /// + protected override void Dispose( bool disposing ) + { + if( disposing ) + { + if (components != null) + { + components.Dispose(); + } + } + base.Dispose( disposing ); + } + + #region Windows Form Designer generated code + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + 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 + + /// + /// The main entry point for the application. + /// + [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 index 000000000..daf6eab59 --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/PhysFS.NET/TestApp/TestAppForm.resx @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + TestAppForm + + \ 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 index 000000000..c7e7b4924 --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/abs-file.h @@ -0,0 +1,165 @@ +/* + * stdio/physfs abstraction layer 2003-04-02 + * + * Adam D. Moss + * + * 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 +#include + +/* + * 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 : 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 +#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 index 000000000..f25d9bfed --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/casefolding.txt @@ -0,0 +1,1064 @@ +# CaseFolding-4.1.0.txt +# Date: 2005-03-26, 00:24:43 GMT [MD] +# +# Unicode Character Database +# Copyright (c) 1991-2005 Unicode, Inc. +# For terms of use, see http://www.unicode.org/terms_of_use.html +# For documentation, see UCD.html +# +# Case Folding Properties +# +# This file is a supplement to the UnicodeData file. +# It provides a case folding mapping generated from the Unicode Character Database. +# If all characters are mapped according to the full mapping below, then +# case differences (according to UnicodeData.txt and SpecialCasing.txt) +# are eliminated. +# +# The data supports both implementations that require simple case foldings +# (where string lengths don't change), and implementations that allow full case folding +# (where string lengths may grow). Note that where they can be supported, the +# full case foldings are superior: for example, they allow "MASSE" and "Maße" to match. +# +# All code points not listed in this file map to themselves. +# +# NOTE: case folding does not preserve normalization formats! +# +# For information on case folding, see +# UTR #21 Case Mappings, at http://www.unicode.org/unicode/reports/tr21/ +# +# ================================================================================ +# Format +# ================================================================================ +# The entries in this file are in the following machine-readable format: +# +# ; ; ; # +# +# 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 index 000000000..bb83d6a25 --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/globbing.c @@ -0,0 +1,159 @@ +/** \file globbing.c */ + +#include +#include +#include +#include + +#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 \n" + " where 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 index 000000000..378441309 --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/globbing.h @@ -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 index 000000000..16e807d99 --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/ignorecase.c @@ -0,0 +1,219 @@ +/** \file ignorecase.c */ + +#include +#include +#include +#include + +#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 index 000000000..1d9835515 --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/ignorecase.h @@ -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 index 000000000..7be2e931e --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/makecasefoldhashtable.pl @@ -0,0 +1,85 @@ +#!/usr/bin/perl -w + +use warnings; +use strict; + +print <<__EOF__; +/* + * This file is part of PhysicsFS (http://icculus.org/physfs/) + * + * This data generated by physfs/extras/makecasefoldhashtable.pl ... + * Do not manually edit this file! + * + * Please see the file LICENSE.txt in the source's root directory. + */ + +#ifndef __PHYSICSFS_INTERNAL__ +#error Do not include this header from your applications. +#endif + +__EOF__ + + +my @foldPairs; + +for (my $i = 0; $i < 256; $i++) { + $foldPairs[$i] = ''; +} + +open(FH,'<','casefolding.txt') or die("failed to open casefolding.txt: $!\n"); +while () { + 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 index 000000000..3f62f4d0d --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/makedist.sh @@ -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 index 000000000..687808dc3 --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/physfs_rb/installer.rb @@ -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 index 000000000..f344059cd --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/extconf.rb @@ -0,0 +1,9 @@ +require 'mkmf' + +$CFLAGS += `sdl-config --cflags`.chomp +$LDFLAGS += `sdl-config --libs`.chomp + +have_library "physfs", "PHYSFS_init" +have_library "SDL", "SDL_AllocRW" + +create_makefile "physfs_so" 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 index 000000000..29bd45482 --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/install.rb @@ -0,0 +1,7 @@ +#!/usr/local/bin/ruby + +if __FILE__ == $0 + require 'slimb/installer' + files = ["physfs.rb", "physfs_so.so"] + installer = Slimb::Installer.new.run files, ARGV +end 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 index 000000000..ac616c844 --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/make_install_test.sh @@ -0,0 +1,9 @@ +#!/bin/sh +ruby extconf.rb +make +cd .. +ruby installer.rb +cd physfs +ruby install.rb +cd test +ruby test_physfs.rb \ 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 index 000000000..88da331be --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/physfs.rb @@ -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 index 000000000..8dd23bffb --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/physfsrwops.c @@ -0,0 +1,192 @@ +/* + * This code provides a glue layer between PhysicsFS and Simple Directmedia + * Layer's (SDL) RWops i/o abstraction. + * + * License: this code is public domain. I make no warranty that it is useful, + * correct, harmless, or environmentally safe. + * + * This particular file may be used however you like, including copying it + * verbatim into a closed-source project, exploiting it commercially, and + * removing any trace of my name from the source (although I hope you won't + * do that). I welcome enhancements and corrections to this file, but I do + * not require you to send me patches if you make changes. + * + * Unless otherwise stated, the rest of PhysicsFS falls under the GNU Lesser + * General Public License: http://www.gnu.org/licenses/lgpl.txt + * + * SDL falls under the LGPL, too. You can get SDL at http://www.libsdl.org/ + * + * This file was written by Ryan C. Gordon. (icculus@icculus.org). + */ + +#include /* 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 index 000000000..5ff519a1f --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/physfsrwops.h @@ -0,0 +1,87 @@ +/* + * This code provides a glue layer between PhysicsFS and Simple Directmedia + * Layer's (SDL) RWops i/o abstraction. + * + * License: this code is public domain. I make no warranty that it is useful, + * correct, harmless, or environmentally safe. + * + * This particular file may be used however you like, including copying it + * verbatim into a closed-source project, exploiting it commercially, and + * removing any trace of my name from the source (although I hope you won't + * do that). I welcome enhancements and corrections to this file, but I do + * not require you to send me patches if you make changes. + * + * Unless otherwise stated, the rest of PhysicsFS falls under the GNU Lesser + * General Public License: http://www.gnu.org/licenses/lgpl.txt + * + * SDL falls under the LGPL, too. You can get SDL at http://www.libsdl.org/ + * + * This file was written by Ryan C. Gordon. (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 index 000000000..043d9117b --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_physfs.c @@ -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 index 000000000..ca820366d --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_physfs.h @@ -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 index 000000000..3e50880a3 --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_physfs_file.c @@ -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 index 000000000..5cc1b218b --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_physfs_file.h @@ -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 index 000000000..6574906a6 --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_sdl_rwops.c @@ -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 index 000000000..05f51bccf --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/rb_sdl_rwops.h @@ -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 index 000000000..3f194c192 --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/physfs_rb/physfs/test/test_physfs.rb @@ -0,0 +1,358 @@ +# +# PhysicsFS test program - mimics real physfs_test +# +require 'readline' +require 'physfs' + +def die msg + puts "#{msg} - reason: #{PhysicsFS.last_error}" +end + +# +# parse line to command and args +# +def parse line + return false if line.nil? + + if line.strip =~ /^(.*?) (?: (?:\s+(.*)) | $)/x + run $1, $2 + else + false + end +end + +# +# parse command args +# +def parse_args args + args.strip! + + dquoted = /^ " (.*?) "/x + squoted = /^ ' (.*?) '/x + unquoted = /^([^\s\'\"]+)/ + + regexps = [dquoted, squoted, unquoted] + + result = [] + while args != "" + regexps.each do |r| + if args =~ r + result << $1 + args.sub! r, "" + args.sub!(/\s+/, "") + break + end + end + end + result +end + +def usage cmd, prefix = "usage: " + print prefix + args = Commands::HELP[cmd] + if args + print cmd + args.scan(/\w+/).each {|x| + print " <#{x}>" + } + puts + else + puts %|#{cmd} (no arguments)| + end +end + +# commands go below +module Commands + HELP = { + "init" => "argv0", + "addarchive" => "archiveLocation append", + "removearchive" => "archiveLocation", + "enumerate" => "dirToEnumerate", + "ls" => "dirToEnumerate", + "setwritedir" => "newWriteDir", + "permitsymlinks" => "1or0", + "setsaneconfig" => "org appName arcExt includeCdRoms archivesFirst", + "mkdir" => "dirToMk", + "delete" => "dirToDelete", + "getrealdir" => "fileToFind", + "exists" => "fileToCheck", + "isdir" => "fileToCheck", + "issymlink" => "fileToCheck", + "cat" => "fileToCat", + "filelength" => "fileToCheck", + "append" => "fileToAppend", + "write" => "fileToCreateOrTrash", + "getlastmodtime" => "fileToExamine" + } + + def quit_cmd + exit + end + + alias q_cmd quit_cmd + + def help_cmd + commands = ::Commands.instance_methods.grep(/_cmd$/).sort + puts "Commands:" + commands.each do |c| + usage c.sub("_cmd", ""), " - " + end + + true + end + + def e val + if val + puts "Successful." + else + puts "Failure. reason: #{PhysicsFS.last_error}" + end + true + end + + def init_cmd arg + e PhysicsFS.init(arg) + end + + def deinit_cmd + e PhysicsFS.deinit + end + + def addarchive_cmd archive, append + e PhysicsFS.add_to_search_path(archive, append) + end + + def removearchive_cmd archive + e PhysicsFS.remove_from_search_path archive + end + + def enumerate_cmd path + entries = PhysicsFS.enumerate(path) + entries.each {|x| + puts x + } + true + end + + alias ls_cmd enumerate_cmd + + def getlasterror_cmd + puts "Last error is [#{PhysicsFS.last_error}]" + true + end + + def getdirsep_cmd + puts "Directory separator is [#{PhysicsFS.dir_separator}]" + true + end + + def getcdromdirs_cmd + dirs = PhysicsFS.cdrom_dirs + dirs.each {|x| + puts x + } + puts " total [#{dirs.length}] drives." + true + end + + def getsearchpath_cmd + spath = PhysicsFS.search_path + spath.each {|x| + puts x + } + puts "total [#{spath.length}] directories." + true + end + + def getbasedir_cmd + dir = PhysicsFS.base_dir + puts dir if dir + true + end + + def getuserdir_cmd + puts PhysicsFS.user_dir + true + end + + def getwritedir_cmd + dir = PhysicsFS.write_dir + if dir + puts "Write directory is [#{dir}]." + else + puts "No write directory defined." + end + true + end + + def setwritedir_cmd dir + e(PhysicsFS.write_dir = dir) + end + + def permitsymlinks_cmd val + if val.to_i == 1 + PhysicsFS.permit_symlinks true + puts "Symlinks are now permitted" + else + PhysicsFS.permit_symlinks false + puts "Symlinks are now forbidden" + end + true + end + + def setsaneconfig_cmd org, appname, ext, includeCdroms, archivesFirst + includeCdroms = includeCdroms.to_i == 1 + archiveFirst = archivesFirst == 1 + e PhysicsFS.set_sane_config(org, appname, ext, includeCdroms, archivesFirst) + end + + def mkdir_cmd dir + e PhysicsFS.mkdir(dir) + end + + def delete_cmd dir + e PhysicsFS.delete(dir) + end + + def getrealdir_cmd file + dir = PhysicsFS.real_dir file + if dir + puts "Found at [#{dir}]" + else + puts "Not found." + end + true + end + + def exists_cmd file + if PhysicsFS.exists? file + puts "File exists" + else + puts "File does not exist" + end + true + end + + def isdir_cmd file + if PhysicsFS.is_directory? file + puts "File is a directory" + else + puts "File is NOT a directory" + end + true + end + + def issymlink_cmd file + if PhysicsFS.is_symlink? file + puts "File is a symlink" + else + puts "File is NOT a symlink" + end + true + end + + def cat_cmd filename + file = PhysicsFS.open_read filename + if file.nil? + puts "failed to open. reason: #{PhysicsFS.last_error}" + return true + end + + puts file.cat + true + end + + def filelength_cmd filename + file = PhysicsFS.open_read filename + if file.nil? + puts "failed to open. reason: #{PhysicsFS.last_error}" + return true + end + + puts file.length + file.close + true + end + + WRITE_STR = "Rubyfied PhysicsFS works just fine.\n\n" + + def append_cmd filename + file = PhysicsFS.open_append filename + if file.nil? + puts "failed to open. reason: #{PhysicsFS.last_error}" + return true + end + + file.write WRITE_STR, 1, WRITE_STR.length + file.close + true + end + + def write_cmd filename + file = PhysicsFS.open_write filename + if file.nil? + puts "failed to open. reason: #{PhysicsFS.last_error}" + return true + end + + file.write_str WRITE_STR + file.close + true + end + + def getlastmodtime_cmd filename + t = PhysicsFS.last_mod_time filename + if t == -1 + puts "failed to determin. reason: #{PhysicsFS.last_error}" + else + puts "Last modified: #{Time.at(t)}" + end + true + end +end + +include Commands + +def run command, args + if args + args = parse_args args + else + args = [] + end + + begin + cmd = method "#{command}_cmd" + if args.length == cmd.arity + return cmd.call *args + else + usage command + true + end + rescue NameError + puts 'Unknown command. Enter "help" for instructions.' + true + end +end + +if __FILE__ == $0 + + PhysicsFS.init($0) or die "PhysicsFS init failed" + + puts "PhysicsFS version: #{PhysicsFS.version}" + puts + + puts "Supported archives: " + puts PhysicsFS.supported_archives + puts + + puts 'Enter commands. Enter "help" for instructions.' + + loop { + line = Readline::readline "physfs_rb> ", true + break unless parse line + } +end + + + + 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 index 000000000..d0920737d --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/physfshttpd.c @@ -0,0 +1,291 @@ +/* + * This is a quick and dirty HTTP server that uses PhysicsFS to retrieve + * files. It is not robust at all, probably buggy, and definitely poorly + * designed. It's just meant to show that it can be done. + * + * Basically, you compile this code, and run it: + * ./physfshttpd archive1.zip archive2.zip /path/to/a/real/dir etc... + * + * The files are appended in order to the PhysicsFS search path, and when + * a client request comes it, it looks for the file in said search path. + * + * My goal was to make this work in less than 300 lines of C, so again, it's + * not to be used for any serious purpose. Patches to make this application + * suck less will be readily and gratefully accepted. + * + * Command line I used to build this on Linux: + * gcc -Wall -Werror -g -o bin/physfshttpd extras/physfshttpd.c -lphysfs + * + * License: this code is public domain. I make no warranty that it is useful, + * correct, harmless, or environmentally safe. + * + * This particular file may be used however you like, including copying it + * verbatim into a closed-source project, exploiting it commercially, and + * removing any trace of my name from the source (although I hope you won't + * do that). I welcome enhancements and corrections to this file, but I do + * not require you to send me patches if you make changes. This code has + * NO WARRANTY. + * + * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license. + * Please see LICENSE.txt in the root of the source tree. + * + * This file was written by Ryan C. Gordon. (icculus@icculus.org). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef LACKING_SIGNALS +#include +#endif + +#ifndef LACKING_PROTOENT +#include +#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" +"404 Not Found\n" +"Can't find that.\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 [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 index 000000000..a6c881589 --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/physfsrwops.c @@ -0,0 +1,193 @@ +/* + * This code provides a glue layer between PhysicsFS and Simple Directmedia + * Layer's (SDL) RWops i/o abstraction. + * + * License: this code is public domain. I make no warranty that it is useful, + * correct, harmless, or environmentally safe. + * + * This particular file may be used however you like, including copying it + * verbatim into a closed-source project, exploiting it commercially, and + * removing any trace of my name from the source (although I hope you won't + * do that). I welcome enhancements and corrections to this file, but I do + * not require you to send me patches if you make changes. This code has + * NO WARRANTY. + * + * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license. + * Please see LICENSE.txt in the root of the source tree. + * + * SDL falls under the LGPL license. You can get SDL at http://www.libsdl.org/ + * + * This file was written by Ryan C. Gordon. (icculus@icculus.org). + */ + +#include /* 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 index 000000000..406fba6f6 --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/physfsrwops.h @@ -0,0 +1,88 @@ +/* + * This code provides a glue layer between PhysicsFS and Simple Directmedia + * Layer's (SDL) RWops i/o abstraction. + * + * License: this code is public domain. I make no warranty that it is useful, + * correct, harmless, or environmentally safe. + * + * This particular file may be used however you like, including copying it + * verbatim into a closed-source project, exploiting it commercially, and + * removing any trace of my name from the source (although I hope you won't + * do that). I welcome enhancements and corrections to this file, but I do + * not require you to send me patches if you make changes. This code has + * NO WARRANTY. + * + * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license. + * Please see LICENSE.txt in the root of the source tree. + * + * SDL falls under the LGPL license. You can get SDL at http://www.libsdl.org/ + * + * This file was written by Ryan C. Gordon. (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 index 000000000..1d26502d7 --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/physfsunpack.c @@ -0,0 +1,181 @@ +#include +#include +#include +#include + +#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 \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 index 000000000..3568d0133 --- /dev/null +++ b/src/unison/physfs-1.1.1/extras/selfextract.c @@ -0,0 +1,66 @@ +/* + * This code shows how to read a zipfile included in an app's binary. + * + * License: this code is public domain. I make no warranty that it is useful, + * correct, harmless, or environmentally safe. + * + * This particular file may be used however you like, including copying it + * verbatim into a closed-source project, exploiting it commercially, and + * removing any trace of my name from the source (although I hope you won't + * do that). I welcome enhancements and corrections to this file, but I do + * not require you to send me patches if you make changes. This code has + * NO WARRANTY. + * + * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license. + * Please see LICENSE.txt in the root of the source tree. + * + * This file was written by Ryan C. Gordon. (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 +#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 index 000000000..4ca4170ca --- /dev/null +++ b/src/unison/physfs-1.1.1/lzma/7zAlloc.h @@ -0,0 +1,20 @@ +/* 7zAlloc.h */ + +#ifndef __7Z_ALLOC_H +#define __7Z_ALLOC_H + +#include + +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 index 000000000..3c4b71e80 --- /dev/null +++ b/src/unison/physfs-1.1.1/lzma/7zBuffer.c @@ -0,0 +1,29 @@ +/* 7zBuffer.c */ + +#include "7zBuffer.h" +#include "7zAlloc.h" + +void SzByteBufferInit(CSzByteBuffer *buffer) +{ + buffer->Capacity = 0; + buffer->Items = 0; +} + +int SzByteBufferCreate(CSzByteBuffer *buffer, size_t newCapacity, void * (*allocFunc)(size_t size)) +{ + buffer->Capacity = newCapacity; + if (newCapacity == 0) + { + buffer->Items = 0; + return 1; + } + buffer->Items = (Byte *)allocFunc(newCapacity); + return (buffer->Items != 0); +} + +void SzByteBufferFree(CSzByteBuffer *buffer, void (*freeFunc)(void *)) +{ + freeFunc(buffer->Items); + buffer->Items = 0; + buffer->Capacity = 0; +} 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 index 000000000..17e59060f --- /dev/null +++ b/src/unison/physfs-1.1.1/lzma/7zBuffer.h @@ -0,0 +1,19 @@ +/* 7zBuffer.h */ + +#ifndef __7Z_BUFFER_H +#define __7Z_BUFFER_H + +#include +#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 index 000000000..977384042 --- /dev/null +++ b/src/unison/physfs-1.1.1/lzma/7zCrc.c @@ -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 index 000000000..adcc563af --- /dev/null +++ b/src/unison/physfs-1.1.1/lzma/7zCrc.h @@ -0,0 +1,24 @@ +/* 7zCrc.h */ + +#ifndef __7Z_CRC_H +#define __7Z_CRC_H + +#include + +#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 index 000000000..bda09cb0c --- /dev/null +++ b/src/unison/physfs-1.1.1/lzma/7zDecode.c @@ -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 index 000000000..74bb180fd --- /dev/null +++ b/src/unison/physfs-1.1.1/lzma/7zDecode.h @@ -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 index 000000000..6ef872c31 --- /dev/null +++ b/src/unison/physfs-1.1.1/lzma/7zExtract.c @@ -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 index 000000000..e9a4fb4e3 --- /dev/null +++ b/src/unison/physfs-1.1.1/lzma/7zExtract.h @@ -0,0 +1,40 @@ +/* 7zExtract.h */ + +#ifndef __7Z_EXTRACT_H +#define __7Z_EXTRACT_H + +#include "7zIn.h" + +/* + SzExtract extracts file from archive + + *outBuffer must be 0 before first call for each new archive. + + Extracting cache: + If you need to decompress more than one file, you can send + these values from previous call: + *blockIndex, + *outBuffer, + *outBufferSize + You can consider "*outBuffer" as cache of solid block. If your archive is solid, + it will increase decompression speed. + + If you use external function, you can declare these 3 cache variables + (blockIndex, outBuffer, outBufferSize) as static in that external function. + + Free *outBuffer and set *outBuffer to 0, if you want to flush cache. +*/ + +SZ_RESULT SzExtract( + ISzInStream *inStream, + CArchiveDatabaseEx *db, + UInt32 fileIndex, /* index of file */ + UInt32 *blockIndex, /* index of solid block */ + Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */ + size_t *outBufferSize, /* buffer size for output buffer */ + size_t *offset, /* offset of stream for required file in *outBuffer */ + size_t *outSizeProcessed, /* size of file in *outBuffer */ + ISzAlloc *allocMain, + ISzAlloc *allocTemp); + +#endif 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 index 000000000..3be4bc27e --- /dev/null +++ b/src/unison/physfs-1.1.1/lzma/7zHeader.c @@ -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 index 000000000..0356aaa6b --- /dev/null +++ b/src/unison/physfs-1.1.1/lzma/7zHeader.h @@ -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 index 000000000..ab32ea990 --- /dev/null +++ b/src/unison/physfs-1.1.1/lzma/7zIn.c @@ -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 &dataVector, + CObjectVector &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 index 000000000..6bfa2a709 --- /dev/null +++ b/src/unison/physfs-1.1.1/lzma/7zIn.h @@ -0,0 +1,55 @@ +/* 7zIn.h */ + +#ifndef __7Z_IN_H +#define __7Z_IN_H + +#include "7zHeader.h" +#include "7zItem.h" +#include "7zAlloc.h" + +typedef struct _CInArchiveInfo +{ + CFileSize StartPositionAfterHeader; + CFileSize DataStartPosition; +}CInArchiveInfo; + +typedef struct _CArchiveDatabaseEx +{ + CArchiveDatabase Database; + CInArchiveInfo ArchiveInfo; + UInt32 *FolderStartPackStreamIndex; + CFileSize *PackStreamStartPositions; + UInt32 *FolderStartFileIndex; + UInt32 *FileIndexToFolderIndexMap; +}CArchiveDatabaseEx; + +void SzArDbExInit(CArchiveDatabaseEx *db); +void SzArDbExFree(CArchiveDatabaseEx *db, void (*freeFunc)(void *)); +CFileSize SzArDbGetFolderStreamPos(CArchiveDatabaseEx *db, UInt32 folderIndex, UInt32 indexInFolder); +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 index 000000000..2a408050f --- /dev/null +++ b/src/unison/physfs-1.1.1/lzma/7zItem.c @@ -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 index 000000000..876539a98 --- /dev/null +++ b/src/unison/physfs-1.1.1/lzma/7zItem.h @@ -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 index 000000000..5047359f3 --- /dev/null +++ b/src/unison/physfs-1.1.1/lzma/7zMethodID.c @@ -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 index 000000000..162fcd15b --- /dev/null +++ b/src/unison/physfs-1.1.1/lzma/7zMethodID.h @@ -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 index 000000000..60dd68c38 --- /dev/null +++ b/src/unison/physfs-1.1.1/lzma/7zTypes.h @@ -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 index 000000000..d4e0f9f26 --- /dev/null +++ b/src/unison/physfs-1.1.1/lzma/LZMA-LICENSE.txt @@ -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 index 000000000..cb8345377 --- /dev/null +++ b/src/unison/physfs-1.1.1/lzma/LzmaDecode.c @@ -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 index 000000000..2870eeb9c --- /dev/null +++ b/src/unison/physfs-1.1.1/lzma/LzmaDecode.h @@ -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 index 000000000..e69de29bb 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 index 000000000..e69de29bb 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 index 000000000..288c5e45d --- /dev/null +++ b/src/unison/physfs-1.1.1/lzma/LzmaTypes.h @@ -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 +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 index 000000000..b1fb4c07f --- /dev/null +++ b/src/unison/physfs-1.1.1/makeos2.cmd @@ -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 index 000000000..243088e14 --- /dev/null +++ b/src/unison/physfs-1.1.1/physfs-1.1.1/CMakeFiles/CMakeError.log @@ -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 index 000000000..65674d026 --- /dev/null +++ b/src/unison/physfs-1.1.1/physfs-1.1.1/CMakeFiles/CMakeTmp/src.c @@ -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 index 000000000..aeb0fc4b0 --- /dev/null +++ b/src/unison/physfs-1.1.1/physfs.c @@ -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 +#include +#include +#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 index 000000000..903863254 --- /dev/null +++ b/src/unison/physfs-1.1.1/physfs.h @@ -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. Any sorting you find in + * these callbacks is just pure luck. Do not rely on it. + * + * \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 index 000000000..020ac2945 --- /dev/null +++ b/src/unison/physfs-1.1.1/physfs.spec.in @@ -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 +- Updated filenames in documents. + +* Thu Dec 18 2002 Edward Rudd +- added zlib_license_change.txt to documents + +* Wed Jul 10 2002 Edward Rudd +- added doxygen to build requirements + +* Wed Jul 10 2002 Edward Rudd +- updated to release 0.17 + +* Tue May 15 2002 Edward Rudd +- updated to latest CVS and modified spec file to use + the autoconf/automake support in the latest CVS + +* Tue Apr 30 2002 Edward Rudd +- 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 index 000000000..1e6742eb9 --- /dev/null +++ b/src/unison/physfs-1.1.1/physfs_byteorder.c @@ -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 +#include + +#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 +#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 index 000000000..0e50f1e7d --- /dev/null +++ b/src/unison/physfs-1.1.1/physfs_casefolding.h @@ -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 index 000000000..f9da66e15 --- /dev/null +++ b/src/unison/physfs-1.1.1/physfs_internal.h @@ -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 /* make sure NULL is defined... */ + +#ifdef HAVE_ASSERT_H +#include +#elif (!defined assert) +#define assert(x) +#endif + +/* !!! FIXME: remove this when revamping stack allocation code... */ +#ifdef _MSC_VER +#include +#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 "¥  à娢, ­¥¯®á।á⢥­­ë© ¢¢®¤/¢ë¢®¤ ä ©«®¢®© á¨á⥬ë" + #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_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 index 000000000..9f95a890e --- /dev/null +++ b/src/unison/physfs-1.1.1/physfs_platforms.h @@ -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 index 000000000..030bcc869 --- /dev/null +++ b/src/unison/physfs-1.1.1/physfs_unicode.c @@ -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 index 000000000..aac27eb4d --- /dev/null +++ b/src/unison/physfs-1.1.1/platform/beos.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "physfs_internal.h" + + +int __PHYSFS_platformInit(void) +{ + return(1); /* always succeed. */ +} /* __PHYSFS_platformInit */ + + +int __PHYSFS_platformDeinit(void) +{ + return(1); /* always succeed. */ +} /* __PHYSFS_platformDeinit */ + + +static char *getMountPoint(const char *devname) +{ + 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 index 000000000..4dde270c3 --- /dev/null +++ b/src/unison/physfs-1.1.1/platform/macosx.c @@ -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 +#include +#include +#include +#include + +/* 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 index 000000000..0fe2308ac --- /dev/null +++ b/src/unison/physfs-1.1.1/platform/os2.c @@ -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 + +#include +#include +#include +#include +#include +#include + +#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, + ¶m, 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(¤tDisk, &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 index 000000000..badb0db31 --- /dev/null +++ b/src/unison/physfs-1.1.1/platform/pocketpc.c @@ -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 +#include + +#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 index 000000000..005125560 --- /dev/null +++ b/src/unison/physfs-1.1.1/platform/posix.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef PHYSFS_HAVE_LLSEEK +#include +#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 index 000000000..2b47cc990 --- /dev/null +++ b/src/unison/physfs-1.1.1/platform/unix.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if (!defined PHYSFS_NO_PTHREADS_SUPPORT) +#include +#endif + +#ifdef PHYSFS_HAVE_SYS_UCRED_H +# ifdef PHYSFS_HAVE_MNTENT_H +# undef PHYSFS_HAVE_MNTENT_H /* don't do both... */ +# endif +# include +#endif + +#ifdef PHYSFS_HAVE_MNTENT_H +#include +#endif + +#include "physfs_internal.h" + + +int __PHYSFS_platformInit(void) +{ + return(1); /* always succeed. */ +} /* __PHYSFS_platformInit */ + + +int __PHYSFS_platformDeinit(void) +{ + return(1); /* always succeed. */ +} /* __PHYSFS_platformDeinit */ + + +#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 index 000000000..c9f9ee894 --- /dev/null +++ b/src/unison/physfs-1.1.1/platform/windows.c @@ -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 +#include +#include +#include +#include +#include +#include + +#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 index 000000000..33c3f7456 --- /dev/null +++ b/src/unison/physfs-1.1.1/test/test_physfs.c @@ -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 +#include +#include +#include + +#if (defined __MWERKS__) +#include +#endif + +#if (defined PHYSFS_HAVE_READLINE) +#include +#include +#include +#endif + +#include + +#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, "" }, + { "deinit", cmd_deinit, 0, NULL }, + { "addarchive", cmd_addarchive, 2, " " }, + { "mount", cmd_mount, 3, " " }, + { "removearchive", cmd_removearchive, 1, "" }, + { "enumerate", cmd_enumerate, 1, "" }, + { "ls", cmd_enumerate, 1, "" }, + { "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, "" }, + { "permitsymlinks", cmd_permitsyms, 1, "<1or0>" }, + { "setsaneconfig", cmd_setsaneconfig, 5, " " }, + { "mkdir", cmd_mkdir, 1, "" }, + { "delete", cmd_delete, 1, "" }, + { "getrealdir", cmd_getrealdir, 1, "" }, + { "exists", cmd_exists, 1, "" }, + { "isdir", cmd_isdir, 1, "" }, + { "issymlink", cmd_issymlink, 1, "" }, + { "cat", cmd_cat, 1, "" }, + { "filelength", cmd_filelength, 1, "" }, + { "append", cmd_append, 1, "" }, + { "write", cmd_write, 1, "" }, + { "getlastmodtime", cmd_getlastmodtime, 1, "" }, + { "setbuffer", cmd_setbuffer, 1, "" }, + { "stressbuffer", cmd_stressbuffer, 1, "" }, + { 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 index 000000000..e762633e5 --- /dev/null +++ b/src/unison/physfs-1.1.1/test/wxtest_physfs.cpp @@ -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 +#endif + +#include +#include +#include +#include +#include + +#include +#include + +#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, "" }, + { "exists", cmd_exists, 1, "" }, + { "isdir", cmd_isdir, 1, "" }, + { "issymlink", cmd_issymlink, 1, "" }, + { "filelength", cmd_filelength, 1, "" }, + { "getlastmodtime", cmd_getlastmodtime, 1, "" }, +*/ +}; + + +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 index 000000000..007ba2627 --- /dev/null +++ b/src/unison/physfs-1.1.1/zlib123/adler32.c @@ -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 index 000000000..df04f0148 --- /dev/null +++ b/src/unison/physfs-1.1.1/zlib123/compress.c @@ -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 index 000000000..f658a9ef5 --- /dev/null +++ b/src/unison/physfs-1.1.1/zlib123/crc32.c @@ -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 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 +# 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 +# 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 index 000000000..8053b6117 --- /dev/null +++ b/src/unison/physfs-1.1.1/zlib123/crc32.h @@ -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 index 000000000..29ce1f64a --- /dev/null +++ b/src/unison/physfs-1.1.1/zlib123/deflate.c @@ -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)<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 index 000000000..05a5ab3a2 --- /dev/null +++ b/src/unison/physfs-1.1.1/zlib123/deflate.h @@ -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 index 000000000..7e90f4928 --- /dev/null +++ b/src/unison/physfs-1.1.1/zlib123/gzio.c @@ -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 + +#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); /* 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 + +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 index 000000000..455dbc9ee --- /dev/null +++ b/src/unison/physfs-1.1.1/zlib123/infback.c @@ -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 index 000000000..bbee92ed1 --- /dev/null +++ b/src/unison/physfs-1.1.1/zlib123/inffast.c @@ -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 index 000000000..1e88d2d97 --- /dev/null +++ b/src/unison/physfs-1.1.1/zlib123/inffast.h @@ -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 index 000000000..75ed4b597 --- /dev/null +++ b/src/unison/physfs-1.1.1/zlib123/inffixed.h @@ -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 index 000000000..792fdee8e --- /dev/null +++ b/src/unison/physfs-1.1.1/zlib123/inflate.c @@ -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 + +/* + 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 index 000000000..07bd3e78a --- /dev/null +++ b/src/unison/physfs-1.1.1/zlib123/inflate.h @@ -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 index 000000000..8a9c13ff0 --- /dev/null +++ b/src/unison/physfs-1.1.1/zlib123/inftrees.c @@ -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 index 000000000..b1104c87e --- /dev/null +++ b/src/unison/physfs-1.1.1/zlib123/inftrees.h @@ -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 index 000000000..395e4e168 --- /dev/null +++ b/src/unison/physfs-1.1.1/zlib123/trees.c @@ -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 +#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< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 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 +# 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<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 index 000000000..72facf900 --- /dev/null +++ b/src/unison/physfs-1.1.1/zlib123/trees.h @@ -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 index 000000000..b59e3d0de --- /dev/null +++ b/src/unison/physfs-1.1.1/zlib123/uncompr.c @@ -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 index 000000000..03a9431c8 --- /dev/null +++ b/src/unison/physfs-1.1.1/zlib123/zconf.h @@ -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 + /* 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 /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* 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 index 000000000..022817927 --- /dev/null +++ b/src/unison/physfs-1.1.1/zlib123/zlib.h @@ -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 index 000000000..d55f5948a --- /dev/null +++ b/src/unison/physfs-1.1.1/zlib123/zutil.c @@ -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 index 000000000..b7d5eff81 --- /dev/null +++ b/src/unison/physfs-1.1.1/zlib123/zutil.h @@ -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 +# endif +# include +# include +#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 +# 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 +# endif +# else /* MSC or DJGPP */ +# include +# 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 +# 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 /* 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 + 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 index 000000000..56151b8b5 --- /dev/null +++ b/src/unison/src/vfs/FileSystem.cpp @@ -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 + +#include + +#include + +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 FileSystem::get_search_path() + { + std::vector 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 FileSystem::ls(const std::string &path) + { + std::vector 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 index 000000000..0e911efdd --- /dev/null +++ b/src/unison/src/vfs/sdl/Utils.cpp @@ -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 + +#include +#include + +#include +#include "SDL.h" + +namespace +{ + int rwops_seek(SDL_RWops *context, int offset, int whence) + { + PHYSFS_File *file = reinterpret_cast(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(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(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 index 000000000..d4ae430e5 --- /dev/null +++ b/src/unison/src/vfs/stream.cpp @@ -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 + +#include +#include +#include + +// 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(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 index 000000000..3c4b8acb5 --- /dev/null +++ b/src/unison/src/video/Blittable.cpp @@ -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 +#include + +namespace Unison +{ + namespace Video + { + Blittable::~Blittable() + { + } + + void Blittable::blit_section(const SurfaceSection §ion, const Point &dst_pos, const RenderOptions &options) + { + blit(section.image, dst_pos, section.clip_rect, options); + } + + void Blittable::blit_section(const TextureSection §ion, 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 index 000000000..624bd3ecf --- /dev/null +++ b/src/unison/src/video/Blitters.cpp @@ -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 +#include + +#include + +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 index 000000000..c29582b7b --- /dev/null +++ b/src/unison/src/video/Color.cpp @@ -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 + +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 index 000000000..a716282e5 --- /dev/null +++ b/src/unison/src/video/Renderers.cpp @@ -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 +#include +#include +#include "auto/Renderer.hpp" +#include "sdl/Renderer.hpp" +#include "opengl/Renderer.hpp" + +#include + +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 surfaces = Texture::save_textures(); + renderer->quit(); + if(name == "auto") + { + renderer = auto_renderer; + } + else + { + std::vector::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 index 000000000..9ebfbdb78 --- /dev/null +++ b/src/unison/src/video/Surface.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include + +#include + +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 index 000000000..ac2697621 --- /dev/null +++ b/src/unison/src/video/Texture.cpp @@ -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 +#include + +#include + +namespace Unison +{ + namespace Video + { + std::set Texture::textures = std::set(); + + 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 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 &surfaces) + { + Backend::Texture::load_textures(surfaces); + std::for_each(textures.begin(), textures.end(), ref); + } + + void Texture::recover_texture_ids() + { + std::map change_map = Backend::Texture::recover_texture_ids(); + if(!change_map.empty()) + { + for(std::set::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 index 000000000..ca608835a --- /dev/null +++ b/src/unison/src/video/Window.cpp @@ -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 +#include +#include +#include +#include +#include + +#include + +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 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 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 index 000000000..c813fcd31 --- /dev/null +++ b/src/unison/src/video/auto/Renderer.cpp @@ -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 +#include + +#include + +namespace Unison +{ + namespace Video + { + namespace Auto + { + Renderer::Renderer(const std::vector &renderers) : + renderer(0), + renderers(renderers) + { + } + + Renderer::~Renderer() + { + } + + void Renderer::init() + { + assert(!renderer); + std::vector::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 index 000000000..3b429d421 --- /dev/null +++ b/src/unison/src/video/auto/Renderer.hpp @@ -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 + +#include +#include + +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 &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 &renderers; + }; + } + } +} + +#endif diff --git a/src/unison/src/video/backend/Texture.cpp b/src/unison/src/video/backend/Texture.cpp new file mode 100644 index 000000000..6b41b62e7 --- /dev/null +++ b/src/unison/src/video/backend/Texture.cpp @@ -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 +#include +#include + +#include +#include + +namespace Unison +{ + namespace Video + { + namespace Backend + { + std::vector Texture::textures = std::vector(); + std::map Texture::named_textures = std::map(); + + 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 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 textures; + }; + } + + std::vector Texture::save_textures() + { + std::vector surfaces = std::for_each(textures.begin(), textures.end(), TextureSaver()).surfaces; + textures.clear(); + return surfaces; + } + + void Texture::load_textures(const std::vector &surfaces) + { + assert(textures.empty()); + textures = std::for_each(surfaces.begin(), surfaces.end(), TextureLoader()).textures; + } + + std::map Texture::recover_texture_ids() + { + std::map change_map; + std::vector new_textures; + bool null_texture_found = false; + for(std::vector::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::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 pair, TextureID id) + { + return pair.second == id; + } + } + + std::string Texture::get_name(TextureID id) + { + if(id == INVALID_TEXTURE_ID) + { + return std::string(); + } + std::map::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 index 000000000..fd87b6b6c --- /dev/null +++ b/src/unison/src/video/opengl/Renderer.cpp @@ -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 +#include +#include +#include +#include + +#include + +#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 index 000000000..c5682f5e5 --- /dev/null +++ b/src/unison/src/video/opengl/Renderer.hpp @@ -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 + +#include + +#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 index 000000000..e1473387e --- /dev/null +++ b/src/unison/src/video/opengl/SDL_gl.c @@ -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 index 000000000..eac9f65d6 --- /dev/null +++ b/src/unison/src/video/opengl/SDL_gl.h @@ -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 index 000000000..2d721505c --- /dev/null +++ b/src/unison/src/video/opengl/SDL_glfuncs.h @@ -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 index 000000000..8d27796aa --- /dev/null +++ b/src/unison/src/video/opengl/Texture.cpp @@ -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 +#include +#include +#include + +#include +#include + +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::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::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::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(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::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 index 000000000..25f20904f --- /dev/null +++ b/src/unison/src/video/opengl/Texture.hpp @@ -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 +#include + +#include +#include + +#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 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 index 000000000..924edb73d --- /dev/null +++ b/src/unison/src/video/opengl/Window.cpp @@ -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 +#include +#include +#include +#include +#include +#include + +#include + +#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(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 index 000000000..cdd37a660 --- /dev/null +++ b/src/unison/src/video/opengl/Window.hpp @@ -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 +#include + +#include + +#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 index 000000000..554fd6c62 --- /dev/null +++ b/src/unison/src/video/sdl/Blitters.cpp @@ -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 +#include + +#include + +#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 index 000000000..cbf94ab57 --- /dev/null +++ b/src/unison/src/video/sdl/Renderer.cpp @@ -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 +#include +#include +#include +#include + +#include + +#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 index 000000000..a7ed887e6 --- /dev/null +++ b/src/unison/src/video/sdl/Renderer.hpp @@ -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 + +#include +#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 index 000000000..3e61de2ee --- /dev/null +++ b/src/unison/src/video/sdl/Texture.cpp @@ -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 +#include +#include +#include +#include + +#include + +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(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 &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 index 000000000..fabf01e79 --- /dev/null +++ b/src/unison/src/video/sdl/Texture.hpp @@ -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 +#include + +#include +#include + +#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 cache; + std::map n_cache; + std::map h_cache; + std::map v_cache; + std::map 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 index 000000000..9ed0d0f78 --- /dev/null +++ b/src/unison/src/video/sdl/Window.cpp @@ -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 +#include +#include +#include +#include +#include +#include + +#include +#include + +#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(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 index 000000000..ff07a3508 --- /dev/null +++ b/src/unison/src/video/sdl/Window.hpp @@ -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 +#include +#include + +#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 diff --git a/src/video/color.hpp b/src/video/color.hpp index f0bd76d6b..0fa97b163 100644 --- a/src/video/color.hpp +++ b/src/video/color.hpp @@ -1,8 +1,7 @@ // $Id$ // // SuperTux -// Copyright (C) 2006 Matthias Braun -// +// Copyright (C) 2006 Matthias Braun // // 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 #include "log.hpp" +#include + 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; diff --git a/src/video/drawing_context.cpp b/src/video/drawing_context.cpp index 7ca3e2634..8255de134 100644 --- a/src/video/drawing_context.cpp +++ b/src/video/drawing_context.cpp @@ -22,55 +22,68 @@ #include #include #include -#include +//#include #include #include #include #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 + +/*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); - 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 > 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; } } diff --git a/src/video/drawing_context.hpp b/src/video/drawing_context.hpp index c8f90127e..28b15fc72 100644 --- a/src/video/drawing_context.hpp +++ b/src/video/drawing_context.hpp @@ -23,23 +23,27 @@ #include #include -#include +//#include -#include - -#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 +#include +#include + +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 > get_light_requests; + + std::map normal_list; + std::map lightmap_list; + std::map *draw_target; + + //Renderer *renderer; + //Lightmap *lightmap; /// the transform stack std::vector transformstack; @@ -146,21 +157,21 @@ private: std::vector blend_stack; Blend blend_mode; - typedef std::vector DrawingRequests; + /*typedef std::vector 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_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 */ }; diff --git a/src/video/drawing_request.hpp b/src/video/drawing_request.hpp index 24e0c0204..b63f85111 100644 --- a/src/video/drawing_request.hpp +++ b/src/video/drawing_request.hpp @@ -23,14 +23,17 @@ #include #include -#include +#include -#include +//#include + +//#include #include "glutil.hpp" -#include "math/vector.hpp" -#include "color.hpp" -#include "font.hpp" +//#include "math/vector.hpp" +//#include "color.hpp" +//#include "font.hpp" +#include 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 diff --git a/src/video/font.cpp b/src/video/font.cpp index e5b6bb12a..cc23a733f 100644 --- a/src/video/font.cpp +++ b/src/video/font.cpp @@ -31,7 +31,8 @@ #include "lisp/lisp.hpp" #include "screen.hpp" #include "font.hpp" -#include "renderer.hpp" +//#include "renderer.hpp" +#include #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(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;*/ } } } diff --git a/src/video/font.hpp b/src/video/font.hpp index 5625be185..ea542c949 100644 --- a/src/video/font.hpp +++ b/src/video/font.hpp @@ -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 index 014fb736c..000000000 --- a/src/video/gl_lightmap.cpp +++ /dev/null @@ -1,311 +0,0 @@ -// $Id: gl_lightmap.cpp 5063 2007-05-27 11:32:00Z matzeb $ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// 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 - -#ifdef HAVE_OPENGL - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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(lightmap_width) / static_cast(width); - lightmap_uv_bottom = static_cast(lightmap_height) / static_cast(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(surface->get_texture()); - GL::SurfaceData *surface_data = reinterpret_cast(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(surface->get_texture()); - GL::SurfaceData *surface_data = reinterpret_cast(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 index cb707099e..000000000 --- a/src/video/gl_lightmap.hpp +++ /dev/null @@ -1,63 +0,0 @@ -// $Id: gl_lightmap.hpp 4986 2007-04-16 17:48:28Z matzeb $ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// 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 - -#ifdef HAVE_OPENGL - -#ifndef SUPERTUX_GL_LIGHTMAP_H -#define SUPERTUX_GL_LIGHTMAP_H - -#include - -#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 index 3eee8f118..000000000 --- a/src/video/gl_renderer.cpp +++ /dev/null @@ -1,339 +0,0 @@ -// $Id: gl_renderer.cpp 5063 2007-05-27 11:32:00Z matzeb $ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// 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 - -#ifdef HAVE_OPENGL - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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(surface->get_texture()); - GL::SurfaceData *surface_data = reinterpret_cast(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(surface->get_texture()); - GL::SurfaceData *surface_data = reinterpret_cast(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 index 1eef6b489..000000000 --- a/src/video/gl_renderer.hpp +++ /dev/null @@ -1,48 +0,0 @@ -// $Id: gl_renderer.hpp 4986 2007-04-16 17:48:28Z matzeb $ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// 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 - -#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 index a441f1095..000000000 --- a/src/video/gl_surface_data.hpp +++ /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 -// -// 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 - -#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 index 413d0ce24..000000000 --- a/src/video/gl_texture.cpp +++ /dev/null @@ -1,154 +0,0 @@ -// $Id: gl_texture.cpp 4063 2006-07-21 21:05:23Z anmaster $ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// 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 - -#ifdef HAVE_OPENGL - -#include "gl_texture.hpp" -#include "gameconfig.hpp" -#include "glutil.hpp" -#include "log.hpp" - -#include -#include - -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 index 14532ccbe..000000000 --- a/src/video/gl_texture.hpp +++ /dev/null @@ -1,97 +0,0 @@ -// $Id: gl_texture.hpp 4063 2006-07-21 21:05:23Z anmaster $ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// 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 - -#ifdef HAVE_OPENGL - -#ifndef __GL_TEXTURE_HPP__ -#define __GL_TEXTURE_HPP__ - -#include - -#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 diff --git a/src/video/glutil.hpp b/src/video/glutil.hpp index 85200bdd6..2c66dd654 100644 --- a/src/video/glutil.hpp +++ b/src/video/glutil.hpp @@ -19,8 +19,19 @@ #ifndef __GLUTIL_HPP__ #define __GLUTIL_HPP__ -#include +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 + +#if 0 #ifdef HAVE_OPENGL #include @@ -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 index 049b21ece..000000000 --- a/src/video/lightmap.hpp +++ /dev/null @@ -1,58 +0,0 @@ -// $Id: lightmap.hpp 4986 2007-04-16 17:48:28Z matzeb $ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// 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 -#include -#include - -#include - -#include - -#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 index 2bd96d70b..000000000 --- a/src/video/renderer.hpp +++ /dev/null @@ -1,56 +0,0 @@ -// $Id: drawing_context.hpp 4986 2007-04-16 17:48:28Z matzeb $ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// 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 -#include -#include - -#include - -#include - -#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 index 8e7c70fac..000000000 --- a/src/video/sdl_lightmap.cpp +++ /dev/null @@ -1,614 +0,0 @@ -// $Id: sdl_lightmap.cpp 5063 2007-05-27 11:32:00Z matzeb $ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// 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 - -#include -#include -#include -#include -#include -#include -#include -#include - -#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(surface->get_texture()); - SDL::SurfaceData *surface_data = reinterpret_cast(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(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 index fbde750fb..000000000 --- a/src/video/sdl_lightmap.hpp +++ /dev/null @@ -1,61 +0,0 @@ -// $Id: sdl_lightmap.hpp 4986 2007-04-16 17:48:28Z matzeb $ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// 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 - -#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 index dede6c832..000000000 --- a/src/video/sdl_renderer.cpp +++ /dev/null @@ -1,433 +0,0 @@ -// $Id: sdl_renderer.cpp 5063 2007-05-27 11:32:00Z matzeb $ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// 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 - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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(surface->get_texture()); - SDL::SurfaceData *surface_data = reinterpret_cast(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(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(fillrectrequest->color.red * 255); - Uint8 g = static_cast(fillrectrequest->color.green * 255); - Uint8 b = static_cast(fillrectrequest->color.blue * 255); - Uint8 a = static_cast(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 index 24dcb84ff..000000000 --- a/src/video/sdl_renderer.hpp +++ /dev/null @@ -1,48 +0,0 @@ -// $Id: sdl_renderer.hpp 4986 2007-04-16 17:48:28Z matzeb $ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// 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 - -#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 index 1e46e683a..000000000 --- a/src/video/sdl_surface_data.hpp +++ /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 -// -// 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 - -#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 index 21645507e..000000000 --- a/src/video/sdl_texture.cpp +++ /dev/null @@ -1,658 +0,0 @@ -// $Id: sdl_texture.cpp 4063 2006-07-21 21:05:23Z anmaster $ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// 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 - -#include "sdl_texture.hpp" -#include "color.hpp" -#include "gameconfig.hpp" -#include "main.hpp" - -#include - -#include - -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 index 34479dbca..000000000 --- a/src/video/sdl_texture.hpp +++ /dev/null @@ -1,140 +0,0 @@ -// $Id: sdl_texture.hpp 4063 2006-07-21 21:05:23Z anmaster $ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// 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 - -#include - -#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 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 diff --git a/src/video/surface.hpp b/src/video/surface.hpp index d90494bfd..a9358fbba 100644 --- a/src/video/surface.hpp +++ b/src/video/surface.hpp @@ -25,8 +25,19 @@ #include #include #include "math/vector.hpp" -#include "texture.hpp" -#include "video_systems.hpp" +#include "file_system.hpp" +#include + +/// 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. @@ -36,49 +47,30 @@ 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 index 6e4c462fe..000000000 --- a/src/video/texture.hpp +++ /dev/null @@ -1,91 +0,0 @@ -// $Id$ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// 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 - -#include -#include - -#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 index d9ff2a74b..000000000 --- a/src/video/texture_manager.cpp +++ /dev/null @@ -1,214 +0,0 @@ -// $Id$ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// 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 - -#include "texture_manager.hpp" - -#include -#include -#include -#include -#include -#include -#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(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::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 index 1431c68ea..000000000 --- a/src/video/texture_manager.hpp +++ /dev/null @@ -1,84 +0,0 @@ -// $Id$ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// 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 - -#include "glutil.hpp" -#include -#include -#include -#include - -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 ImageTextures; - ImageTextures image_textures; - - Texture* create_image_texture(const std::string& filename); - -#ifdef HAVE_OPENGL - typedef std::set 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 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 index 1fd3627c2..000000000 --- a/src/video/video_systems.cpp +++ /dev/null @@ -1,180 +0,0 @@ -// $Id: video_systems.cpp 5063 2007-05-27 11:32:00Z matzeb $ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// 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 - -#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(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 index 1347f5485..000000000 --- a/src/video/video_systems.hpp +++ /dev/null @@ -1,48 +0,0 @@ -// $Id: video_systems.hpp 5138 2007-08-15 01:02:22Z tuxdev $ -// -// SuperTux -// Copyright (C) 2006 Matthias Braun -// -// 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 - -#include -#include - -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 diff --git a/src/world.cpp b/src/world.cpp index 8fd459934..d8beb4a5c 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -20,7 +20,8 @@ #include #include -#include +//#include +#include #include #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 << "': " < files = Unison::VFS::FileSystem::get().ls(path); + for(std::vector::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 diff --git a/src/worldmap/level.cpp b/src/worldmap/level.cpp index 2b61124c6..c3ec7e544 100644 --- a/src/worldmap/level.cpp +++ b/src/worldmap/level.cpp @@ -20,13 +20,14 @@ #include #include -#include +//#include #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 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); diff --git a/src/worldmap/worldmap.cpp b/src/worldmap/worldmap.cpp index 2f5d3aa50..473811e81 100644 --- a/src/worldmap/worldmap.cpp +++ b/src/worldmap/worldmap.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +//#include #include "worldmap.hpp" -- 2.11.0